mirror of https://github.com/gin-gonic/gin.git
When the nested structure has the same name field, the resolution skips the same name field of the substructure
This commit is contained in:
parent
d062a6a615
commit
e1e6bb07f7
|
@ -78,11 +78,23 @@ func mappingByPtr(ptr interface{}, setter setter, tag string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||
type structInfo struct {
|
||||
value reflect.Value
|
||||
field reflect.StructField
|
||||
}
|
||||
|
||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string, maped ...map[string]struct{}) (bool, error) {
|
||||
if field.Tag.Get(tag) == "-" { // just ignoring this field
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var _maped map[string]struct{}
|
||||
if len(maped) > 0 {
|
||||
_maped = maped[0]
|
||||
} else {
|
||||
_maped = make(map[string]struct{})
|
||||
}
|
||||
|
||||
vKind := value.Kind()
|
||||
|
||||
if vKind == reflect.Ptr {
|
||||
|
@ -92,7 +104,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||
isNew = true
|
||||
vPtr = reflect.New(value.Type().Elem())
|
||||
}
|
||||
isSet, err := mapping(vPtr.Elem(), field, setter, tag)
|
||||
isSet, err := mapping(vPtr.Elem(), field, setter, tag, _maped)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -116,22 +128,59 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
|
|||
tValue := value.Type()
|
||||
|
||||
var isSet bool
|
||||
structs := make([]structInfo, 0)
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
sf := tValue.Field(i)
|
||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue
|
||||
}
|
||||
ok, err := mapping(value.Field(i), sf, setter, tag)
|
||||
tagValue := sf.Tag.Get(tag)
|
||||
if _, ok := _maped[tagValue]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if isStruct(value.Field(i)) {
|
||||
structs = append(structs, structInfo{
|
||||
value: value.Field(i),
|
||||
field: sf,
|
||||
})
|
||||
continue
|
||||
}
|
||||
ok, err := mapping(value.Field(i), sf, setter, tag, _maped)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isSet = isSet || ok
|
||||
|
||||
if isSet && tagValue != "" {
|
||||
_maped[tagValue] = struct{}{}
|
||||
}
|
||||
}
|
||||
for _, st := range structs {
|
||||
ok, err := mapping(st.value, st.field, setter, tag, _maped)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isSet = isSet || ok
|
||||
tagValue := st.field.Tag.Get(tag)
|
||||
if isSet && tagValue != "" {
|
||||
_maped[tagValue] = struct{}{}
|
||||
}
|
||||
}
|
||||
return isSet, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func isStruct(_field reflect.Value) bool {
|
||||
if _field.Kind() == reflect.Ptr {
|
||||
vPtr := reflect.New(_field.Type().Elem())
|
||||
return vPtr.Elem().Kind() == reflect.Struct
|
||||
} else {
|
||||
return _field.Kind() == reflect.Struct
|
||||
}
|
||||
}
|
||||
|
||||
type setOptions struct {
|
||||
isDefaultExists bool
|
||||
defaultValue string
|
||||
|
|
|
@ -288,3 +288,56 @@ func TestMappingIgnoredCircularRef(t *testing.T) {
|
|||
err := mappingByPtr(&s, formSource{}, "form")
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestMappingNestedStructure(t *testing.T) {
|
||||
formData := formSource{"name": {"hello"}, "id": {"1"}, "age": {"18"}}
|
||||
type Other struct {
|
||||
Name string `form:"name"`
|
||||
}
|
||||
type City struct {
|
||||
Id int `form:"id"`
|
||||
Name string `form:"name"`
|
||||
OtherInfo *Other
|
||||
}
|
||||
type User struct {
|
||||
Id int `form:"id"`
|
||||
Name string `form:"name"`
|
||||
Age int `form:"age"`
|
||||
CityInfo *City
|
||||
}
|
||||
var u User
|
||||
err := mappingByPtr(&u, formData, "form")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, u.Id, 1)
|
||||
assert.Equal(t, u.Name, "hello")
|
||||
assert.Nil(t, u.CityInfo)
|
||||
|
||||
type User1 struct {
|
||||
CityInfo *City
|
||||
Id int `form:"id"`
|
||||
Name string `form:"name"`
|
||||
Age int `form:"age"`
|
||||
}
|
||||
var u1 User1
|
||||
|
||||
err = mappingByPtr(&u1, formData, "form")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, u1.Id, 1)
|
||||
assert.Equal(t, u1.Name, "hello")
|
||||
assert.Nil(t, u1.CityInfo)
|
||||
|
||||
type User2 struct {
|
||||
CityInfo City
|
||||
Id int `form:"id"`
|
||||
Name string `form:"name"`
|
||||
Age int `form:"age"`
|
||||
}
|
||||
var u2 User2
|
||||
|
||||
err = mappingByPtr(&u2, formData, "form")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, u2.Id, 1)
|
||||
assert.Equal(t, u2.Name, "hello")
|
||||
assert.Equal(t, u2.CityInfo.Id, 0)
|
||||
assert.Equal(t, u2.CityInfo.Name, "")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue