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

     1  package jsonmap
     2  
     3  import (
     4  	"errors"
     5  	"gitee.com/zhongguo168a/gocodes/datax/schemax/basickind"
     6  	"gitee.com/zhongguo168a/gocodes/datax/schemax/fieldkind"
     7  	"reflect"
     8  	"strconv"
     9  )
    10  
    11  func StructToMap(from interface{}, to map[string]interface{}) (err error) {
    12  	if to == nil {
    13  		return errors.New("to is nil")
    14  	}
    15  	if from == nil {
    16  		return
    17  	}
    18  	_, err = structToMapObj(reflect.ValueOf(from), nil, to)
    19  	if err != nil {
    20  		return err
    21  	}
    22  
    23  	return
    24  }
    25  
    26  func structToMapObj(sourceRef reflect.Value, sourceTyp reflect.Type, itargetMap interface{}) (r interface{}, err error) {
    27  	if sourceRef.Kind() == reflect.Ptr {
    28  		if sourceRef.IsNil() {
    29  			return
    30  		}
    31  		sourceRef = sourceRef.Elem()
    32  		if sourceTyp != nil {
    33  			sourceTyp = sourceTyp.Elem()
    34  		}
    35  	}
    36  
    37  	targetMap, ok := itargetMap.(map[string]interface{})
    38  	if ok {
    39  		if targetMap == nil {
    40  			targetMap = map[string]interface{}{}
    41  		}
    42  	} else {
    43  		targetMap = map[string]interface{}{}
    44  	}
    45  	r = targetMap
    46  
    47  	rmap := targetMap
    48  	if sourceTyp == nil {
    49  		sourceTyp = sourceRef.Type()
    50  	}
    51  	for i := 0; i < sourceTyp.NumField(); i++ {
    52  		field := sourceTyp.Field(i)
    53  		jsonzTagStr := field.Tag.Get("jsonz")
    54  		if jsonzTagStr == "_" {
    55  			continue
    56  		}
    57  		//tags := parseTag(jsonzTagStr)
    58  		fname := field.Name
    59  		lastName := func() (x string) {
    60  			jsontag := field.Tag.Get("alias")
    61  			x = jsontag
    62  			if x == "" {
    63  				x = fname
    64  			}
    65  			return
    66  		}()
    67  
    68  		valRef := sourceRef.Field(i)
    69  		ftyp := field.Type
    70  		catalog := fieldkind.ReflectToFieldKind(ftyp)
    71  		switch catalog {
    72  		case fieldkind.Class:
    73  			if field.Anonymous {
    74  				r, err = structToMapObj(valRef, ftyp, rmap)
    75  				if err != nil {
    76  					err = errors.New(err.Error() + "at class field=" + field.Name)
    77  					return
    78  				}
    79  			} else {
    80  				rmap[lastName], err = structToMapObj(valRef, ftyp, rmap[fname])
    81  				if err != nil {
    82  					err = errors.New(err.Error() + "at class field=" + field.Name)
    83  					return
    84  				}
    85  			}
    86  		case fieldkind.Array:
    87  			rmap[lastName], err = structToMapArray(valRef, ftyp)
    88  			if err != nil {
    89  				err = errors.New(err.Error() + "at class field=" + field.Name)
    90  				return
    91  			}
    92  		case fieldkind.Map:
    93  			rmap[lastName], err = structToMapMap(valRef, nil, ftyp)
    94  			if err != nil {
    95  				err = errors.New(err.Error() + "at class field=" + field.Name)
    96  				return
    97  			}
    98  		case fieldkind.Enum:
    99  			rmap[lastName], err = structToMapEnum(ftyp, valRef)
   100  			if err != nil {
   101  				err = errors.New(err.Error() + "at class field=" + field.Name)
   102  				return
   103  			}
   104  		case fieldkind.Basic:
   105  			rmap[lastName] = structToMapBasic(ftyp, valRef)
   106  		case fieldkind.Any:
   107  			rmap[lastName], err = structToMapAny(ftyp, valRef)
   108  			if err != nil {
   109  				err = errors.New(err.Error() + "at class field=" + field.Name)
   110  				return
   111  			}
   112  		default:
   113  			err = errors.New("not support: " + ftyp.String())
   114  			return
   115  
   116  		}
   117  	}
   118  	return
   119  }
   120  
   121  func structToMapAny(ftyp reflect.Type, val reflect.Value) (st interface{}, err error) {
   122  	if val.IsNil() {
   123  		return
   124  	}
   125  	catalog := fieldkind.ReflectToFieldKind(val.Elem().Type())
   126  	valref := val.Elem()
   127  	switch catalog {
   128  	case fieldkind.Class:
   129  		st, err = structToMapObj(valref, valref.Type(), nil)
   130  		if err != nil {
   131  			return
   132  		}
   133  	case fieldkind.Basic:
   134  		st = structToMapBasic(ftyp, valref)
   135  	case fieldkind.Map:
   136  		st, err = structToMapMap(valref, nil, valref.Type())
   137  		if err != nil {
   138  			return
   139  		}
   140  	}
   141  
   142  	return
   143  }
   144  
   145  func structToMapEnum(ftyp reflect.Type, val reflect.Value) (st interface{}, err error) {
   146  	typ, ok := basicTypes[ftyp.Kind()]
   147  	if ok == false {
   148  		err = errors.New("not suppoer enum type, " + ftyp.Key().String())
   149  		return
   150  	}
   151  
   152  	st = InterfaceToJSONValue(val.Convert(typ).Interface())
   153  	return
   154  }
   155  
   156  func structToMapBasic(basic reflect.Type, val reflect.Value) (r interface{}) {
   157  	kind := basickind.ReflectKindToBasicKind(basic.Kind())
   158  	if kind == basickind.Invalid { // any
   159  		return InterfaceToJSONValue(val.Interface())
   160  	}
   161  	return ConvertBasicToJsonValue(kind, val.Interface())
   162  }
   163  
   164  func structToMapArray(sourceArr reflect.Value, ftyp reflect.Type) (rarr []interface{}, err error) {
   165  	if sourceArr.Len() == 0 {
   166  		return
   167  	}
   168  
   169  	elemTyp := ftyp.Elem()
   170  
   171  	rarr = make([]interface{}, sourceArr.Len(), sourceArr.Cap())
   172  	catalog := fieldkind.ReflectToFieldKind(elemTyp)
   173  	switch catalog {
   174  	case fieldkind.Class:
   175  		for i := 0; i < sourceArr.Len(); i++ {
   176  			imap, classerr := structToMapObj(sourceArr.Index(i), elemTyp, nil)
   177  			if classerr != nil {
   178  				err = errors.New("at index=" + strconv.Itoa(i) + ": " + classerr.Error())
   179  				return
   180  			}
   181  			rarr[i] = imap
   182  		}
   183  	case fieldkind.Basic:
   184  		for i := 0; i < sourceArr.Len(); i++ {
   185  			rarr[i] = structToMapBasic(elemTyp, sourceArr.Index(i))
   186  		}
   187  	case fieldkind.Any:
   188  		for i := 0; i < sourceArr.Len(); i++ {
   189  			rarr[i], err = structToMapAny(elemTyp, sourceArr.Index(i))
   190  			if err != nil {
   191  				err = errors.New("at index=" + strconv.Itoa(i) + ": " + err.Error())
   192  				return
   193  			}
   194  		}
   195  	default:
   196  		err = errors.New("not support: " + elemTyp.String())
   197  		return
   198  	}
   199  	return
   200  }
   201  
   202  func structToMapMap(sourceRef reflect.Value, mmap map[string]interface{}, ftyp reflect.Type) (rval interface{}, err error) {
   203  	if sourceRef.IsNil() {
   204  		return nil, nil
   205  	}
   206  	mmap = map[string]interface{}{}
   207  	rval = mmap
   208  
   209  	keytyp, ok := basicTypes[ftyp.Key().Kind()]
   210  	if ok == false {
   211  		err = errors.New("not suppoer map key, " + ftyp.Key().String())
   212  		return
   213  	}
   214  	vtyp := ftyp.Elem()
   215  	for _, ckey := range sourceRef.MapKeys() {
   216  		key := InterfaceToJSONKey(ckey.Convert(keytyp).Interface())
   217  		valRef := sourceRef.MapIndex(ckey)
   218  		//vtyp := valRef.Type()
   219  		catalog := fieldkind.ReflectToFieldKind(vtyp)
   220  		switch catalog {
   221  		case fieldkind.Class:
   222  			mmap[key], err = structToMapObj(valRef, vtyp, ckey.String())
   223  			if err != nil {
   224  				err = errors.New(err.Error() + "at map key=" + key)
   225  				return
   226  			}
   227  		case fieldkind.Enum:
   228  			mmap[key], err = structToMapEnum(vtyp, valRef)
   229  			if err != nil {
   230  				err = errors.New(err.Error() + "at map key=" + key)
   231  				return
   232  			}
   233  		case fieldkind.Basic:
   234  			mmap[key] = structToMapBasic(vtyp, valRef)
   235  		case fieldkind.Any:
   236  			mmap[key] = InterfaceToJSONValue(valRef.Interface())
   237  		default:
   238  			err = errors.New("not support: " + vtyp.String())
   239  			return
   240  		}
   241  	}
   242  
   243  	return
   244  }
   245  
   246  var basicTypes = map[reflect.Kind]reflect.Type{
   247  	reflect.Int:     reflect.TypeOf(0),
   248  	reflect.Int8:    reflect.TypeOf(int8(0)),
   249  	reflect.Int16:   reflect.TypeOf(int16(0)),
   250  	reflect.Int32:   reflect.TypeOf(int32(0)),
   251  	reflect.Int64:   reflect.TypeOf(int64(0)),
   252  	reflect.Uint:    reflect.TypeOf(uint(0)),
   253  	reflect.Uint8:   reflect.TypeOf(uint8(0)),
   254  	reflect.Uint16:  reflect.TypeOf(uint16(0)),
   255  	reflect.Uint32:  reflect.TypeOf(uint32(0)),
   256  	reflect.Uint64:  reflect.TypeOf(uint64(0)),
   257  	reflect.Float32: reflect.TypeOf(float32(0)),
   258  	reflect.Float64: reflect.TypeOf(float64(0)),
   259  	reflect.String:  reflect.TypeOf(""),
   260  	reflect.Bool:    reflect.TypeOf(false),
   261  }