浏览代码

feat: optimize mapping error (#3438)

MarkJoyMa 1 年之前
父节点
当前提交
05db706c62
共有 2 个文件被更改,包括 65 次插入25 次删除
  1. 37 25
      core/mapping/unmarshaler.go
  2. 28 0
      core/mapping/unmarshaler_test.go

+ 37 - 25
core/mapping/unmarshaler.go

@@ -72,7 +72,11 @@ func UnmarshalKey(m map[string]any, v any) error {
 }
 }
 
 
 // Unmarshal unmarshals m into v.
 // Unmarshal unmarshals m into v.
-func (u *Unmarshaler) Unmarshal(i any, v any) error {
+func (u *Unmarshaler) Unmarshal(i, v any) error {
+	return u.unmarshal(i, v, "")
+}
+
+func (u *Unmarshaler) unmarshal(i, v any, fullName string) error {
 	valueType := reflect.TypeOf(v)
 	valueType := reflect.TypeOf(v)
 	if valueType.Kind() != reflect.Ptr {
 	if valueType.Kind() != reflect.Ptr {
 		return errValueNotSettable
 		return errValueNotSettable
@@ -85,13 +89,13 @@ func (u *Unmarshaler) Unmarshal(i any, v any) error {
 			return errTypeMismatch
 			return errTypeMismatch
 		}
 		}
 
 
-		return u.UnmarshalValuer(mapValuer(iv), v)
+		return u.unmarshalValuer(mapValuer(iv), v, fullName)
 	case []any:
 	case []any:
 		if elemType.Kind() != reflect.Slice {
 		if elemType.Kind() != reflect.Slice {
 			return errTypeMismatch
 			return errTypeMismatch
 		}
 		}
 
 
-		return u.fillSlice(elemType, reflect.ValueOf(v).Elem(), iv)
+		return u.fillSlice(elemType, reflect.ValueOf(v).Elem(), iv, fullName)
 	default:
 	default:
 		return errUnsupportedType
 		return errUnsupportedType
 	}
 	}
@@ -99,17 +103,21 @@ func (u *Unmarshaler) Unmarshal(i any, v any) error {
 
 
 // UnmarshalValuer unmarshals m into v.
 // UnmarshalValuer unmarshals m into v.
 func (u *Unmarshaler) UnmarshalValuer(m Valuer, v any) error {
 func (u *Unmarshaler) UnmarshalValuer(m Valuer, v any) error {
-	return u.unmarshalWithFullName(simpleValuer{current: m}, v, "")
+	return u.unmarshalValuer(simpleValuer{current: m}, v, "")
+}
+
+func (u *Unmarshaler) unmarshalValuer(m Valuer, v any, fullName string) error {
+	return u.unmarshalWithFullName(simpleValuer{current: m}, v, fullName)
 }
 }
 
 
-func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapValue any) error {
+func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapValue any, fullName string) error {
 	if !value.CanSet() {
 	if !value.CanSet() {
 		return errValueNotSettable
 		return errValueNotSettable
 	}
 	}
 
 
 	fieldKeyType := fieldType.Key()
 	fieldKeyType := fieldType.Key()
 	fieldElemType := fieldType.Elem()
 	fieldElemType := fieldType.Elem()
-	targetValue, err := u.generateMap(fieldKeyType, fieldElemType, mapValue)
+	targetValue, err := u.generateMap(fieldKeyType, fieldElemType, mapValue, fullName)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -143,14 +151,14 @@ func (u *Unmarshaler) fillMapFromString(value reflect.Value, mapValue any) error
 	return nil
 	return nil
 }
 }
 
 
-func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, mapValue any) error {
+func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, mapValue any, fullName string) error {
 	if !value.CanSet() {
 	if !value.CanSet() {
 		return errValueNotSettable
 		return errValueNotSettable
 	}
 	}
 
 
 	refValue := reflect.ValueOf(mapValue)
 	refValue := reflect.ValueOf(mapValue)
 	if refValue.Kind() != reflect.Slice {
 	if refValue.Kind() != reflect.Slice {
-		return errTypeMismatch
+		return fmt.Errorf("%s: %v", fullName, errTypeMismatch)
 	}
 	}
 	if refValue.IsNil() {
 	if refValue.IsNil() {
 		return nil
 		return nil
@@ -172,6 +180,8 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
 			continue
 			continue
 		}
 		}
 
 
+		sliceFullName := fmt.Sprintf("%s[%d]", fullName, i)
+
 		valid = true
 		valid = true
 		switch dereffedBaseKind {
 		switch dereffedBaseKind {
 		case reflect.Struct:
 		case reflect.Struct:
@@ -181,17 +191,17 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
 				return errTypeMismatch
 				return errTypeMismatch
 			}
 			}
 
 
-			if err := u.Unmarshal(val, target.Interface()); err != nil {
+			if err := u.unmarshal(val, target.Interface(), sliceFullName); err != nil {
 				return err
 				return err
 			}
 			}
 
 
 			SetValue(fieldType.Elem(), conv.Index(i), target.Elem())
 			SetValue(fieldType.Elem(), conv.Index(i), target.Elem())
 		case reflect.Slice:
 		case reflect.Slice:
-			if err := u.fillSlice(dereffedBaseType, conv.Index(i), ithValue); err != nil {
+			if err := u.fillSlice(dereffedBaseType, conv.Index(i), ithValue, sliceFullName); err != nil {
 				return err
 				return err
 			}
 			}
 		default:
 		default:
-			if err := u.fillSliceValue(conv, i, dereffedBaseKind, ithValue); err != nil {
+			if err := u.fillSliceValue(conv, i, dereffedBaseKind, ithValue, sliceFullName); err != nil {
 				return err
 				return err
 			}
 			}
 		}
 		}
@@ -205,7 +215,7 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
 }
 }
 
 
 func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.Value,
 func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.Value,
-	mapValue any) error {
+	mapValue any, fullName string) error {
 	var slice []any
 	var slice []any
 	switch v := mapValue.(type) {
 	switch v := mapValue.(type) {
 	case fmt.Stringer:
 	case fmt.Stringer:
@@ -225,7 +235,7 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
 	conv := reflect.MakeSlice(reflect.SliceOf(baseFieldType), len(slice), cap(slice))
 	conv := reflect.MakeSlice(reflect.SliceOf(baseFieldType), len(slice), cap(slice))
 
 
 	for i := 0; i < len(slice); i++ {
 	for i := 0; i < len(slice); i++ {
-		if err := u.fillSliceValue(conv, i, baseFieldKind, slice[i]); err != nil {
+		if err := u.fillSliceValue(conv, i, baseFieldKind, slice[i], fullName); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -235,7 +245,7 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
 }
 }
 
 
 func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
 func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
-	baseKind reflect.Kind, value any) error {
+	baseKind reflect.Kind, value any, fullName string) error {
 	ithVal := slice.Index(index)
 	ithVal := slice.Index(index)
 	switch v := value.(type) {
 	switch v := value.(type) {
 	case fmt.Stringer:
 	case fmt.Stringer:
@@ -243,7 +253,7 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
 	case string:
 	case string:
 		return setValueFromString(baseKind, ithVal, v)
 		return setValueFromString(baseKind, ithVal, v)
 	case map[string]any:
 	case map[string]any:
-		return u.fillMap(ithVal.Type(), ithVal, value)
+		return u.fillMap(ithVal.Type(), ithVal, value, fullName)
 	default:
 	default:
 		// don't need to consider the difference between int, int8, int16, int32, int64,
 		// don't need to consider the difference between int, int8, int16, int32, int64,
 		// uint, uint8, uint16, uint32, uint64, because they're handled as json.Number.
 		// uint, uint8, uint16, uint32, uint64, because they're handled as json.Number.
@@ -269,7 +279,7 @@ func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
 }
 }
 
 
 func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value reflect.Value,
 func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value reflect.Value,
-	defaultValue string) error {
+	defaultValue, fullName string) error {
 	baseFieldType := Deref(derefedType.Elem())
 	baseFieldType := Deref(derefedType.Elem())
 	baseFieldKind := baseFieldType.Kind()
 	baseFieldKind := baseFieldType.Kind()
 	defaultCacheLock.Lock()
 	defaultCacheLock.Lock()
@@ -287,10 +297,10 @@ func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value refle
 		defaultCacheLock.Unlock()
 		defaultCacheLock.Unlock()
 	}
 	}
 
 
-	return u.fillSlice(derefedType, value, slice)
+	return u.fillSlice(derefedType, value, slice, fullName)
 }
 }
 
 
