gitee.com/zhongguo168a/gocodes@v0.0.0-20230609140523-e1828349603f/datax/jsonmap/jsonmap-to-struct.go (about)

     1  package jsonmap
     2  
     3  import (
     4  	"errors"
     5  	"gitee.com/zhongguo168a/gocodes/datax/schemax/fieldkind"
     6  	"reflect"
     7  	"strconv"
     8  )
     9  
    10  var (
    11  	refNil = reflect.ValueOf(nil)
    12  )
    13  
    14  func MapToStruct(from map[string]interface{}, to interface{}) (err error) {
    15  	if from == nil {
    16  		return
    17  	}
    18  	if to == nil {
    19  		return
    20  	}
    21  	err = structFromMapObj(reflect.ValueOf(to), nil, from)
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	return
    27  }
    28  
    29  func structFromMapObj(sourceRef reflect.Value, sourceTyp reflect.Type, itargetMap interface{}) (err error) {
    30  	var isTargetNil bool
    31  	targetMap, ok := itargetMap.(map[string]interface{})
    32  	if ok {
    33  		if targetMap == nil {
    34  			isTargetNil = true
    35  		}
    36  	} else {
    37  		isTargetNil = true
    38  	}
    39  
    40  	if sourceRef.Kind() == reflect.Ptr {
    41  		if isTargetNil {
    42  			sourceRef.Set(refNil)
    43  			return
    44  		}
    45  		if sourceTyp != nil {
    46  			sourceTyp = sourceTyp.Elem()
    47  		}
    48  		if sourceRef.IsNil() {
    49  			if sourceTyp == nil {
    50  				return // 无法创建新的对象,返回
    51  			}
    52  			sourceRef.Set(reflect.New(sourceTyp))
    53  		}
    54  		sourceRef = sourceRef.Elem()
    55  
    56  	} else {
    57  		if isTargetNil {
    58  			return
    59  		}
    60  	}
    61  
    62  	if sourceTyp == nil {
    63  		sourceTyp = sourceRef.Type()
    64  	}
    65  	for i := 0; i < sourceTyp.NumField(); i++ {
    66  		field := sourceTyp.Field(i)
    67  		jsonzTagStr := field.Tag.Get("jsonz")
    68  		if jsonzTagStr == "_" {
    69  			continue
    70  		}
    71  		//tags := parseTag(jsonzTagStr)
    72  		fname := field.Name
    73  		lastName := func() (x string) {
    74  			jsontag := field.Tag.Get("alias")
    75  			x = jsontag
    76  			if x == "" {
    77  				x = fname
    78  			}
    79  			return
    80  		}()
    81  		valRef := sourceRef.Field(i)
    82  		ftyp := field.Type
    83  		catalog := fieldkind.ReflectToFieldKind(ftyp)
    84  
    85  		tval, thas := targetMap[lastName]
    86  		if catalog == fieldkind.Class && field.Anonymous {
    87  
    88  		} else {
    89  			if !thas { // 如果目标map不存在字段,则不作任何动作
    90  				continue
    91  			}
    92  		}
    93  
    94  		switch catalog {
    95  		case fieldkind.Class:
    96  			if field.Anonymous {
    97  				err = structFromMapObj(valRef, ftyp, targetMap)
    98  				if err != nil {
    99  					err = errors.New(err.Error() + " at class field=" + field.Name)
   100  					return
   101  				}
   102  			} else {
   103  				err = structFromMapObj(valRef, ftyp, tval)
   104  				if err != nil {
   105  					err = errors.New(err.Error() + " at class field=" + field.Name)
   106  					return
   107  				}
   108  			}
   109  		case fieldkind.Array:
   110  			err = structFromMapArray(valRef, ftyp, tval)
   111  			if err != nil {
   112  				err = errors.New(err.Error() + " at class field=" + field.Name)
   113  				return
   114  			}
   115  		case fieldkind.Map:
   116  			err = structFromMapMap(valRef, tval, ftyp)
   117  			if err != nil {
   118  				err = errors.New(err.Error() + " at class field=" + field.Name)
   119  				return
   120  			}
   121  		case fieldkind.Enum:
   122  			err = structFromMapEnum(ftyp, valRef, tval)
   123  			if err != nil {
   124  				err = errors.New(err.Error() + " at class field=" + field.Name)
   125  				return
   126  			}
   127  		case fieldkind.Basic:
   128  			err = structFromMapBasic(ftyp, valRef, ConvertJsonKeyToReflectKind(ftyp.Kind(), tval))
   129  			if err != nil {
   130  				err = errors.New(err.Error() + " at class field=" + field.Name)
   131  				return
   132  			}
   133  		case fieldkind.Any:
   134  			r, anyerr := structFromMapAny(ftyp, valRef, tval)
   135  			if anyerr != nil {
   136  				err = errors.New(anyerr.Error() + " at class field=" + field.Name)
   137  				return
   138  			}
   139  			valRef.Set(r)
   140  		default:
   141  			err = errors.New("not support: " + ftyp.String())
   142  			return
   143  
   144  		}
   145  	}
   146  	return
   147  }
   148  
   149  func structFromMapAny(ftyp reflect.Type, val reflect.Value, target interface{}) (r reflect.Value, err error) {
   150  	switch tval := target.(type) {
   151  	case map[string]interface{}:
   152  		r = reflect.ValueOf(target)
   153  	default:
   154  		target = InterfaceToJSONValue(tval)
   155  		r = reflect.ValueOf(target)
   156  	}
   157  	return
   158  }
   159  
   160  func structFromMapEnum(ftyp reflect.Type, val reflect.Value, target interface{}) (err error) {
   161  	tarref := reflect.ValueOf(target)
   162  	if tarref.Type().String() != ftyp.String() {
   163  		if !tarref.Type().ConvertibleTo(ftyp) {
   164  			err = errors.New("cannot convert to " + ftyp.String())
   165  			return
   166  		}
   167  
   168  		tarref = tarref.Convert(ftyp)
   169  	}
   170  	val.Set(tarref)
   171  	return
   172  }
   173  
   174  func structFromMapBasic(basic reflect.Type, val reflect.Value, target interface{}) (err error) {
   175  	if !reflect.ValueOf(target).Type().ConvertibleTo(basic) {
   176  		err = errors.New("cannot convert to " + basic.String())
   177  		return
   178  	}
   179  	val.Set(reflect.ValueOf(target).Convert(basic))
   180  	return
   181  }
   182  
   183  func structFromMapArray(sourceArr reflect.Value, ftyp reflect.Type, itarget interface{}) (err error) {
   184  	var isTargetNil bool
   185  	targetArr, ok := itarget.([]interface{})
   186  	if ok {
   187  		if targetArr == nil {
   188  			isTargetNil = true
   189  		}
   190  	} else {
   191  		isTargetNil = true
   192  	}
   193  	if isTargetNil {
   194  		// todo: 将数组设置成nil?
   195  		//sourceArr.Set(refNil)
   196  		return
   197  	}
   198  
   199  	elemTyp := ftyp.Elem()
   200  
   201  	sourceArr.Set(reflect.MakeSlice(ftyp, len(targetArr), cap(targetArr)))
   202  	catalog := fieldkind.ReflectToFieldKind(elemTyp)
   203  	switch catalog {
   204  	case fieldkind.Class:
   205  		for i := 0; i < sourceArr.Len(); i++ {
   206  			classerr := structFromMapObj(sourceArr.Index(i), elemTyp, targetArr[i])
   207  			if classerr != nil {
   208  				err = errors.New("at index=" + strconv.Itoa(i) + ": " + classerr.Error())
   209  				return
   210  			}
   211  		}
   212  	case fieldkind.Basic:
   213  		for i := 0; i < sourceArr.Len(); i++ {
   214  			err = structFromMapBasic(elemTyp, sourceArr.Index(i), targetArr[i])
   215  			if err != nil {
   216  				err = errors.New("at index=" + strconv.Itoa(i) + ": " + err.Error())
   217  				return
   218  			}
   219  
   220  		}
   221  	case fieldkind.Any:
   222  		for i := 0; i < sourceArr.Len(); i++ {
   223  			elemVal := sourceArr.Index(i)
   224  			r, anyerr := structFromMapAny(ftyp, elemVal, targetArr[i])
   225  			if anyerr != nil {
   226  				err = errors.New("at index=" + strconv.Itoa(i) + ": " + err.Error())
   227  				return
   228  			}
   229  			elemVal.Set(r)
   230  		}
   231  	default:
   232  		err = errors.New("not support: " + elemTyp.String())
   233  		return
   234  	}
   235  	return
   236  }
   237  
   238  func structFromMapMap(sourceRef reflect.Value, itarget interface{}, ftyp reflect.Type) (err error) {
   239  	var isTargetNil bool
   240  	targetMap, ok := itarget.(map[string]interface{})
   241  	if ok {
   242  		if targetMap == nil {
   243  			isTargetNil = true
   244  		}
   245  	} else {
   246  		isTargetNil = true
   247  	}
   248  	if isTargetNil {
   249  		if !sourceRef.IsNil() {
   250  			sourceRef.Set(refNil)
   251  		}
   252  		return
   253  	}
   254  	// 如果 map存在,对象不存在,初始化对象
   255  	if sourceRef.IsNil() {
   256  		sourceRef.Set(reflect.MakeMap(ftyp))
   257  	}
   258  
   259  	keytyp := ftyp.Key()
   260  	vtyp := ftyp.Elem()
   261  	for tkey, tval := range targetMap {
   262  		ckey := reflect.ValueOf(ConvertJsonKeyToReflectKind(ftyp.Key().Kind(), tkey))
   263  		ckey = ckey.Convert(keytyp)
   264  		valRef := sourceRef.MapIndex(ckey)
   265  		catalog := fieldkind.ReflectToFieldKind(vtyp)
   266  		switch catalog {
   267  		case fieldkind.Class:
   268  			err = structFromMapObj(valRef, vtyp, tval)
   269  			if err != nil {
   270  				err = errors.New(err.Error() + "at map key=" + ckey.String())
   271  				return
   272  			}
   273  		case fieldkind.Enum:
   274  			err = structFromMapEnum(vtyp, valRef, tval)
   275  			if err != nil {
   276  				err = errors.New(err.Error() + "at map key=" + ckey.String())
   277  				return
   278  			}
   279  		case fieldkind.Basic:
   280  			sourceRef.SetMapIndex(ckey, reflect.ValueOf(tval).Convert(vtyp))
   281  		case fieldkind.Any:
   282  			r, anyerr := structFromMapAny(ftyp, valRef, tval)
   283  			if anyerr != nil {
   284  				err = errors.New(anyerr.Error() + " at map key=" + ckey.String())
   285  				return
   286  			}
   287  			sourceRef.SetMapIndex(ckey, r)
   288  
   289  		default:
   290  			err = errors.New("not support: " + vtyp.String())
   291  			return
   292  		}
   293  	}
   294  
   295  	return
   296  }