mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-14 02:10:00 +08:00
chore: refactor mapping unmarshaler (#4145)
This commit is contained in:
@@ -113,27 +113,6 @@ func (u *Unmarshaler) unmarshalValuer(m Valuer, v any, fullName string) error {
|
|||||||
return u.unmarshalWithFullName(simpleValuer{current: m}, v, fullName)
|
return u.unmarshalWithFullName(simpleValuer{current: m}, v, fullName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Unmarshaler) fillJsonUnmarshalerStruct(fieldType reflect.Type,
|
|
||||||
value reflect.Value, targetValue string) error {
|
|
||||||
if !value.CanSet() {
|
|
||||||
return errValueNotSettable
|
|
||||||
}
|
|
||||||
|
|
||||||
baseType := Deref(fieldType)
|
|
||||||
target := reflect.New(baseType)
|
|
||||||
unmarshaler, ok := target.Interface().(json.Unmarshaler)
|
|
||||||
if !ok {
|
|
||||||
return errUnsupportedType
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unmarshaler.UnmarshalJSON([]byte(targetValue)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
value.Set(target)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value,
|
func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value,
|
||||||
mapValue any, fullName string) error {
|
mapValue any, fullName string) error {
|
||||||
if !value.CanSet() {
|
if !value.CanSet() {
|
||||||
@@ -330,6 +309,32 @@ func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value refle
|
|||||||
return u.fillSlice(derefedType, value, slice, fullName)
|
return u.fillSlice(derefedType, value, slice, fullName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) fillUnmarshalerStruct(fieldType reflect.Type,
|
||||||
|
value reflect.Value, targetValue string) error {
|
||||||
|
if !value.CanSet() {
|
||||||
|
return errValueNotSettable
|
||||||
|
}
|
||||||
|
|
||||||
|
baseType := Deref(fieldType)
|
||||||
|
target := reflect.New(baseType)
|
||||||
|
switch u.key {
|
||||||
|
case jsonTagKey:
|
||||||
|
unmarshaler, ok := target.Interface().(json.Unmarshaler)
|
||||||
|
if !ok {
|
||||||
|
return errUnsupportedType
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unmarshaler.UnmarshalJSON([]byte(targetValue)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return errUnsupportedType
|
||||||
|
}
|
||||||
|
|
||||||
|
value.Set(target)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any,
|
func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any,
|
||||||
fullName string) (reflect.Value, error) {
|
fullName string) (reflect.Value, error) {
|
||||||
mapType := reflect.MapOf(keyType, elemType)
|
mapType := reflect.MapOf(keyType, elemType)
|
||||||
@@ -423,6 +428,15 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any,
|
|||||||
return targetValue, nil
|
return targetValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *Unmarshaler) implementsUnmarshaler(t reflect.Type) bool {
|
||||||
|
switch u.key {
|
||||||
|
case jsonTagKey:
|
||||||
|
return t.Implements(reflect.TypeOf((*json.Unmarshaler)(nil)).Elem())
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (u *Unmarshaler) parseOptionsWithContext(field reflect.StructField, m Valuer, fullName string) (
|
func (u *Unmarshaler) parseOptionsWithContext(field reflect.StructField, m Valuer, fullName string) (
|
||||||
string, *fieldOptionsWithContext, error) {
|
string, *fieldOptionsWithContext, error) {
|
||||||
key, options, err := parseKeyAndOptions(u.key, field)
|
key, options, err := parseKeyAndOptions(u.key, field)
|
||||||
@@ -600,8 +614,8 @@ func (u *Unmarshaler) processFieldNotFromString(fieldType reflect.Type, value re
|
|||||||
return u.fillSliceFromString(fieldType, value, mapValue, fullName)
|
return u.fillSliceFromString(fieldType, value, mapValue, fullName)
|
||||||
case valueKind == reflect.String && derefedFieldType == durationType:
|
case valueKind == reflect.String && derefedFieldType == durationType:
|
||||||
return fillDurationValue(fieldType, value, mapValue.(string))
|
return fillDurationValue(fieldType, value, mapValue.(string))
|
||||||
case valueKind == reflect.String && typeKind == reflect.Struct && implementsJsonUnmarshaler(fieldType):
|
case valueKind == reflect.String && typeKind == reflect.Struct && u.implementsUnmarshaler(fieldType):
|
||||||
return u.fillJsonUnmarshalerStruct(fieldType, value, mapValue.(string))
|
return u.fillUnmarshalerStruct(fieldType, value, mapValue.(string))
|
||||||
default:
|
default:
|
||||||
return u.processFieldPrimitive(fieldType, value, mapValue, opts, fullName)
|
return u.processFieldPrimitive(fieldType, value, mapValue, opts, fullName)
|
||||||
}
|
}
|
||||||
@@ -1087,10 +1101,6 @@ func getValueWithChainedKeys(m valuerWithParent, keys []string) (any, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func implementsJsonUnmarshaler(t reflect.Type) bool {
|
|
||||||
return t.Implements(reflect.TypeOf((*json.Unmarshaler)(nil)).Elem())
|
|
||||||
}
|
|
||||||
|
|
||||||
func join(elem ...string) string {
|
func join(elem ...string) string {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
|
|||||||
@@ -5761,7 +5761,7 @@ func TestUnmarshalWithIgnoreFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshal_JsonUnmarshaler(t *testing.T) {
|
func TestUnmarshal_Unmarshaler(t *testing.T) {
|
||||||
t.Run("success", func(t *testing.T) {
|
t.Run("success", func(t *testing.T) {
|
||||||
v := struct {
|
v := struct {
|
||||||
Foo *mockUnmarshaler `json:"name"`
|
Foo *mockUnmarshaler `json:"name"`
|
||||||
@@ -5778,6 +5778,30 @@ func TestUnmarshal_JsonUnmarshaler(t *testing.T) {
|
|||||||
body := `{"name": "hello"}`
|
body := `{"name": "hello"}`
|
||||||
assert.Error(t, UnmarshalJsonBytes([]byte(body), &v))
|
assert.Error(t, UnmarshalJsonBytes([]byte(body), &v))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("not json unmarshaler", func(t *testing.T) {
|
||||||
|
v := struct {
|
||||||
|
Foo *struct {
|
||||||
|
Name string
|
||||||
|
} `key:"name"`
|
||||||
|
}{}
|
||||||
|
u := NewUnmarshaler(defaultKeyName)
|
||||||
|
assert.Error(t, u.Unmarshal(map[string]any{
|
||||||
|
"name": "hello",
|
||||||
|
}, &v))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not with json key", func(t *testing.T) {
|
||||||
|
v := struct {
|
||||||
|
Foo *mockUnmarshaler `json:"name"`
|
||||||
|
}{}
|
||||||
|
u := NewUnmarshaler(defaultKeyName)
|
||||||
|
// with different key, ignore
|
||||||
|
assert.NoError(t, u.Unmarshal(map[string]any{
|
||||||
|
"name": "hello",
|
||||||
|
}, &v))
|
||||||
|
assert.Nil(t, v.Foo)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkDefaultValue(b *testing.B) {
|
func BenchmarkDefaultValue(b *testing.B) {
|
||||||
|
|||||||
Reference in New Issue
Block a user