contextjson120: Add context to decode error message

This commit is contained in:
世界 2023-12-05 14:52:03 +08:00
parent 96f5dea24b
commit 51aeb14a87
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
2 changed files with 85 additions and 4 deletions

View file

@ -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
}

View file

@ -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()
}
}