diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 461a6c7da..57fadd7c9 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -220,12 +220,6 @@ func doStruct( if len(usedParamsKeyOrTagNameMap) == len(paramsMap) { return nil } - // If the length of `paramsMap` is less than the number of fields, then loop based on `paramsMap` - if len(paramsMap) < len(cachedStructInfo.FieldConvertInfos) { - return bindStructWithLoopParamsMap( - paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, - ) - } return bindStructWithLoopFieldInfos( paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo, ) @@ -247,84 +241,6 @@ func setOtherSameNameField( return nil } -func bindStructWithLoopParamsMap( - paramsMap map[string]any, - structValue reflect.Value, - paramKeyToAttrMap map[string]string, - usedParamsKeyOrTagNameMap map[string]struct{}, - cachedStructInfo *structcache.CachedStructInfo, -) (err error) { - var ( - fieldName string - cachedFieldInfo *structcache.CachedFieldInfo - fieldValue reflect.Value - paramKey string - paramValue any - ok bool - ) - for paramKey, paramValue = range paramsMap { - if _, ok = usedParamsKeyOrTagNameMap[paramKey]; ok { - continue - } - cachedFieldInfo = cachedStructInfo.GetFieldInfo(paramKey) - if cachedFieldInfo != nil { - fieldName = cachedFieldInfo.FieldName() - // already converted using its field name? - // the field name has the more priority than tag name. - _, ok = usedParamsKeyOrTagNameMap[fieldName] - if ok && cachedFieldInfo.IsField { - continue - } - fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) - if err = bindVarToStructField( - fieldValue, paramValue, cachedFieldInfo, paramKeyToAttrMap, - ); err != nil { - return err - } - // handle same field name in nested struct. - if len(cachedFieldInfo.OtherSameNameField) > 0 { - if err = setOtherSameNameField(cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap); err != nil { - return err - } - } - usedParamsKeyOrTagNameMap[fieldName] = struct{}{} - continue - } - - // fuzzy matching. - for _, cachedFieldInfo = range cachedStructInfo.FieldConvertInfos { - fieldName = cachedFieldInfo.FieldName() - if _, ok = usedParamsKeyOrTagNameMap[fieldName]; ok { - continue - } - if !strings.EqualFold( - cachedFieldInfo.RemoveSymbolsFieldName, - utils.RemoveSymbols(paramKey)) { - continue - } - fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) - if paramValue != nil { - if err = bindVarToStructField( - fieldValue, paramValue, cachedFieldInfo, paramKeyToAttrMap, - ); err != nil { - return err - } - // handle same field name in nested struct. - if len(cachedFieldInfo.OtherSameNameField) > 0 { - if err = setOtherSameNameField( - cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap, - ); err != nil { - return err - } - } - } - usedParamsKeyOrTagNameMap[cachedFieldInfo.FieldName()] = struct{}{} - break - } - } - return nil -} - func bindStructWithLoopFieldInfos( paramsMap map[string]any, structValue reflect.Value, @@ -346,10 +262,6 @@ func bindStructWithLoopFieldInfos( if paramValue, ok = paramsMap[fieldTag]; !ok { continue } - if _, ok = usedParamsKeyOrTagNameMap[fieldTag]; ok { - matched = true - break - } fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue) if err = bindVarToStructField( fieldValue, paramValue, cachedFieldInfo, paramKeyToAttrMap, diff --git a/util/gconv/gconv_z_unit_issue_test.go b/util/gconv/gconv_z_unit_issue_test.go index 55b6149ad..7e80fe30a 100644 --- a/util/gconv/gconv_z_unit_issue_test.go +++ b/util/gconv/gconv_z_unit_issue_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/gogf/gf/v2/container/gtype" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/internal/json" @@ -783,3 +784,24 @@ func Test_Issue3868(t *testing.T) { } }) } + +// https://github.com/gogf/gf/issues/3903 +func Test_Issue3903(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + type TestA struct { + UserId int `json:"UserId" orm:"user_id" ` + } + type TestB struct { + TestA + UserId int `json:"NewUserId" description:""` + } + var input = map[string]interface{}{ + "user_id": gvar.New(100, true), + } + var a TestB + err := gconv.StructTag(input, &a, "orm") + t.AssertNil(err) + t.Assert(a.TestA.UserId, 100) + t.Assert(a.UserId, 100) + }) +} diff --git a/util/gconv/internal/structcache/structcache_cached_struct_info.go b/util/gconv/internal/structcache/structcache_cached_struct_info.go index 70fd1bf44..245107376 100644 --- a/util/gconv/internal/structcache/structcache_cached_struct_info.go +++ b/util/gconv/internal/structcache/structcache_cached_struct_info.go @@ -59,16 +59,17 @@ func (csi *CachedStructInfo) AddField(field reflect.StructField, fieldIndexes [] } func (csi *CachedStructInfo) makeOrCopyCachedInfo( - field reflect.StructField, - fieldIndexes []int, - priorityTags []string, + field reflect.StructField, fieldIndexes []int, priorityTags []string, cachedFieldInfo *CachedFieldInfo, currTagOrFieldName string, ) (newFieldInfo *CachedFieldInfo) { if cachedFieldInfo == nil { // If the field is not cached, it creates a new one. newFieldInfo = csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags) - } else if cachedFieldInfo.StructField.Type != field.Type { + newFieldInfo.IsField = currTagOrFieldName == field.Name + return + } + if cachedFieldInfo.StructField.Type != field.Type { // If the types are different, some information needs to be reset. newFieldInfo = csi.makeCachedFieldInfo(field, fieldIndexes, priorityTags) } else {