-func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any) (reflect.Value, error) {
+func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any, fullName string) (reflect.Value, error) {
 	mapType := reflect.MapOf(keyType, elemType)
 	mapType := reflect.MapOf(keyType, elemType)
 	valueType := reflect.TypeOf(mapValue)
 	valueType := reflect.TypeOf(mapValue)
 	if mapType == valueType {
 	if mapType == valueType {
@@ -310,10 +320,12 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
 		keythValue := refValue.MapIndex(key)
 		keythValue := refValue.MapIndex(key)
 		keythData := keythValue.Interface()
 		keythData := keythValue.Interface()
 
 
+		mapFullName := fmt.Sprintf("%s[%s]", fullName, key.String())
+
 		switch dereffedElemKind {
 		switch dereffedElemKind {
 		case reflect.Slice:
 		case reflect.Slice:
 			target := reflect.New(dereffedElemType)
 			target := reflect.New(dereffedElemType)
-			if err := u.fillSlice(elemType, target.Elem(), keythData); err != nil {
+			if err := u.fillSlice(elemType, target.Elem(), keythData, mapFullName); err != nil {
 				return emptyValue, err
 				return emptyValue, err
 			}
 			}
 
 
@@ -325,7 +337,7 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
 			}
 			}
 
 
 			target := reflect.New(dereffedElemType)
 			target := reflect.New(dereffedElemType)
-			if err := u.Unmarshal(keythMap, target.Interface()); err != nil {
+			if err := u.unmarshal(keythMap, target.Interface(), mapFullName); err != nil {
 				return emptyValue, err
 				return emptyValue, err
 			}
 			}
 
 
@@ -336,7 +348,7 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any)
 				return emptyValue, errTypeMismatch
 				return emptyValue, errTypeMismatch
 			}
 			}
 
 
-			innerValue, err := u.generateMap(elemType.Key(), elemType.Elem(), keythMap)
+			innerValue, err := u.generateMap(elemType.Key(), elemType.Elem(), keythMap, mapFullName)
 			if err != nil {
 			if err != nil {
 				return emptyValue, err
 				return emptyValue, err
 			}
 			}
@@ -541,13 +553,13 @@ func (u *Unmarshaler) processFieldNotFromString(fieldType reflect.Type, value re
 			parent:  vp.parent,
 			parent:  vp.parent,
 		}, fullName)
 		}, fullName)
 	case typeKind == reflect.Slice && valueKind == reflect.Slice:
 	case typeKind == reflect.Slice && valueKind == reflect.Slice:
-		return u.fillSlice(fieldType, value, mapValue)
+		return u.fillSlice(fieldType, value, mapValue, fullName)
 	case valueKind == reflect.Map && typeKind == reflect.Map:
 	case valueKind == reflect.Map && typeKind == reflect.Map:
-		return u.fillMap(fieldType, value, mapValue)
+		return u.fillMap(fieldType, value, mapValue, fullName)
 	case valueKind == reflect.String && typeKind == reflect.Map:
 	case valueKind == reflect.String && typeKind == reflect.Map:
 		return u.fillMapFromString(value, mapValue)
 		return u.fillMapFromString(value, mapValue)
 	case valueKind == reflect.String && typeKind == reflect.Slice:
 	case valueKind == reflect.String && typeKind == reflect.Slice:
-		return u.fillSliceFromString(fieldType, value, mapValue)
+		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))
 	default:
 	default:
@@ -819,7 +831,7 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
 
 
 		switch fieldKind {
 		switch fieldKind {
 		case reflect.Array, reflect.Slice:
 		case reflect.Array, reflect.Slice:
-			return u.fillSliceWithDefault(derefedType, value, defaultValue)
+			return u.fillSliceWithDefault(derefedType, value, defaultValue, fullName)
 		default:
 		default:
 			return setValueFromString(fieldKind, value, defaultValue)
 			return setValueFromString(fieldKind, value, defaultValue)
 		}
 		}

+ 28 - 0
core/mapping/unmarshaler_test.go

@@ -4980,6 +4980,34 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
 		err := unmarshaler.UnmarshalValuer(nil, &i)
 		err := unmarshaler.UnmarshalValuer(nil, &i)
 		assert.Error(t, err)
 		assert.Error(t, err)
 	})
 	})
+
+	t.Run("slice element missing error", func(t *testing.T) {
+		type inner struct {
+			S []struct {
+				Name string `json:"name"`
+				Age  int    `json:"age"`
+			} `json:"s"`
+		}
+		content := []byte(`{"s": [{"name": "foo"}]}`)
+		var s inner
+		err := UnmarshalJsonBytes(content, &s)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "s[0].age")
+	})
+
+	t.Run("map element missing error", func(t *testing.T) {
+		type inner struct {
+			S map[string]struct {
+				Name string `json:"name"`
+				Age  int    `json:"age"`
+			} `json:"s"`
+		}
+		content := []byte(`{"s": {"a":{"name": "foo"}}}`)
+		var s inner
+		err := UnmarshalJsonBytes(content, &s)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "s[a].age")
+	})
 }
 }
 
 
 // TestUnmarshalerProcessFieldPrimitiveWithJSONNumber test the number type check.
 // TestUnmarshalerProcessFieldPrimitiveWithJSONNumber test the number type check.