encoding/json: add embedded structs to the UnmarshalTypeError's Field

Including embedded struct inforamtion in error message.

Fixes #68941
This commit is contained in:
j2gg0s 2024-08-20 16:30:51 +08:00
parent 6edc1c23ed
commit 717f680aca
3 changed files with 27 additions and 7 deletions

View File

@ -0,0 +1 @@
[UnmarshalTypeError.Field] now includes embedded structs to provide more detailed error messages.

View File

@ -127,7 +127,7 @@ type UnmarshalTypeError struct {
Type reflect.Type // type of Go value it could not be assigned to Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes Offset int64 // error occurred after reading Offset bytes
Struct string // name of the struct type containing the field Struct string // name of the struct type containing the field
Field string // the full path from root node to the field Field string // the full path from root node to the field, include embedded struct
} }
func (e *UnmarshalTypeError) Error() string { func (e *UnmarshalTypeError) Error() string {
@ -701,7 +701,10 @@ func (d *decodeState) object(v reflect.Value) error {
if f != nil { if f != nil {
subv = v subv = v
destring = f.quoted destring = f.quoted
for _, i := range f.index { if d.errorContext == nil {
d.errorContext = new(errorContext)
}
for i, ind := range f.index {
if subv.Kind() == reflect.Pointer { if subv.Kind() == reflect.Pointer {
if subv.IsNil() { if subv.IsNil() {
// If a struct embeds a pointer to an unexported type, // If a struct embeds a pointer to an unexported type,
@ -721,13 +724,16 @@ func (d *decodeState) object(v reflect.Value) error {
} }
subv = subv.Elem() subv = subv.Elem()
} }
subv = subv.Field(i) if i < len(f.index)-1 {
d.errorContext.FieldStack = append(
d.errorContext.FieldStack,
subv.Type().Field(ind).Name,
)
} }
if d.errorContext == nil { subv = subv.Field(ind)
d.errorContext = new(errorContext)
} }
d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name)
d.errorContext.Struct = t d.errorContext.Struct = t
d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name)
} else if d.disallowUnknownFields { } else if d.disallowUnknownFields {
d.saveError(fmt.Errorf("json: unknown field %q", key)) d.saveError(fmt.Errorf("json: unknown field %q", key))
} }

View File

@ -898,6 +898,19 @@ var unmarshalTests = []struct {
}, },
}, },
{
CaseName: Name(""),
in: `{"Level1a": "hello"}`,
ptr: new(Top),
err: &UnmarshalTypeError{
Value: "string",
Struct: "Top",
Field: "Embed0a.Level1a",
Type: reflect.TypeFor[int](),
Offset: 10,
},
},
// issue 15146. // issue 15146.
// invalid inputs in wrongStringTests below. // invalid inputs in wrongStringTests below.
{CaseName: Name(""), in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true}, {CaseName: Name(""), in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true},