mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/json: support encoding.TextMarshaler, encoding.TextUnmarshaler
R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/12703043
This commit is contained in:
parent
5822e7848a
commit
7e886740d1
4 changed files with 315 additions and 26 deletions
|
|
@ -8,6 +8,7 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
|
@ -293,7 +294,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 +323,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 +445,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 +628,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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue