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  }