diff options
Diffstat (limited to 'libgo/go/encoding/json/decode.go')
-rw-r--r-- | libgo/go/encoding/json/decode.go | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 62ac294b89f..458fb39ec01 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -8,6 +8,7 @@ package json import ( + "encoding" "encoding/base64" "errors" "fmt" @@ -37,9 +38,7 @@ import ( // keys to the keys used by Marshal (either the struct field name or its tag), // preferring an exact match but also accepting a case-insensitive match. // -// To unmarshal JSON into an interface value, Unmarshal unmarshals -// the JSON into the concrete value contained in the interface value. -// If the interface value is nil, that is, has no concrete value stored in it, +// To unmarshal JSON into an interface value, // Unmarshal stores one of these in the interface value: // // bool, for JSON booleans @@ -293,7 +292,7 @@ func (d *decodeState) value(v reflect.Value) { // until it gets to a non-pointer. // if it encounters an Unmarshaler, indirect stops and returns that. // if decodingNull is true, indirect stops at the last pointer so it can be set to nil. -func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) { +func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { // If v is a named type and is addressable, // start with its address, so that if the type has pointer methods, // we find them. @@ -322,28 +321,38 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, v.Set(reflect.New(v.Type().Elem())) } if v.Type().NumMethod() > 0 { - if unmarshaler, ok := v.Interface().(Unmarshaler); ok { - return unmarshaler, reflect.Value{} + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} } } v = v.Elem() } - return nil, v + return nil, nil, v } // array consumes an array from d.data[d.off-1:], decoding into the value v. // the first byte of the array ('[') has been read already. func (d *decodeState) array(v reflect.Value) { // Check for unmarshaler. - unmarshaler, pv := d.indirect(v, false) - if unmarshaler != nil { + u, ut, pv := d.indirect(v, false) + if u != nil { d.off-- - err := unmarshaler.UnmarshalJSON(d.next()) + err := u.UnmarshalJSON(d.next()) if err != nil { d.error(err) } return } + if ut != nil { + d.saveError(&UnmarshalTypeError{"array", v.Type()}) + d.off-- + d.next() + return + } + v = pv // Check type of target. @@ -434,15 +443,21 @@ func (d *decodeState) array(v reflect.Value) { // the first byte of the object ('{') has been read already. func (d *decodeState) object(v reflect.Value) { // Check for unmarshaler. - unmarshaler, pv := d.indirect(v, false) - if unmarshaler != nil { + u, ut, pv := d.indirect(v, false) + if u != nil { d.off-- - err := unmarshaler.UnmarshalJSON(d.next()) + err := u.UnmarshalJSON(d.next()) if err != nil { d.error(err) } return } + if ut != nil { + d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.off-- + d.next() // skip over { } in input + return + } v = pv // Decoding into nil interface? Switch to non-reflect code. @@ -611,14 +626,37 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool return } wantptr := item[0] == 'n' // null - unmarshaler, pv := d.indirect(v, wantptr) - if unmarshaler != nil { - err := unmarshaler.UnmarshalJSON(item) + u, ut, pv := d.indirect(v, wantptr) + if u != nil { + err := u.UnmarshalJSON(item) + if err != nil { + d.error(err) + } + return + } + if ut != nil { + if item[0] != '"' { + 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()}) + } + } + s, ok := unquoteBytes(item) + if !ok { + 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(errPhase) + } + } + err := ut.UnmarshalText(s) if err != nil { d.error(err) } return } + v = pv switch c := item[0]; c { |