yunion.io/x/jsonutils@v1.0.0/marshal.go (about) 1 // Copyright 2019 Yunion 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package jsonutils 16 17 /** 18 jsonutils.Marshal 19 20 Convert any object to JSONObject 21 22 */ 23 24 import ( 25 "fmt" 26 "reflect" 27 "time" 28 29 "yunion.io/x/log" 30 "yunion.io/x/pkg/gotypes" 31 "yunion.io/x/pkg/tristate" 32 "yunion.io/x/pkg/util/reflectutils" 33 "yunion.io/x/pkg/util/timeutils" 34 ) 35 36 func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 37 if val.Kind() == reflect.Slice && val.IsNil() { 38 if !omitEmpty { 39 return JSONNull 40 } else { 41 return nil 42 } 43 } 44 if val.Len() == 0 && info != nil && info.OmitEmpty && omitEmpty { 45 return nil 46 } 47 objs := make([]JSONObject, 0) 48 for i := 0; i < val.Len(); i += 1 { 49 val := marshalValue(val.Index(i), nil, omitEmpty) 50 if val != nil { 51 objs = append(objs, val) 52 } 53 } 54 arr := NewArray(objs...) 55 if info != nil && info.ForceString { 56 return NewString(arr.String()) 57 } else { 58 return arr 59 } 60 } 61 62 func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 63 if val.IsNil() { 64 if !omitEmpty { 65 return JSONNull 66 } else { 67 return nil 68 } 69 } 70 keys := val.MapKeys() 71 if len(keys) == 0 && info != nil && info.OmitEmpty && omitEmpty { 72 return nil 73 } 74 objPairs := make([]JSONPair, 0) 75 for i := 0; i < len(keys); i += 1 { 76 key := keys[i] 77 val := marshalValue(val.MapIndex(key), nil, omitEmpty) 78 if val != nil { 79 objPairs = append(objPairs, JSONPair{key: fmt.Sprintf("%s", key), val: val}) 80 } 81 } 82 dict := NewDict(objPairs...) 83 if info != nil && info.ForceString { 84 return NewString(dict.String()) 85 } else { 86 return dict 87 } 88 } 89 90 func marshalStruct(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 91 objPairs := struct2JSONPairs(val, omitEmpty) 92 if len(objPairs) == 0 && info != nil && info.OmitEmpty && omitEmpty { 93 return nil 94 } 95 dict := NewDict(objPairs...) 96 if info != nil && info.ForceString { 97 return NewString(dict.String()) 98 } else { 99 return dict 100 } 101 } 102 103 func findValueByKey(pairs []JSONPair, key string) JSONObject { 104 for i := range pairs { 105 if pairs[i].key == key { 106 return pairs[i].val 107 } 108 } 109 return nil 110 } 111 112 func struct2JSONPairs(val reflect.Value, omitEmpty bool) []JSONPair { 113 fields := reflectutils.FetchStructFieldValueSet(val) 114 objPairs := make([]JSONPair, 0, len(fields)) 115 depFields := make(map[string]string) 116 for i := 0; i < len(fields); i += 1 { 117 jsonInfo := fields[i].Info 118 if jsonInfo.Ignore { 119 continue 120 } 121 key := jsonInfo.MarshalName() 122 if deprecatedBy, ok := fields[i].Info.Tags[TAG_DEPRECATED_BY]; ok { 123 depFields[key] = deprecatedBy 124 continue 125 } 126 val := marshalValue(fields[i].Value, jsonInfo, omitEmpty) 127 if val != nil { 128 objPair := JSONPair{key: key, val: val} 129 objPairs = append(objPairs, objPair) 130 } 131 } 132 depPairs := make([]JSONPair, 0, len(depFields)) 133 for depKey, key := range depFields { 134 findLoop := false 135 for { 136 if okey, ok := depFields[key]; ok { 137 if okey == depKey { 138 // loop detected 139 findLoop = true 140 break 141 } 142 key = okey 143 } else { 144 break 145 } 146 } 147 if findLoop { 148 continue 149 } 150 val := findValueByKey(objPairs, key) 151 if val != nil { 152 objPair := JSONPair{key: depKey, val: val} 153 depPairs = append(depPairs, objPair) 154 } 155 } 156 objPairs = append(objPairs, depPairs...) 157 return objPairs 158 } 159 160 func marshalInt64(val int64, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 161 if val == 0 && info != nil && info.OmitZero && omitEmpty { 162 return nil 163 } else if info != nil && info.ForceString { 164 return NewString(fmt.Sprintf("%d", val)) 165 } else { 166 return NewInt(val) 167 } 168 } 169 170 func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int, omitEmpty bool) JSONObject { 171 if val == 0.0 && info != nil && info.OmitZero && omitEmpty { 172 return nil 173 } else if info != nil && info.ForceString { 174 return NewString(fmt.Sprintf("%f", val)) 175 } else { 176 return NewFloat64(val) 177 } 178 } 179 180 func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int, omitEmpty bool) JSONObject { 181 if val == 0.0 && info != nil && info.OmitZero && omitEmpty { 182 return nil 183 } else if info != nil && info.ForceString { 184 return NewString(fmt.Sprintf("%f", val)) 185 } else { 186 return NewFloat32(val) 187 } 188 } 189 190 func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 191 if !val && info != nil && info.OmitFalse && omitEmpty { 192 return nil 193 } else if info != nil && info.ForceString { 194 return NewString(fmt.Sprintf("%v", val)) 195 } else { 196 if val { 197 return JSONTrue 198 } else { 199 return JSONFalse 200 } 201 } 202 } 203 204 func marshalTristate(val tristate.TriState, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 205 if val.IsTrue() { 206 return JSONTrue 207 } else if val.IsFalse() { 208 return JSONFalse 209 } else { 210 if omitEmpty { 211 return nil 212 } else { 213 return JSONNull 214 } 215 } 216 } 217 218 func marshalString(val string, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 219 if len(val) == 0 && info != nil && info.OmitEmpty && omitEmpty { 220 return nil 221 } else { 222 return NewString(val) 223 } 224 } 225 226 func marshalTime(val time.Time, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 227 if val.IsZero() { 228 if info != nil && info.OmitEmpty && omitEmpty { 229 return nil 230 } 231 return NewString("") 232 } else { 233 return NewString(timeutils.FullIsoTime(val)) 234 } 235 } 236 237 func Marshal(obj interface{}) JSONObject { 238 if obj == nil { 239 return JSONNull 240 } 241 val := reflect.ValueOf(obj) 242 if kind := val.Kind(); val.IsZero() && kind == reflect.Ptr { 243 return JSONNull 244 } 245 objValue := reflect.Indirect(val) 246 mval := marshalValue(objValue, nil, true) 247 if mval == nil { 248 return JSONNull 249 } 250 return mval 251 } 252 253 func marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject { 254 switch objValue.Type() { 255 case JSONDictPtrType, JSONArrayPtrType, JSONBoolPtrType, JSONIntPtrType, JSONFloatPtrType, JSONStringPtrType, JSONObjectType: 256 if objValue.IsNil() { 257 if omitEmpty { 258 return nil 259 } else { 260 return JSONNull 261 } 262 } 263 return objValue.Interface().(JSONObject) 264 case JSONDictType: 265 json, ok := objValue.Interface().(JSONDict) 266 if ok { 267 if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty { 268 return nil 269 } else { 270 return &json 271 } 272 } else { 273 return nil 274 } 275 case JSONArrayType: 276 json, ok := objValue.Interface().(JSONArray) 277 if ok { 278 if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty { 279 return nil 280 } else { 281 return &json 282 } 283 } else { 284 return nil 285 } 286 case JSONBoolType: 287 json, ok := objValue.Interface().(JSONBool) 288 if ok { 289 if !json.data && info != nil && info.OmitEmpty && omitEmpty { 290 return nil 291 } else { 292 return &json 293 } 294 } else { 295 return nil 296 } 297 case JSONIntType: 298 json, ok := objValue.Interface().(JSONInt) 299 if ok { 300 if json.data == 0 && info != nil && info.OmitEmpty && omitEmpty { 301 return nil 302 } else { 303 return &json 304 } 305 } else { 306 return nil 307 } 308 case JSONFloatType: 309 json, ok := objValue.Interface().(JSONFloat) 310 if ok { 311 if json.data == 0.0 && info != nil && info.OmitEmpty && omitEmpty { 312 return nil 313 } else { 314 return &json 315 } 316 } else { 317 return nil 318 } 319 case JSONStringType: 320 json, ok := objValue.Interface().(JSONString) 321 if ok { 322 if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty { 323 return nil 324 } else { 325 return &json 326 } 327 } else { 328 return nil 329 } 330 case tristate.TriStateType: 331 tri, ok := objValue.Interface().(tristate.TriState) 332 if ok { 333 return marshalTristate(tri, info, omitEmpty) 334 } else { 335 return nil 336 } 337 } 338 switch objValue.Kind() { 339 case reflect.Slice, reflect.Array: 340 return marshalSlice(objValue, info, omitEmpty) 341 case reflect.Struct: 342 if objValue.Type() == gotypes.TimeType { 343 return marshalTime(objValue.Interface().(time.Time), info, omitEmpty) 344 } else { 345 return marshalStruct(objValue, info, omitEmpty) 346 } 347 case reflect.Map: 348 return marshalMap(objValue, info, omitEmpty) 349 case reflect.String: 350 strValue := objValue.Convert(gotypes.StringType) 351 return marshalString(strValue.Interface().(string), info, omitEmpty) 352 case reflect.Bool: 353 return marshalBoolean(objValue.Interface().(bool), info, omitEmpty) 354 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 355 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 356 intValue := objValue.Convert(gotypes.Int64Type) 357 return marshalInt64(intValue.Interface().(int64), info, omitEmpty) 358 case reflect.Float32: 359 floatVal := objValue.Convert(gotypes.Float32Type) 360 return marshalFloat32(floatVal.Interface().(float32), info, 32, omitEmpty) 361 case reflect.Float64: 362 floatVal := objValue.Convert(gotypes.Float64Type) 363 return marshalFloat64(floatVal.Interface().(float64), info, 64, omitEmpty) 364 case reflect.Interface, reflect.Ptr: 365 if objValue.IsNil() { 366 if omitEmpty { 367 return nil 368 } else { 369 return JSONNull 370 } 371 } 372 return marshalValue(objValue.Elem(), info, omitEmpty) 373 default: 374 log.Errorf("unsupport object %s %s", objValue.Type(), objValue.Interface()) 375 return JSONNull 376 } 377 } 378 379 func MarshalAll(obj interface{}) JSONObject { 380 if obj == nil { 381 return JSONNull 382 } 383 val := reflect.ValueOf(obj) 384 if kind := val.Kind(); val.IsZero() && kind == reflect.Ptr { 385 return JSONNull 386 } 387 objValue := reflect.Indirect(val) 388 mval := marshalValue(objValue, nil, false) 389 if mval == nil { 390 return JSONNull 391 } 392 return mval 393 }