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 }