diff --git a/common/json/internal/contextjson_120/decode.go b/common/json/internal/contextjson_120/decode.go index 44bed0c..7a3c809 100644 --- a/common/json/internal/contextjson_120/decode.go +++ b/common/json/internal/contextjson_120/decode.go @@ -217,6 +217,7 @@ type decodeState struct { savedError error useNumber bool disallowUnknownFields bool + context *decodeContext } // readIndex returns the position of the last byte read. @@ -245,7 +246,11 @@ func (d *decodeState) init(data []byte) *decodeState { // for reporting at the end of the unmarshal. func (d *decodeState) saveError(err error) { if d.savedError == nil { - d.savedError = d.addErrorContext(err) + if d.context != nil { + d.savedError = d.addErrorContext(&contextError{err, d.formatContext(), d.context.key == ""}) + } else { + d.savedError = d.addErrorContext(err) + } } } @@ -504,7 +509,11 @@ func (d *decodeState) array(v reflect.Value) error { if u != nil { start := d.readIndex() d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) + err := u.UnmarshalJSON(d.data[start:d.off]) + if err != nil { + d.saveError(err) + } + return nil } if ut != nil { d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) @@ -533,6 +542,7 @@ func (d *decodeState) array(v reflect.Value) error { } i := 0 + d.context = &decodeContext{parent: d.context} for { // Look ahead for ] - can only happen on first iteration. d.scanWhile(scanSkipSpace) @@ -580,8 +590,11 @@ func (d *decodeState) array(v reflect.Value) error { if d.opcode != scanArrayValue { panic(phasePanicMsg) } + d.context.index++ } + d.context = d.context.parent + if i < v.Len() { if v.Kind() == reflect.Array { // Array. Zero the rest. @@ -612,7 +625,11 @@ func (d *decodeState) object(v reflect.Value) error { if u != nil { start := d.readIndex() d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) + err := u.UnmarshalJSON(d.data[start:d.off]) + if err != nil { + d.saveError(err) + } + return nil } if ut != nil { d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) @@ -668,6 +685,7 @@ func (d *decodeState) object(v reflect.Value) error { origErrorContext = *d.errorContext } + d.context = &decodeContext{parent: d.context} for { // Read opening " of string key or closing }. d.scanWhile(scanSkipSpace) @@ -687,6 +705,7 @@ func (d *decodeState) object(v reflect.Value) error { if !ok { panic(phasePanicMsg) } + d.context.key = string(key) // Figure out field corresponding to key. var subv reflect.Value @@ -749,6 +768,7 @@ func (d *decodeState) object(v reflect.Value) error { } else if d.disallowUnknownFields { d.saveError(fmt.Errorf("json: unknown field %q", key)) } + d.context.index++ } // Read : before value. @@ -838,6 +858,7 @@ func (d *decodeState) object(v reflect.Value) error { panic(phasePanicMsg) } } + d.context = d.context.parent return nil } @@ -871,7 +892,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool isNull := item[0] == 'n' // null u, ut, pv := indirect(v, isNull) if u != nil { - return u.UnmarshalJSON(item) + err := u.UnmarshalJSON(item) + if err != nil { + d.saveError(err) + } + return nil } if ut != nil { if item[0] != '"' { @@ -1059,6 +1084,7 @@ func (d *decodeState) valueInterface() (val any) { // arrayInterface is like array but returns []interface{}. func (d *decodeState) arrayInterface() []any { v := make([]any, 0) + d.context = &decodeContext{parent: d.context} for { // Look ahead for ] - can only happen on first iteration. d.scanWhile(scanSkipSpace) @@ -1078,13 +1104,16 @@ func (d *decodeState) arrayInterface() []any { if d.opcode != scanArrayValue { panic(phasePanicMsg) } + d.context.index++ } + d.context = d.context.parent return v } // objectInterface is like object but returns map[string]interface{}. func (d *decodeState) objectInterface() map[string]any { m := make(map[string]any) + d.context = &decodeContext{parent: d.context} for { // Read opening " of string key or closing }. d.scanWhile(scanSkipSpace) @@ -1104,6 +1133,7 @@ func (d *decodeState) objectInterface() map[string]any { if !ok { panic(phasePanicMsg) } + d.context.key = key // Read : before value. if d.opcode == scanSkipSpace { @@ -1127,7 +1157,9 @@ func (d *decodeState) objectInterface() map[string]any { if d.opcode != scanObjectValue { panic(phasePanicMsg) } + d.context.index++ } + d.context = d.context.parent return m } diff --git a/common/json/internal/contextjson_120/decode_context.go b/common/json/internal/contextjson_120/decode_context.go new file mode 100644 index 0000000..3000926 --- /dev/null +++ b/common/json/internal/contextjson_120/decode_context.go @@ -0,0 +1,49 @@ +package json + +import "strconv" + +type decodeContext struct { + parent *decodeContext + index int + key string +} + +func (d *decodeState) formatContext() string { + var description string + context := d.context + var appendDot bool + for context != nil { + if appendDot { + description = "." + description + } + if context.key != "" { + description = context.key + description + appendDot = true + } else { + description = "[" + strconv.Itoa(context.index) + "]" + description + appendDot = false + } + context = context.parent + } + return description +} + +type contextError struct { + parent error + context string + index bool +} + +func (c *contextError) Unwrap() error { + return c.parent +} + +func (c *contextError) Error() string { + //goland:noinspection GoTypeAssertionOnErrors + switch c.parent.(type) { + case *contextError: + return c.context + "." + c.parent.Error() + default: + return c.context + ": " + c.parent.Error() + } +}