github.com/wangyougui/gf/v2@v2.6.5/util/gconv/gconv_struct.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  package gconv
     8  
     9  import (
    10  	"reflect"
    11  	"strings"
    12  
    13  	"github.com/wangyougui/gf/v2/errors/gcode"
    14  	"github.com/wangyougui/gf/v2/errors/gerror"
    15  	"github.com/wangyougui/gf/v2/internal/empty"
    16  	"github.com/wangyougui/gf/v2/internal/json"
    17  	"github.com/wangyougui/gf/v2/internal/utils"
    18  	"github.com/wangyougui/gf/v2/os/gstructs"
    19  	"github.com/wangyougui/gf/v2/util/gtag"
    20  )
    21  
    22  // Struct maps the params key-value pairs to the corresponding struct object's attributes.
    23  // The third parameter `mapping` is unnecessary, indicating the mapping rules between the
    24  // custom key name and the attribute name(case-sensitive).
    25  //
    26  // Note:
    27  //  1. The `params` can be any type of map/struct, usually a map.
    28  //  2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object
    29  //     or struct pointer.
    30  //  3. Only the public attributes of struct object can be mapped.
    31  //  4. If `params` is a map, the key of the map `params` can be lowercase.
    32  //     It will automatically convert the first letter of the key to uppercase
    33  //     in mapping procedure to do the matching.
    34  //     It ignores the map key, if it does not match.
    35  func Struct(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
    36  	return Scan(params, pointer, paramKeyToAttrMap...)
    37  }
    38  
    39  // StructTag acts as Struct but also with support for priority tag feature, which retrieves the
    40  // specified tags for `params` key-value items to struct attribute names mapping.
    41  // The parameter `priorityTag` supports multiple tags that can be joined with char ','.
    42  func StructTag(params interface{}, pointer interface{}, priorityTag string) (err error) {
    43  	return doStruct(params, pointer, nil, priorityTag)
    44  }
    45  
    46  // doStruct is the core internal converting function for any data to struct.
    47  func doStruct(
    48  	params interface{}, pointer interface{}, paramKeyToAttrMap map[string]string, priorityTag string,
    49  ) (err error) {
    50  	if params == nil {
    51  		// If `params` is nil, no conversion.
    52  		return nil
    53  	}
    54  	if pointer == nil {
    55  		return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil")
    56  	}
    57  
    58  	// JSON content converting.
    59  	ok, err := doConvertWithJsonCheck(params, pointer)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	if ok {
    64  		return nil
    65  	}
    66  
    67  	defer func() {
    68  		// Catch the panic, especially the reflection operation panics.
    69  		if exception := recover(); exception != nil {
    70  			if v, ok := exception.(error); ok && gerror.HasStack(v) {
    71  				err = v
    72  			} else {
    73  				err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
    74  			}
    75  		}
    76  	}()
    77  
    78  	var (
    79  		paramsReflectValue      reflect.Value
    80  		paramsInterface         interface{} // DO NOT use `params` directly as it might be type `reflect.Value`
    81  		pointerReflectValue     reflect.Value
    82  		pointerReflectKind      reflect.Kind
    83  		pointerElemReflectValue reflect.Value // The pointed element.
    84  	)
    85  	if v, ok := params.(reflect.Value); ok {
    86  		paramsReflectValue = v
    87  	} else {
    88  		paramsReflectValue = reflect.ValueOf(params)
    89  	}
    90  	paramsInterface = paramsReflectValue.Interface()
    91  	if v, ok := pointer.(reflect.Value); ok {
    92  		pointerReflectValue = v
    93  		pointerElemReflectValue = v
    94  	} else {
    95  		pointerReflectValue = reflect.ValueOf(pointer)
    96  		pointerReflectKind = pointerReflectValue.Kind()
    97  		if pointerReflectKind != reflect.Ptr {
    98  			return gerror.NewCodef(
    99  				gcode.CodeInvalidParameter,
   100  				"destination pointer should be type of '*struct', but got '%v'",
   101  				pointerReflectKind,
   102  			)
   103  		}
   104  		// Using IsNil on reflect.Ptr variable is OK.
   105  		if !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() {
   106  			return gerror.NewCode(
   107  				gcode.CodeInvalidParameter,
   108  				"destination pointer cannot be nil",
   109  			)
   110  		}
   111  		pointerElemReflectValue = pointerReflectValue.Elem()
   112  	}
   113  
   114  	// If `params` and `pointer` are the same type, the do directly assignment.
   115  	// For performance enhancement purpose.
   116  	if ok = doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok {
   117  		return nil
   118  	}
   119  
   120  	// custom convert.
   121  	if ok, err = callCustomConverter(paramsReflectValue, pointerReflectValue); ok {
   122  		return err
   123  	}
   124  
   125  	// Normal unmarshalling interfaces checks.
   126  	if ok, err = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok {
   127  		return err
   128  	}
   129  
   130  	// It automatically creates struct object if necessary.
   131  	// For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User.
   132  	if pointerElemReflectValue.Kind() == reflect.Ptr {
   133  		if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {
   134  			e := reflect.New(pointerElemReflectValue.Type().Elem())
   135  			pointerElemReflectValue.Set(e)
   136  			defer func() {
   137  				if err != nil {
   138  					// If it is converted failed, it reset the `pointer` to nil.
   139  					pointerReflectValue.Elem().Set(reflect.Zero(pointerReflectValue.Type().Elem()))
   140  				}
   141  			}()
   142  		}
   143  		// if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok {
   144  		//	return v.UnmarshalValue(params)
   145  		// }
   146  		// Note that it's `pointerElemReflectValue` here not `pointerReflectValue`.
   147  		if ok, err := bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok {
   148  			return err
   149  		}
   150  		// Retrieve its element, may be struct at last.
   151  		pointerElemReflectValue = pointerElemReflectValue.Elem()
   152  	}
   153  
   154  	// paramsMap is the map[string]interface{} type variable for params.
   155  	// DO NOT use MapDeep here.
   156  	paramsMap := doMapConvert(paramsInterface, recursiveTypeAuto, true)
   157  	if paramsMap == nil {
   158  		return gerror.NewCodef(
   159  			gcode.CodeInvalidParameter,
   160  			`convert params from "%#v" to "map[string]interface{}" failed`,
   161  			params,
   162  		)
   163  	}
   164  
   165  	// Nothing to be done as the parameters are empty.
   166  	if len(paramsMap) == 0 {
   167  		return nil
   168  	}
   169  
   170  	// It only performs one converting to the same attribute.
   171  	// doneMap is used to check repeated converting, its key is the real attribute name
   172  	// of the struct.
   173  	doneMap := make(map[string]struct{})
   174  
   175  	// The key of the attrMap is the attribute name of the struct,
   176  	// and the value is its replaced name for later comparison to improve performance.
   177  	var (
   178  		tempName       string
   179  		elemFieldType  reflect.StructField
   180  		elemFieldValue reflect.Value
   181  		elemType       = pointerElemReflectValue.Type()
   182  		// Attribute name to its symbols-removed name,
   183  		// in order to quick index and comparison in following logic.
   184  		attrToCheckNameMap = make(map[string]string)
   185  	)
   186  	for i := 0; i < pointerElemReflectValue.NumField(); i++ {
   187  		elemFieldType = elemType.Field(i)
   188  		// Only do converting to public attributes.
   189  		if !utils.IsLetterUpper(elemFieldType.Name[0]) {
   190  			continue
   191  		}
   192  		// Maybe it's struct/*struct embedded.
   193  		if elemFieldType.Anonymous {
   194  			elemFieldValue = pointerElemReflectValue.Field(i)
   195  			// Ignore the interface attribute if it's nil.
   196  			if elemFieldValue.Kind() == reflect.Interface {
   197  				elemFieldValue = elemFieldValue.Elem()
   198  				if !elemFieldValue.IsValid() {
   199  					continue
   200  				}
   201  			}
   202  			if err = doStruct(paramsMap, elemFieldValue, paramKeyToAttrMap, priorityTag); err != nil {
   203  				return err
   204  			}
   205  		} else {
   206  			tempName = elemFieldType.Name
   207  			attrToCheckNameMap[tempName] = utils.RemoveSymbols(tempName)
   208  		}
   209  	}
   210  	if len(attrToCheckNameMap) == 0 {
   211  		return nil
   212  	}
   213  
   214  	// The key of the `attrToTagCheckNameMap` is the attribute name of the struct,
   215  	// and the value is its replaced tag name for later comparison to improve performance.
   216  	var (
   217  		attrToTagCheckNameMap = make(map[string]string)
   218  		priorityTagArray      []string
   219  	)
   220  	if priorityTag != "" {
   221  		priorityTagArray = append(utils.SplitAndTrim(priorityTag, ","), gtag.StructTagPriority...)
   222  	} else {
   223  		priorityTagArray = gtag.StructTagPriority
   224  	}
   225  	tagToAttrNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	for tagName, attributeName := range tagToAttrNameMap {
   230  		// If there's something else in the tag string,
   231  		// it uses the first part which is split using char ','.
   232  		// Eg:
   233  		// orm:"id, priority"
   234  		// orm:"name, with:uid=id"
   235  		attrToTagCheckNameMap[attributeName] = utils.RemoveSymbols(strings.Split(tagName, ",")[0])
   236  		// If tag and attribute values both exist in `paramsMap`,
   237  		// it then uses the tag value overwriting the attribute value in `paramsMap`.
   238  		if paramsMap[tagName] != nil && paramsMap[attributeName] != nil {
   239  			paramsMap[attributeName] = paramsMap[tagName]
   240  		}
   241  	}
   242  
   243  	// To convert value base on custom parameter key to attribute name map.
   244  	err = doStructBaseOnParamKeyToAttrMap(
   245  		pointerElemReflectValue,
   246  		paramsMap,
   247  		paramKeyToAttrMap,
   248  		doneMap,
   249  	)
   250  	if err != nil {
   251  		return err
   252  	}
   253  	// Already done all attributes value assignment nothing to do next.
   254  	if len(doneMap) == len(attrToCheckNameMap) {
   255  		return nil
   256  	}
   257  
   258  	// To convert value base on precise attribute name.
   259  	err = doStructBaseOnAttribute(
   260  		pointerElemReflectValue,
   261  		paramsMap,
   262  		paramKeyToAttrMap,
   263  		doneMap,
   264  		attrToCheckNameMap,
   265  	)
   266  	if err != nil {
   267  		return err
   268  	}
   269  	// Already done all attributes value assignment nothing to do next.
   270  	if len(doneMap) == len(attrToCheckNameMap) {
   271  		return nil
   272  	}
   273  
   274  	// To convert value base on parameter map.
   275  	err = doStructBaseOnParamMap(
   276  		pointerElemReflectValue,
   277  		paramsMap,
   278  		paramKeyToAttrMap,
   279  		doneMap,
   280  		attrToCheckNameMap,
   281  		attrToTagCheckNameMap,
   282  		tagToAttrNameMap,
   283  	)
   284  	if err != nil {
   285  		return err
   286  	}
   287  	return nil
   288  }
   289  
   290  func doStructBaseOnParamKeyToAttrMap(
   291  	pointerElemReflectValue reflect.Value,
   292  	paramsMap map[string]interface{},
   293  	paramKeyToAttrMap map[string]string,
   294  	doneAttrMap map[string]struct{},
   295  ) error {
   296  	if len(paramKeyToAttrMap) == 0 {
   297  		return nil
   298  	}
   299  	for paramKey, attrName := range paramKeyToAttrMap {
   300  		paramValue, ok := paramsMap[paramKey]
   301  		if !ok {
   302  			continue
   303  		}
   304  		// If the attribute name is already checked converting, then skip it.
   305  		if _, ok = doneAttrMap[attrName]; ok {
   306  			continue
   307  		}
   308  		// Mark it done.
   309  		doneAttrMap[attrName] = struct{}{}
   310  		if err := bindVarToStructAttr(
   311  			pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap,
   312  		); err != nil {
   313  			return err
   314  		}
   315  	}
   316  	return nil
   317  }
   318  
   319  func doStructBaseOnAttribute(
   320  	pointerElemReflectValue reflect.Value,
   321  	paramsMap map[string]interface{},
   322  	paramKeyToAttrMap map[string]string,
   323  	doneAttrMap map[string]struct{},
   324  	attrToCheckNameMap map[string]string,
   325  ) error {
   326  	var customMappingAttrMap = make(map[string]struct{})
   327  	if len(paramKeyToAttrMap) > 0 {
   328  		// It ignores the attribute names if it is specified in the `paramKeyToAttrMap`.
   329  		for paramName := range paramsMap {
   330  			if passedAttrKey, ok := paramKeyToAttrMap[paramName]; ok {
   331  				customMappingAttrMap[passedAttrKey] = struct{}{}
   332  			}
   333  		}
   334  	}
   335  	for attrName := range attrToCheckNameMap {
   336  		// The value by precise attribute name.
   337  		paramValue, ok := paramsMap[attrName]
   338  		if !ok {
   339  			continue
   340  		}
   341  		// If the attribute name is in custom paramKeyToAttrMap, it then ignores this converting.
   342  		if _, ok = customMappingAttrMap[attrName]; ok {
   343  			continue
   344  		}
   345  		// If the attribute name is already checked converting, then skip it.
   346  		if _, ok = doneAttrMap[attrName]; ok {
   347  			continue
   348  		}
   349  		// Mark it done.
   350  		doneAttrMap[attrName] = struct{}{}
   351  		if err := bindVarToStructAttr(
   352  			pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap,
   353  		); err != nil {
   354  			return err
   355  		}
   356  	}
   357  	return nil
   358  }
   359  
   360  func doStructBaseOnParamMap(
   361  	pointerElemReflectValue reflect.Value,
   362  	paramsMap map[string]interface{},
   363  	paramKeyToAttrMap map[string]string,
   364  	doneAttrMap map[string]struct{},
   365  	attrToCheckNameMap map[string]string,
   366  	attrToTagCheckNameMap map[string]string,
   367  	tagToAttrNameMap map[string]string,
   368  ) error {
   369  	var (
   370  		attrName  string
   371  		checkName string
   372  	)
   373  	for paramName, paramValue := range paramsMap {
   374  		// It firstly considers `paramName` as accurate tag name,
   375  		// and retrieve attribute name from `tagToAttrNameMap` .
   376  		attrName = tagToAttrNameMap[paramName]
   377  		if attrName == "" {
   378  			checkName = utils.RemoveSymbols(paramName)
   379  			// Loop to find the matched attribute name with or without
   380  			// string cases and chars like '-'/'_'/'.'/' '.
   381  
   382  			// Matching the parameters to struct tag names.
   383  			// The `attrKey` is the attribute name of the struct.
   384  			for attrKey, cmpKey := range attrToTagCheckNameMap {
   385  				if strings.EqualFold(checkName, cmpKey) {
   386  					attrName = attrKey
   387  					break
   388  				}
   389  			}
   390  		}
   391  
   392  		// Matching the parameters to struct attributes.
   393  		if attrName == "" {
   394  			for attrKey, cmpKey := range attrToCheckNameMap {
   395  				// Eg:
   396  				// UserName  eq user_name
   397  				// User-Name eq username
   398  				// username  eq userName
   399  				// etc.
   400  				if strings.EqualFold(checkName, cmpKey) {
   401  					attrName = attrKey
   402  					break
   403  				}
   404  			}
   405  		}
   406  
   407  		// No matching, it gives up this attribute converting.
   408  		if attrName == "" {
   409  			continue
   410  		}
   411  		// If the attribute name is already checked converting, then skip it.
   412  		if _, ok := doneAttrMap[attrName]; ok {
   413  			continue
   414  		}
   415  		// Mark it done.
   416  		doneAttrMap[attrName] = struct{}{}
   417  		if err := bindVarToStructAttr(
   418  			pointerElemReflectValue, attrName, paramValue, paramKeyToAttrMap,
   419  		); err != nil {
   420  			return err
   421  		}
   422  	}
   423  	return nil
   424  }
   425  
   426  // bindVarToStructAttr sets value to struct object attribute by name.
   427  func bindVarToStructAttr(
   428  	structReflectValue reflect.Value,
   429  	attrName string, value interface{}, paramKeyToAttrMap map[string]string,
   430  ) (err error) {
   431  	structFieldValue := structReflectValue.FieldByName(attrName)
   432  	if !structFieldValue.IsValid() {
   433  		return nil
   434  	}
   435  	// CanSet checks whether attribute is public accessible.
   436  	if !structFieldValue.CanSet() {
   437  		return nil
   438  	}
   439  	defer func() {
   440  		if exception := recover(); exception != nil {
   441  			if err = bindVarToReflectValue(structFieldValue, value, paramKeyToAttrMap); err != nil {
   442  				err = gerror.Wrapf(err, `error binding value to attribute "%s"`, attrName)
   443  			}
   444  		}
   445  	}()
   446  	// Directly converting.
   447  	if empty.IsNil(value) {
   448  		structFieldValue.Set(reflect.Zero(structFieldValue.Type()))
   449  	} else {
   450  		// Try to call custom converter.
   451  		// Issue: https://github.com/wangyougui/gf/issues/3099
   452  		var (
   453  			customConverterInput reflect.Value
   454  			ok                   bool
   455  		)
   456  		if customConverterInput, ok = value.(reflect.Value); !ok {
   457  			customConverterInput = reflect.ValueOf(value)
   458  		}
   459  
   460  		if ok, err = callCustomConverter(customConverterInput, structFieldValue); ok || err != nil {
   461  			return
   462  		}
   463  
   464  		// Special handling for certain types:
   465  		// - Overwrite the default type converting logic of stdlib for time.Time/*time.Time.
   466  		var structFieldTypeName = structFieldValue.Type().String()
   467  		switch structFieldTypeName {
   468  		case "time.Time", "*time.Time":
   469  			doConvertWithReflectValueSet(structFieldValue, doConvertInput{
   470  				FromValue:  value,
   471  				ToTypeName: structFieldTypeName,
   472  				ReferValue: structFieldValue,
   473  			})
   474  			return
   475  		// Hold the time zone consistent in recursive
   476  		// Issue: https://github.com/wangyougui/gf/issues/2980
   477  		case "*gtime.Time", "gtime.Time":
   478  			doConvertWithReflectValueSet(structFieldValue, doConvertInput{
   479  				FromValue:  value,
   480  				ToTypeName: structFieldTypeName,
   481  				ReferValue: structFieldValue,
   482  			})
   483  			return
   484  		}
   485  
   486  		// Common interface check.
   487  		if ok, err = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
   488  			return err
   489  		}
   490  
   491  		// Default converting.
   492  		doConvertWithReflectValueSet(structFieldValue, doConvertInput{
   493  			FromValue:  value,
   494  			ToTypeName: structFieldTypeName,
   495  			ReferValue: structFieldValue,
   496  		})
   497  	}
   498  	return nil
   499  }
   500  
   501  // bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks.
   502  func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (bool, error) {
   503  	var pointer interface{}
   504  	if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() {
   505  		reflectValueAddr := reflectValue.Addr()
   506  		if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() {
   507  			return false, nil
   508  		}
   509  		// Not a pointer, but can token address, that makes it can be unmarshalled.
   510  		pointer = reflectValue.Addr().Interface()
   511  	} else {
   512  		if reflectValue.IsNil() || !reflectValue.IsValid() {
   513  			return false, nil
   514  		}
   515  		pointer = reflectValue.Interface()
   516  	}
   517  	// UnmarshalValue.
   518  	if v, ok := pointer.(iUnmarshalValue); ok {
   519  		return ok, v.UnmarshalValue(value)
   520  	}
   521  	// UnmarshalText.
   522  	if v, ok := pointer.(iUnmarshalText); ok {
   523  		var valueBytes []byte
   524  		if b, ok := value.([]byte); ok {
   525  			valueBytes = b
   526  		} else if s, ok := value.(string); ok {
   527  			valueBytes = []byte(s)
   528  		} else if f, ok := value.(iString); ok {
   529  			valueBytes = []byte(f.String())
   530  		}
   531  		if len(valueBytes) > 0 {
   532  			return ok, v.UnmarshalText(valueBytes)
   533  		}
   534  	}
   535  	// UnmarshalJSON.
   536  	if v, ok := pointer.(iUnmarshalJSON); ok {
   537  		var valueBytes []byte
   538  		if b, ok := value.([]byte); ok {
   539  			valueBytes = b
   540  		} else if s, ok := value.(string); ok {
   541  			valueBytes = []byte(s)
   542  		} else if f, ok := value.(iString); ok {
   543  			valueBytes = []byte(f.String())
   544  		}
   545  
   546  		if len(valueBytes) > 0 {
   547  			// If it is not a valid JSON string, it then adds char `"` on its both sides to make it is.
   548  			if !json.Valid(valueBytes) {
   549  				newValueBytes := make([]byte, len(valueBytes)+2)
   550  				newValueBytes[0] = '"'
   551  				newValueBytes[len(newValueBytes)-1] = '"'
   552  				copy(newValueBytes[1:], valueBytes)
   553  				valueBytes = newValueBytes
   554  			}
   555  			return ok, v.UnmarshalJSON(valueBytes)
   556  		}
   557  	}
   558  	if v, ok := pointer.(iSet); ok {
   559  		v.Set(value)
   560  		return ok, nil
   561  	}
   562  	return false, nil
   563  }
   564  
   565  // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
   566  func bindVarToReflectValue(
   567  	structFieldValue reflect.Value, value interface{}, paramKeyToAttrMap map[string]string,
   568  ) (err error) {
   569  	// JSON content converting.
   570  	ok, err := doConvertWithJsonCheck(value, structFieldValue)
   571  	if err != nil {
   572  		return err
   573  	}
   574  	if ok {
   575  		return nil
   576  	}
   577  
   578  	kind := structFieldValue.Kind()
   579  	// Converting using `Set` interface implements, for some types.
   580  	switch kind {
   581  	case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface:
   582  		if !structFieldValue.IsNil() {
   583  			if v, ok := structFieldValue.Interface().(iSet); ok {
   584  				v.Set(value)
   585  				return nil
   586  			}
   587  		}
   588  	}
   589  
   590  	// Converting using reflection by kind.
   591  	switch kind {
   592  	case reflect.Map:
   593  		return doMapToMap(value, structFieldValue, paramKeyToAttrMap)
   594  
   595  	case reflect.Struct:
   596  		// Recursively converting for struct attribute.
   597  		if err = doStruct(value, structFieldValue, nil, ""); err != nil {
   598  			// Note there's reflect conversion mechanism here.
   599  			structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
   600  		}
   601  
   602  	// Note that the slice element might be type of struct,
   603  	// so it uses Struct function doing the converting internally.
   604  	case reflect.Slice, reflect.Array:
   605  		var (
   606  			reflectArray reflect.Value
   607  			reflectValue = reflect.ValueOf(value)
   608  		)
   609  		if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array {
   610  			reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len())
   611  			if reflectValue.Len() > 0 {
   612  				var (
   613  					elemType     = reflectArray.Index(0).Type()
   614  					elemTypeName string
   615  					converted    bool
   616  				)
   617  				for i := 0; i < reflectValue.Len(); i++ {
   618  					converted = false
   619  					elemTypeName = elemType.Name()
   620  					if elemTypeName == "" {
   621  						elemTypeName = elemType.String()
   622  					}
   623  					var elem reflect.Value
   624  					if elemType.Kind() == reflect.Ptr {
   625  						elem = reflect.New(elemType.Elem()).Elem()
   626  					} else {
   627  						elem = reflect.New(elemType).Elem()
   628  					}
   629  					if elem.Kind() == reflect.Struct {
   630  						if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil {
   631  							converted = true
   632  						}
   633  					}
   634  					if !converted {
   635  						doConvertWithReflectValueSet(elem, doConvertInput{
   636  							FromValue:  reflectValue.Index(i).Interface(),
   637  							ToTypeName: elemTypeName,
   638  							ReferValue: elem,
   639  						})
   640  					}
   641  					if elemType.Kind() == reflect.Ptr {
   642  						// Before it sets the `elem` to array, do pointer converting if necessary.
   643  						elem = elem.Addr()
   644  					}
   645  					reflectArray.Index(i).Set(elem)
   646  				}
   647  			}
   648  		} else {
   649  			var (
   650  				elem         reflect.Value
   651  				elemType     = structFieldValue.Type().Elem()
   652  				elemTypeName = elemType.Name()
   653  				converted    bool
   654  			)
   655  			switch reflectValue.Kind() {
   656  			case reflect.String:
   657  				// Value is empty string.
   658  				if reflectValue.IsZero() {
   659  					var elemKind = elemType.Kind()
   660  					// Try to find the original type kind of the slice element.
   661  					if elemKind == reflect.Ptr {
   662  						elemKind = elemType.Elem().Kind()
   663  					}
   664  					switch elemKind {
   665  					case reflect.String:
   666  						// Empty string cannot be assigned to string slice.
   667  						return nil
   668  					}
   669  				}
   670  			}
   671  			if elemTypeName == "" {
   672  				elemTypeName = elemType.String()
   673  			}
   674  			if elemType.Kind() == reflect.Ptr {
   675  				elem = reflect.New(elemType.Elem()).Elem()
   676  			} else {
   677  				elem = reflect.New(elemType).Elem()
   678  			}
   679  			if elem.Kind() == reflect.Struct {
   680  				if err = doStruct(value, elem, nil, ""); err == nil {
   681  					converted = true
   682  				}
   683  			}
   684  			if !converted {
   685  				doConvertWithReflectValueSet(elem, doConvertInput{
   686  					FromValue:  value,
   687  					ToTypeName: elemTypeName,
   688  					ReferValue: elem,
   689  				})
   690  			}
   691  			if elemType.Kind() == reflect.Ptr {
   692  				// Before it sets the `elem` to array, do pointer converting if necessary.
   693  				elem = elem.Addr()
   694  			}
   695  			reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
   696  			reflectArray.Index(0).Set(elem)
   697  		}
   698  		structFieldValue.Set(reflectArray)
   699  
   700  	case reflect.Ptr:
   701  		if structFieldValue.IsNil() || structFieldValue.IsZero() {
   702  			// Nil or empty pointer, it creates a new one.
   703  			item := reflect.New(structFieldValue.Type().Elem())
   704  			if ok, err = bindVarToReflectValueWithInterfaceCheck(item, value); ok {
   705  				structFieldValue.Set(item)
   706  				return err
   707  			}
   708  			elem := item.Elem()
   709  			if err = bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil {
   710  				structFieldValue.Set(elem.Addr())
   711  			}
   712  		} else {
   713  			// Not empty pointer, it assigns values to it.
   714  			return bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap)
   715  		}
   716  
   717  	// It mainly and specially handles the interface of nil value.
   718  	case reflect.Interface:
   719  		if value == nil {
   720  			// Specially.
   721  			structFieldValue.Set(reflect.ValueOf((*interface{})(nil)))
   722  		} else {
   723  			// Note there's reflect conversion mechanism here.
   724  			structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
   725  		}
   726  
   727  	default:
   728  		defer func() {
   729  			if exception := recover(); exception != nil {
   730  				err = gerror.NewCodef(
   731  					gcode.CodeInternalPanic,
   732  					`cannot convert value "%+v" to type "%s":%+v`,
   733  					value,
   734  					structFieldValue.Type().String(),
   735  					exception,
   736  				)
   737  			}
   738  		}()
   739  		// It here uses reflect converting `value` to type of the attribute and assigns
   740  		// the result value to the attribute. It might fail and panic if the usual Go
   741  		// conversion rules do not allow conversion.
   742  		structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
   743  	}
   744  	return nil
   745  }