From a257ffb1784709658efcb622a88d7b54cbee0b55 Mon Sep 17 00:00:00 2001 From: Alex Plugaru Date: Mon, 26 Jan 2015 11:51:43 +0100 Subject: [PATCH] encoding/json: add UnmarshalTypeError.Offset Fixes #9693 Change-Id: Ibf07199729bfc883b2a7e051cafd98185f912acd Reviewed-on: https://go-review.googlesource.com/3283 Reviewed-by: Russ Cox Reviewed-by: Brad Fitzpatrick --- src/encoding/json/decode.go | 39 ++++++++++++++++---------------- src/encoding/json/decode_test.go | 4 ++-- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 212365cede..f26a7d49f0 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -90,8 +90,9 @@ type Unmarshaler interface { // An UnmarshalTypeError describes a JSON value that was // not appropriate for a value of a specific Go type. type UnmarshalTypeError struct { - Value string // description of JSON value - "bool", "array", "number -5" - Type reflect.Type // type of Go value it could not be assigned to + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes } func (e *UnmarshalTypeError) Error() string { @@ -377,7 +378,7 @@ func (d *decodeState) array(v reflect.Value) { return } if ut != nil { - d.saveError(&UnmarshalTypeError{"array", v.Type()}) + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) d.off-- d.next() return @@ -396,7 +397,7 @@ func (d *decodeState) array(v reflect.Value) { // Otherwise it's invalid. fallthrough default: - d.saveError(&UnmarshalTypeError{"array", v.Type()}) + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) d.off-- d.next() return @@ -485,7 +486,7 @@ func (d *decodeState) object(v reflect.Value) { return } if ut != nil { - d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) d.off-- d.next() // skip over { } in input return @@ -504,7 +505,7 @@ func (d *decodeState) object(v reflect.Value) { // map must have string kind t := v.Type() if t.Key().Kind() != reflect.String { - d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) d.off-- d.next() // skip over { } in input return @@ -515,7 +516,7 @@ func (d *decodeState) object(v reflect.Value) { case reflect.Struct: default: - d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) d.off-- d.next() // skip over { } in input return @@ -646,7 +647,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) { } f, err := strconv.ParseFloat(s, 64) if err != nil { - return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)} + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} } return f, nil } @@ -679,7 +680,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) } else { - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) } } s, ok := unquoteBytes(item) @@ -713,7 +714,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) } else { - d.saveError(&UnmarshalTypeError{"bool", v.Type()}) + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) } case reflect.Bool: v.SetBool(value) @@ -721,7 +722,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if v.NumMethod() == 0 { v.Set(reflect.ValueOf(value)) } else { - d.saveError(&UnmarshalTypeError{"bool", v.Type()}) + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) } } @@ -736,10 +737,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } switch v.Kind() { default: - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) case reflect.Slice: if v.Type() != byteSliceType { - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) break } b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) @@ -755,7 +756,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if v.NumMethod() == 0 { v.Set(reflect.ValueOf(string(s))) } else { - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) } } @@ -777,7 +778,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) } else { - d.error(&UnmarshalTypeError{"number", v.Type()}) + d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) } case reflect.Interface: n, err := d.convertNumber(s) @@ -786,7 +787,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool break } if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{"number", v.Type()}) + d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) break } v.Set(reflect.ValueOf(n)) @@ -794,7 +795,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: n, err := strconv.ParseInt(s, 10, 64) if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) break } v.SetInt(n) @@ -802,7 +803,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: n, err := strconv.ParseUint(s, 10, 64) if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) break } v.SetUint(n) @@ -810,7 +811,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool case reflect.Float32, reflect.Float64: n, err := strconv.ParseFloat(s, v.Type().Bits()) if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) break } v.SetFloat(n) diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 83b9d39ad6..7ecc8f4402 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -231,7 +231,7 @@ var unmarshalTests = []unmarshalTest{ {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, {in: "null", ptr: new(interface{}), out: nil}, - {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}}, + {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, @@ -411,7 +411,7 @@ var unmarshalTests = []unmarshalTest{ { in: `{"2009-11-10T23:00:00Z": "hello world"}`, ptr: &map[time.Time]string{}, - err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})}, + err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1}, }, } -- 2.50.0