summaryrefslogtreecommitdiff
path: root/src/pkg/encoding/json
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/encoding/json')
-rw-r--r--src/pkg/encoding/json/bench_test.go34
-rw-r--r--src/pkg/encoding/json/decode.go244
-rw-r--r--src/pkg/encoding/json/decode_test.go607
-rw-r--r--src/pkg/encoding/json/encode.go266
-rw-r--r--src/pkg/encoding/json/encode_test.go20
-rw-r--r--src/pkg/encoding/json/scanner_test.go9
-rw-r--r--src/pkg/encoding/json/stream.go13
-rw-r--r--src/pkg/encoding/json/stream_test.go46
-rw-r--r--src/pkg/encoding/json/tagkey_test.go10
9 files changed, 999 insertions, 250 deletions
diff --git a/src/pkg/encoding/json/bench_test.go b/src/pkg/encoding/json/bench_test.go
index 333c1c0ce..29dbc26d4 100644
--- a/src/pkg/encoding/json/bench_test.go
+++ b/src/pkg/encoding/json/bench_test.go
@@ -153,5 +153,37 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
b.Fatal("Unmmarshal:", err)
}
}
- b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkUnmarshalString(b *testing.B) {
+ data := []byte(`"hello, world"`)
+ var s string
+
+ for i := 0; i < b.N; i++ {
+ if err := Unmarshal(data, &s); err != nil {
+ b.Fatal("Unmarshal:", err)
+ }
+ }
+}
+
+func BenchmarkUnmarshalFloat64(b *testing.B) {
+ var f float64
+ data := []byte(`3.14`)
+
+ for i := 0; i < b.N; i++ {
+ if err := Unmarshal(data, &f); err != nil {
+ b.Fatal("Unmarshal:", err)
+ }
+ }
+}
+
+func BenchmarkUnmarshalInt64(b *testing.B) {
+ var x int64
+ data := []byte(`3`)
+
+ for i := 0; i < b.N; i++ {
+ if err := Unmarshal(data, &x); err != nil {
+ b.Fatal("Unmarshal:", err)
+ }
+ }
}
diff --git a/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go
index d61f88706..f2ec9cb67 100644
--- a/src/pkg/encoding/json/decode.go
+++ b/src/pkg/encoding/json/decode.go
@@ -33,6 +33,10 @@ import (
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
//
+// To unmarshal JSON into a struct, Unmarshal matches incoming object
+// 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,
@@ -51,24 +55,29 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
+// When unmarshaling quoted strings, invalid UTF-8 or
+// invalid UTF-16 surrogate pairs are not treated as an error.
+// Instead, they are replaced by the Unicode replacement
+// character U+FFFD.
+//
func Unmarshal(data []byte, v interface{}) error {
- d := new(decodeState).init(data)
-
- // Quick check for well-formedness.
+ // Check for well-formedness.
// Avoids filling out half a data structure
// before discovering a JSON syntax error.
+ var d decodeState
err := checkValid(data, &d.scan)
if err != nil {
return err
}
+ d.init(data)
return d.unmarshal(v)
}
// Unmarshaler is the interface implemented by objects
// that can unmarshal a JSON description of themselves.
-// The input can be assumed to be a valid JSON object
-// encoding. UnmarshalJSON must copy the JSON data
+// The input can be assumed to be a valid encoding of
+// a JSON value. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
@@ -87,6 +96,7 @@ func (e *UnmarshalTypeError) Error() string {
// An UnmarshalFieldError describes a JSON object key that
// led to an unexported (and therefore unwritable) struct field.
+// (No longer used; kept for compatibility.)
type UnmarshalFieldError struct {
Key string
Type reflect.Type
@@ -125,18 +135,33 @@ func (d *decodeState) unmarshal(v interface{}) (err error) {
}()
rv := reflect.ValueOf(v)
- pv := rv
- if pv.Kind() != reflect.Ptr || pv.IsNil() {
+ if rv.Kind() != reflect.Ptr || rv.IsNil() {
return &InvalidUnmarshalError{reflect.TypeOf(v)}
}
d.scan.reset()
- // We decode rv not pv.Elem because the Unmarshaler interface
+ // We decode rv not rv.Elem because the Unmarshaler interface
// test must be applied at the top level of the value.
d.value(rv)
return d.savedError
}
+// A Number represents a JSON number literal.
+type Number string
+
+// String returns the literal text of the number.
+func (n Number) String() string { return string(n) }
+
+// Float64 returns the number as a float64.
+func (n Number) Float64() (float64, error) {
+ return strconv.ParseFloat(string(n), 64)
+}
+
+// Int64 returns the number as an int64.
+func (n Number) Int64() (int64, error) {
+ return strconv.ParseInt(string(n), 10, 64)
+}
+
// decodeState represents the state while decoding a JSON value.
type decodeState struct {
data []byte
@@ -145,6 +170,7 @@ type decodeState struct {
nextscan scanner // for calls to nextValue
savedError error
tempstr string // scratch space to avoid some allocations
+ useNumber bool
}
// errPhase is used for errors that should not happen unless
@@ -265,47 +291,32 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
v = v.Addr()
}
for {
- var isUnmarshaler bool
- if v.Type().NumMethod() > 0 {
- // Remember that this is an unmarshaler,
- // but wait to return it until after allocating
- // the pointer (if necessary).
- _, isUnmarshaler = v.Interface().(Unmarshaler)
- }
-
// Load value from interface, but only if the result will be
// usefully addressable.
- if iv := v; iv.Kind() == reflect.Interface && !iv.IsNil() {
- e := iv.Elem()
+ if v.Kind() == reflect.Interface && !v.IsNil() {
+ e := v.Elem()
if e.Kind() == reflect.Ptr && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Ptr) {
v = e
continue
}
}
- pv := v
- if pv.Kind() != reflect.Ptr {
+ if v.Kind() != reflect.Ptr {
break
}
- if pv.Elem().Kind() != reflect.Ptr && decodingNull && pv.CanSet() {
- return nil, pv
+ if v.Elem().Kind() != reflect.Ptr && decodingNull && v.CanSet() {
+ break
}
- if pv.IsNil() {
- pv.Set(reflect.New(pv.Type().Elem()))
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
}
- if isUnmarshaler {
- // Using v.Interface().(Unmarshaler)
- // here means that we have to use a pointer
- // as the struct field. We cannot use a value inside
- // a pointer to a struct, because in that case
- // v.Interface() is the value (x.f) not the pointer (&x.f).
- // This is an unfortunate consequence of reflect.
- // An alternative would be to look up the
- // UnmarshalJSON method and return a FuncValue.
- return v.Interface().(Unmarshaler), reflect.Value{}
+ if v.Type().NumMethod() > 0 {
+ if unmarshaler, ok := v.Interface().(Unmarshaler); ok {
+ return unmarshaler, reflect.Value{}
+ }
}
- v = pv.Elem()
+ v = v.Elem()
}
return nil, v
}
@@ -327,15 +338,19 @@ func (d *decodeState) array(v reflect.Value) {
// Check type of target.
switch v.Kind() {
+ case reflect.Interface:
+ if v.NumMethod() == 0 {
+ // Decoding into nil interface? Switch to non-reflect code.
+ v.Set(reflect.ValueOf(d.arrayInterface()))
+ return
+ }
+ // Otherwise it's invalid.
+ fallthrough
default:
d.saveError(&UnmarshalTypeError{"array", v.Type()})
d.off--
d.next()
return
- case reflect.Interface:
- // Decoding into nil interface? Switch to non-reflect code.
- v.Set(reflect.ValueOf(d.arrayInterface()))
- return
case reflect.Array:
case reflect.Slice:
break
@@ -421,36 +436,27 @@ func (d *decodeState) object(v reflect.Value) {
v = pv
// Decoding into nil interface? Switch to non-reflect code.
- iv := v
- if iv.Kind() == reflect.Interface {
- iv.Set(reflect.ValueOf(d.objectInterface()))
+ if v.Kind() == reflect.Interface && v.NumMethod() == 0 {
+ v.Set(reflect.ValueOf(d.objectInterface()))
return
}
// Check type of target: struct or map[string]T
- var (
- mv reflect.Value
- sv reflect.Value
- )
switch v.Kind() {
case reflect.Map:
- // map must have string type
+ // map must have string kind
t := v.Type()
- if t.Key() != reflect.TypeOf("") {
+ if t.Key().Kind() != reflect.String {
d.saveError(&UnmarshalTypeError{"object", v.Type()})
break
}
- mv = v
- if mv.IsNil() {
- mv.Set(reflect.MakeMap(t))
+ if v.IsNil() {
+ v.Set(reflect.MakeMap(t))
}
case reflect.Struct:
- sv = v
+
default:
d.saveError(&UnmarshalTypeError{"object", v.Type()})
- }
-
- if !mv.IsValid() && !sv.IsValid() {
d.off--
d.next() // skip over { } in input
return
@@ -482,8 +488,8 @@ func (d *decodeState) object(v reflect.Value) {
var subv reflect.Value
destring := false // whether the value is wrapped in a string to be decoded first
- if mv.IsValid() {
- elemType := mv.Type().Elem()
+ if v.Kind() == reflect.Map {
+ elemType := v.Type().Elem()
if !mapElem.IsValid() {
mapElem = reflect.New(elemType).Elem()
} else {
@@ -491,51 +497,30 @@ func (d *decodeState) object(v reflect.Value) {
}
subv = mapElem
} else {
- var f reflect.StructField
- var ok bool
- st := sv.Type()
- for i := 0; i < sv.NumField(); i++ {
- sf := st.Field(i)
- tag := sf.Tag.Get("json")
- if tag == "-" {
- // Pretend this field doesn't exist.
- continue
- }
- if sf.Anonymous {
- // Pretend this field doesn't exist,
- // so that we can do a good job with
- // these in a later version.
- continue
- }
- // First, tag match
- tagName, _ := parseTag(tag)
- if tagName == key {
- f = sf
- ok = true
- break // no better match possible
- }
- // Second, exact field name match
- if sf.Name == key {
- f = sf
- ok = true
+ var f *field
+ fields := cachedTypeFields(v.Type())
+ for i := range fields {
+ ff := &fields[i]
+ if ff.name == key {
+ f = ff
+ break
}
- // Third, case-insensitive field name match,
- // but only if a better match hasn't already been seen
- if !ok && strings.EqualFold(sf.Name, key) {
- f = sf
- ok = true
+ if f == nil && strings.EqualFold(ff.name, key) {
+ f = ff
}
}
-
- // Extract value; name must be exported.
- if ok {
- if f.PkgPath != "" {
- d.saveError(&UnmarshalFieldError{key, st, f})
- } else {
- subv = sv.FieldByIndex(f.Index)
+ if f != nil {
+ subv = v
+ destring = f.quoted
+ for _, i := range f.index {
+ if subv.Kind() == reflect.Ptr {
+ if subv.IsNil() {
+ subv.Set(reflect.New(subv.Type().Elem()))
+ }
+ subv = subv.Elem()
+ }
+ subv = subv.Field(i)
}
- _, opts := parseTag(f.Tag.Get("json"))
- destring = opts.Contains("string")
}
}
@@ -554,10 +539,12 @@ func (d *decodeState) object(v reflect.Value) {
} else {
d.value(subv)
}
+
// Write value back to map;
// if using struct, subv points into struct already.
- if mv.IsValid() {
- mv.SetMapIndex(reflect.ValueOf(key), subv)
+ if v.Kind() == reflect.Map {
+ kv := reflect.ValueOf(key).Convert(v.Type().Key())
+ v.SetMapIndex(kv, subv)
}
// Next token must be , or }.
@@ -586,6 +573,21 @@ func (d *decodeState) literal(v reflect.Value) {
d.literalStore(d.data[start:d.off], v, false)
}
+// convertNumber converts the number literal s to a float64 or a Number
+// depending on the setting of d.useNumber.
+func (d *decodeState) convertNumber(s string) (interface{}, error) {
+ if d.useNumber {
+ return Number(s), nil
+ }
+ f, err := strconv.ParseFloat(s, 64)
+ if err != nil {
+ return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)}
+ }
+ return f, nil
+}
+
+var numberType = reflect.TypeOf(Number(""))
+
// literalStore decodes a literal stored in item into v.
//
// fromQuoted indicates whether this literal came from unwrapping a
@@ -612,12 +614,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
switch c := item[0]; c {
case 'n': // null
switch v.Kind() {
- default:
- d.saveError(&UnmarshalTypeError{"null", v.Type()})
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
v.Set(reflect.Zero(v.Type()))
+ // otherwise, ignore null for primitives/string
}
-
case 't', 'f': // true, false
value := c == 't'
switch v.Kind() {
@@ -630,7 +630,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Bool:
v.SetBool(value)
case reflect.Interface:
- v.Set(reflect.ValueOf(value))
+ if v.NumMethod() == 0 {
+ v.Set(reflect.ValueOf(value))
+ } else {
+ d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+ }
}
case '"': // string
@@ -660,7 +664,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.String:
v.SetString(string(s))
case reflect.Interface:
- v.Set(reflect.ValueOf(string(s)))
+ if v.NumMethod() == 0 {
+ v.Set(reflect.ValueOf(string(s)))
+ } else {
+ d.saveError(&UnmarshalTypeError{"string", v.Type()})
+ }
}
default: // number
@@ -674,15 +682,23 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
s := string(item)
switch v.Kind() {
default:
+ if v.Kind() == reflect.String && v.Type() == numberType {
+ v.SetString(s)
+ break
+ }
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()})
}
case reflect.Interface:
- n, err := strconv.ParseFloat(s, 64)
+ n, err := d.convertNumber(s)
if err != nil {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+ d.saveError(err)
+ break
+ }
+ if v.NumMethod() != 0 {
+ d.saveError(&UnmarshalTypeError{"number", v.Type()})
break
}
v.Set(reflect.ValueOf(n))
@@ -735,7 +751,7 @@ func (d *decodeState) valueInterface() interface{} {
// arrayInterface is like array but returns []interface{}.
func (d *decodeState) arrayInterface() []interface{} {
- var v []interface{}
+ var v = make([]interface{}, 0)
for {
// Look ahead for ] - can only happen on first iteration.
op := d.scanWhile(scanSkipSpace)
@@ -836,9 +852,9 @@ func (d *decodeState) literalInterface() interface{} {
if c != '-' && (c < '0' || c > '9') {
d.error(errPhase)
}
- n, err := strconv.ParseFloat(string(item), 64)
+ n, err := d.convertNumber(string(item))
if err != nil {
- d.saveError(&UnmarshalTypeError{"number " + string(item), reflect.TypeOf(0.0)})
+ d.saveError(err)
}
return n
}
@@ -979,11 +995,3 @@ func unquoteBytes(s []byte) (t []byte, ok bool) {
}
return b[0:w], true
}
-
-// The following is issue 3069.
-
-// BUG(rsc): This package ignores anonymous (embedded) struct fields
-// during encoding and decoding. A future version may assign meaning
-// to them. To force an anonymous field to be ignored in all future
-// versions of this package, use an explicit `json:"-"` tag in the struct
-// definition.
diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go
index 6fac22c4a..e1bd918dd 100644
--- a/src/pkg/encoding/json/decode_test.go
+++ b/src/pkg/encoding/json/decode_test.go
@@ -7,9 +7,11 @@ package json
import (
"bytes"
"fmt"
+ "image"
"reflect"
"strings"
"testing"
+ "time"
)
type T struct {
@@ -18,6 +20,32 @@ type T struct {
Z int `json:"-"`
}
+type U struct {
+ Alphabet string `json:"alpha"`
+}
+
+type V struct {
+ F1 interface{}
+ F2 int32
+ F3 Number
+}
+
+// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshalling with and
+// without UseNumber
+var ifaceNumAsFloat64 = map[string]interface{}{
+ "k1": float64(1),
+ "k2": "s",
+ "k3": []interface{}{float64(1), float64(2.0), float64(3e-3)},
+ "k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)},
+}
+
+var ifaceNumAsNumber = map[string]interface{}{
+ "k1": Number("1"),
+ "k2": "s",
+ "k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")},
+ "k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")},
+}
+
type tx struct {
x int
}
@@ -48,55 +76,297 @@ var (
umstruct = ustruct{unmarshaler{true}}
)
+// Test data structures for anonymous fields.
+
+type Point struct {
+ Z int
+}
+
+type Top struct {
+ Level0 int
+ Embed0
+ *Embed0a
+ *Embed0b `json:"e,omitempty"` // treated as named
+ Embed0c `json:"-"` // ignored
+ Loop
+ Embed0p // has Point with X, Y, used
+ Embed0q // has Point with Z, used
+}
+
+type Embed0 struct {
+ Level1a int // overridden by Embed0a's Level1a with json tag
+ Level1b int // used because Embed0a's Level1b is renamed
+ Level1c int // used because Embed0a's Level1c is ignored
+ Level1d int // annihilated by Embed0a's Level1d
+ Level1e int `json:"x"` // annihilated by Embed0a.Level1e
+}
+
+type Embed0a struct {
+ Level1a int `json:"Level1a,omitempty"`
+ Level1b int `json:"LEVEL1B,omitempty"`
+ Level1c int `json:"-"`
+ Level1d int // annihilated by Embed0's Level1d
+ Level1f int `json:"x"` // annihilated by Embed0's Level1e
+}
+
+type Embed0b Embed0
+
+type Embed0c Embed0
+
+type Embed0p struct {
+ image.Point
+}
+
+type Embed0q struct {
+ Point
+}
+
+type Loop struct {
+ Loop1 int `json:",omitempty"`
+ Loop2 int `json:",omitempty"`
+ *Loop
+}
+
+// From reflect test:
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+ S6
+ S7
+ S8
+}
+
+type S6 struct {
+ X int
+}
+
+type S7 S6
+
+type S8 struct {
+ S9
+}
+
+type S9 struct {
+ X int
+ Y int
+}
+
+// From reflect test:
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+ S11
+ S12
+ S13
+}
+
+type S11 struct {
+ S6
+}
+
+type S12 struct {
+ S6
+}
+
+type S13 struct {
+ S8
+}
+
type unmarshalTest struct {
- in string
- ptr interface{}
- out interface{}
- err error
+ in string
+ ptr interface{}
+ out interface{}
+ err error
+ useNumber bool
+}
+
+type Ambig struct {
+ // Given "hello", the first match should win.
+ First int `json:"HELLO"`
+ Second int `json:"Hello"`
}
var unmarshalTests = []unmarshalTest{
// basic types
- {`true`, new(bool), true, nil},
- {`1`, new(int), 1, nil},
- {`1.2`, new(float64), 1.2, nil},
- {`-5`, new(int16), int16(-5), nil},
- {`"a\u1234"`, new(string), "a\u1234", nil},
- {`"http:\/\/"`, new(string), "http://", nil},
- {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
- {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
- {"null", new(interface{}), nil, nil},
- {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
- {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
+ {in: `true`, ptr: new(bool), out: true},
+ {in: `1`, ptr: new(int), out: 1},
+ {in: `1.2`, ptr: new(float64), out: 1.2},
+ {in: `-5`, ptr: new(int16), out: int16(-5)},
+ {in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},
+ {in: `2`, ptr: new(Number), out: Number("2")},
+ {in: `2`, ptr: new(interface{}), out: float64(2.0)},
+ {in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true},
+ {in: `"a\u1234"`, ptr: new(string), out: "a\u1234"},
+ {in: `"http:\/\/"`, ptr: new(string), out: "http://"},
+ {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}`, 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},
+ {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},
+ {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true},
+
+ // raw values with whitespace
+ {in: "\n true ", ptr: new(bool), out: true},
+ {in: "\t 1 ", ptr: new(int), out: 1},
+ {in: "\r 1.2 ", ptr: new(float64), out: 1.2},
+ {in: "\t -5 \n", ptr: new(int16), out: int16(-5)},
+ {in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"},
// Z has a "-" tag.
- {`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil},
+ {in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}},
+
+ {in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}},
+ {in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}},
+ {in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}},
// syntax errors
- {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
- {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
+ {in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}},
+ {in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
+ {in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
+
+ // raw value errors
+ {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}},
+ {in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}},
+ {in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}},
+ {in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
+ {in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}},
// array tests
- {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
- {`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
- {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
+ {in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}},
+ {in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},
+ {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
+
+ // empty array to interface test
+ {in: `[]`, ptr: new([]interface{}), out: []interface{}{}},
+ {in: `null`, ptr: new([]interface{}), out: []interface{}(nil)},
+ {in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}},
+ {in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}},
// composite tests
- {allValueIndent, new(All), allValue, nil},
- {allValueCompact, new(All), allValue, nil},
- {allValueIndent, new(*All), &allValue, nil},
- {allValueCompact, new(*All), &allValue, nil},
- {pallValueIndent, new(All), pallValue, nil},
- {pallValueCompact, new(All), pallValue, nil},
- {pallValueIndent, new(*All), &pallValue, nil},
- {pallValueCompact, new(*All), &pallValue, nil},
+ {in: allValueIndent, ptr: new(All), out: allValue},
+ {in: allValueCompact, ptr: new(All), out: allValue},
+ {in: allValueIndent, ptr: new(*All), out: &allValue},
+ {in: allValueCompact, ptr: new(*All), out: &allValue},
+ {in: pallValueIndent, ptr: new(All), out: pallValue},
+ {in: pallValueCompact, ptr: new(All), out: pallValue},
+ {in: pallValueIndent, ptr: new(*All), out: &pallValue},
+ {in: pallValueCompact, ptr: new(*All), out: &pallValue},
// unmarshal interface test
- {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
- {`{"T":false}`, &ump, &umtrue, nil},
- {`[{"T":false}]`, &umslice, umslice, nil},
- {`[{"T":false}]`, &umslicep, &umslice, nil},
- {`{"M":{"T":false}}`, &umstruct, umstruct, nil},
+ {in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called
+ {in: `{"T":false}`, ptr: &ump, out: &umtrue},
+ {in: `[{"T":false}]`, ptr: &umslice, out: umslice},
+ {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice},
+ {in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct},
+
+ {
+ in: `{
+ "Level0": 1,
+ "Level1b": 2,
+ "Level1c": 3,
+ "x": 4,
+ "Level1a": 5,
+ "LEVEL1B": 6,
+ "e": {
+ "Level1a": 8,
+ "Level1b": 9,
+ "Level1c": 10,
+ "Level1d": 11,
+ "x": 12
+ },
+ "Loop1": 13,
+ "Loop2": 14,
+ "X": 15,
+ "Y": 16,
+ "Z": 17
+ }`,
+ ptr: new(Top),
+ out: Top{
+ Level0: 1,
+ Embed0: Embed0{
+ Level1b: 2,
+ Level1c: 3,
+ },
+ Embed0a: &Embed0a{
+ Level1a: 5,
+ Level1b: 6,
+ },
+ Embed0b: &Embed0b{
+ Level1a: 8,
+ Level1b: 9,
+ Level1c: 10,
+ Level1d: 11,
+ Level1e: 12,
+ },
+ Loop: Loop{
+ Loop1: 13,
+ Loop2: 14,
+ },
+ Embed0p: Embed0p{
+ Point: image.Point{X: 15, Y: 16},
+ },
+ Embed0q: Embed0q{
+ Point: Point{Z: 17},
+ },
+ },
+ },
+ {
+ in: `{"hello": 1}`,
+ ptr: new(Ambig),
+ out: Ambig{First: 1},
+ },
+
+ {
+ in: `{"X": 1,"Y":2}`,
+ ptr: new(S5),
+ out: S5{S8: S8{S9: S9{Y: 2}}},
+ },
+ {
+ in: `{"X": 1,"Y":2}`,
+ ptr: new(S10),
+ out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
+ },
+
+ // invalid UTF-8 is coerced to valid UTF-8.
+ {
+ in: "\"hello\xffworld\"",
+ ptr: new(string),
+ out: "hello\ufffdworld",
+ },
+ {
+ in: "\"hello\xc2\xc2world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\xc2\xffworld\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffdworld",
+ },
+ {
+ in: "\"hello\\ud800\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\\ud800\\ud800world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffdworld",
+ },
+ {
+ in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"",
+ ptr: new(string),
+ out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
+ },
}
func TestMarshal(t *testing.T) {
@@ -135,6 +405,18 @@ func TestMarshalBadUTF8(t *testing.T) {
}
}
+func TestMarshalNumberZeroVal(t *testing.T) {
+ var n Number
+ out, err := Marshal(n)
+ if err != nil {
+ t.Fatal(err)
+ }
+ outStr := string(out)
+ if outStr != "0" {
+ t.Fatalf("Invalid zero val for Number: %q", outStr)
+ }
+}
+
func TestUnmarshal(t *testing.T) {
for i, tt := range unmarshalTests {
var scan scanner
@@ -150,7 +432,11 @@ func TestUnmarshal(t *testing.T) {
}
// v = new(right-type)
v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
- if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
+ dec := NewDecoder(bytes.NewBuffer(in))
+ if tt.useNumber {
+ dec.UseNumber()
+ }
+ if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) {
t.Errorf("#%d: %v want %v", i, err, tt.err)
continue
}
@@ -162,6 +448,28 @@ func TestUnmarshal(t *testing.T) {
println(string(data))
continue
}
+
+ // Check round trip.
+ if tt.err == nil {
+ enc, err := Marshal(v.Interface())
+ if err != nil {
+ t.Errorf("#%d: error re-marshaling: %v", i, err)
+ continue
+ }
+ vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
+ dec = NewDecoder(bytes.NewBuffer(enc))
+ if tt.useNumber {
+ dec.UseNumber()
+ }
+ if err := dec.Decode(vv.Interface()); err != nil {
+ t.Errorf("#%d: error re-unmarshaling: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
+ t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface())
+ continue
+ }
+ }
}
}
@@ -175,13 +483,45 @@ func TestUnmarshalMarshal(t *testing.T) {
if err != nil {
t.Fatalf("Marshal: %v", err)
}
- if bytes.Compare(jsonBig, b) != 0 {
+ if !bytes.Equal(jsonBig, b) {
t.Errorf("Marshal jsonBig")
diff(t, b, jsonBig)
return
}
}
+var numberTests = []struct {
+ in string
+ i int64
+ intErr string
+ f float64
+ floatErr string
+}{
+ {in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
+ {in: "-12", i: -12, f: -12.0},
+ {in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
+}
+
+// Independent of Decode, basic coverage of the accessors in Number
+func TestNumberAccessors(t *testing.T) {
+ for _, tt := range numberTests {
+ n := Number(tt.in)
+ if s := n.String(); s != tt.in {
+ t.Errorf("Number(%q).String() is %q", tt.in, s)
+ }
+ if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
+ t.Errorf("Number(%q).Int64() is %d", tt.in, i)
+ } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
+ t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err)
+ }
+ if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
+ t.Errorf("Number(%q).Float64() is %g", tt.in, f)
+ } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
+ t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err)
+ }
+ }
+}
+
func TestLargeByteSlice(t *testing.T) {
s0 := make([]byte, 2000)
for i := range s0 {
@@ -195,7 +535,7 @@ func TestLargeByteSlice(t *testing.T) {
if err := Unmarshal(b, &s1); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
- if bytes.Compare(s0, s1) != 0 {
+ if !bytes.Equal(s0, s1) {
t.Errorf("Marshal large byte slice")
diff(t, s0, s1)
}
@@ -610,35 +950,6 @@ func TestRefUnmarshal(t *testing.T) {
}
}
-// Test that anonymous fields are ignored.
-// We may assign meaning to them later.
-func TestAnonymous(t *testing.T) {
- type S struct {
- T
- N int
- }
-
- data, err := Marshal(new(S))
- if err != nil {
- t.Fatalf("Marshal: %v", err)
- }
- want := `{"N":0}`
- if string(data) != want {
- t.Fatalf("Marshal = %#q, want %#q", string(data), want)
- }
-
- var s S
- if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil {
- t.Fatalf("Unmarshal: %v", err)
- }
- if s.N != 2 {
- t.Fatal("Unmarshal: did not set N")
- }
- if s.T.Y != 0 {
- t.Fatal("Unmarshal: did set T.Y")
- }
-}
-
// Test that the empty string doesn't panic decoding when ,string is specified
// Issue 3450
func TestEmptyString(t *testing.T) {
@@ -703,3 +1014,167 @@ func TestInterfaceSet(t *testing.T) {
}
}
}
+
+// JSON null values should be ignored for primitives and string values instead of resulting in an error.
+// Issue 2540
+func TestUnmarshalNulls(t *testing.T) {
+ jsonData := []byte(`{
+ "Bool" : null,
+ "Int" : null,
+ "Int8" : null,
+ "Int16" : null,
+ "Int32" : null,
+ "Int64" : null,
+ "Uint" : null,
+ "Uint8" : null,
+ "Uint16" : null,
+ "Uint32" : null,
+ "Uint64" : null,
+ "Float32" : null,
+ "Float64" : null,
+ "String" : null}`)
+
+ nulls := All{
+ Bool: true,
+ Int: 2,
+ Int8: 3,
+ Int16: 4,
+ Int32: 5,
+ Int64: 6,
+ Uint: 7,
+ Uint8: 8,
+ Uint16: 9,
+ Uint32: 10,
+ Uint64: 11,
+ Float32: 12.1,
+ Float64: 13.1,
+ String: "14"}
+
+ err := Unmarshal(jsonData, &nulls)
+ if err != nil {
+ t.Errorf("Unmarshal of null values failed: %v", err)
+ }
+ if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
+ nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
+ nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
+
+ t.Errorf("Unmarshal of null values affected primitives")
+ }
+}
+
+func TestStringKind(t *testing.T) {
+ type stringKind string
+ type aMap map[stringKind]int
+
+ var m1, m2 map[stringKind]int
+ m1 = map[stringKind]int{
+ "foo": 42,
+ }
+
+ data, err := Marshal(m1)
+ if err != nil {
+ t.Errorf("Unexpected error marshalling: %v", err)
+ }
+
+ err = Unmarshal(data, &m2)
+ if err != nil {
+ t.Errorf("Unexpected error unmarshalling: %v", err)
+ }
+
+ if !reflect.DeepEqual(m1, m2) {
+ t.Error("Items should be equal after encoding and then decoding")
+ }
+
+}
+
+var decodeTypeErrorTests = []struct {
+ dest interface{}
+ src string
+}{
+ {new(string), `{"user": "name"}`}, // issue 4628.
+ {new(error), `{}`}, // issue 4222
+ {new(error), `[]`},
+ {new(error), `""`},
+ {new(error), `123`},
+ {new(error), `true`},
+}
+
+func TestUnmarshalTypeError(t *testing.T) {
+ for _, item := range decodeTypeErrorTests {
+ err := Unmarshal([]byte(item.src), item.dest)
+ if _, ok := err.(*UnmarshalTypeError); !ok {
+ t.Errorf("expected type error for Unmarshal(%q, type %T): got %T",
+ item.src, item.dest, err)
+ }
+ }
+}
+
+var unmarshalSyntaxTests = []string{
+ "tru",
+ "fals",
+ "nul",
+ "123e",
+ `"hello`,
+ `[1,2,3`,
+ `{"key":1`,
+ `{"key":1,`,
+}
+
+func TestUnmarshalSyntax(t *testing.T) {
+ var x interface{}
+ for _, src := range unmarshalSyntaxTests {
+ err := Unmarshal([]byte(src), &x)
+ if _, ok := err.(*SyntaxError); !ok {
+ t.Errorf("expected syntax error for Unmarshal(%q): got %T", src, err)
+ }
+ }
+}
+
+// Test handling of unexported fields that should be ignored.
+// Issue 4660
+type unexportedFields struct {
+ Name string
+ m map[string]interface{} `json:"-"`
+ m2 map[string]interface{} `json:"abcd"`
+}
+
+func TestUnmarshalUnexported(t *testing.T) {
+ input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}`
+ want := &unexportedFields{Name: "Bob"}
+
+ out := &unexportedFields{}
+ err := Unmarshal([]byte(input), out)
+ if err != nil {
+ t.Errorf("got error %v, expected nil", err)
+ }
+ if !reflect.DeepEqual(out, want) {
+ t.Errorf("got %q, want %q", out, want)
+ }
+}
+
+// Time3339 is a time.Time which encodes to and from JSON
+// as an RFC 3339 time in UTC.
+type Time3339 time.Time
+
+func (t *Time3339) UnmarshalJSON(b []byte) error {
+ if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
+ return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b)
+ }
+ tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
+ if err != nil {
+ return err
+ }
+ *t = Time3339(tm)
+ return nil
+}
+
+func TestUnmarshalJSONLiteralError(t *testing.T) {
+ var t3 Time3339
+ err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3)
+ if err == nil {
+ t.Fatalf("expected error; got time %v", time.Time(t3))
+ }
+ if !strings.Contains(err.Error(), "range") {
+ t.Errorf("got err = %v; want out of range error", err)
+ }
+}
diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index b6e1cb16e..fb57f1d51 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -36,7 +36,7 @@ import (
//
// Boolean values encode as JSON booleans.
//
-// Floating point and integer values encode as JSON numbers.
+// Floating point, integer, and Number values encode as JSON numbers.
//
// String values encode as JSON strings, with each invalid UTF-8 sequence
// replaced by the encoding of the Unicode replacement character U+FFFD.
@@ -55,7 +55,7 @@ import (
// nil pointer or interface value, and any array, slice, map, or string of
// length zero. The object's default key string is the struct field name
// but can be specified in the struct field's tag value. The "json" key in
-// struct field's tag value is the key name, followed by an optional comma
+// the struct field's tag value is the key name, followed by an optional comma
// and options. Examples:
//
// // Field is ignored by this package.
@@ -75,8 +75,9 @@ import (
// Field int `json:",omitempty"`
//
// The "string" option signals that a field is stored as JSON inside a
-// JSON-encoded string. This extra level of encoding is sometimes
-// used when communicating with JavaScript programs:
+// JSON-encoded string. It applies only to fields of string, floating point,
+// or integer types. This extra level of encoding is sometimes used when
+// communicating with JavaScript programs:
//
// Int64String int64 `json:",string"`
//
@@ -84,6 +85,16 @@ import (
// only Unicode letters, digits, dollar signs, percent signs, hyphens,
// underscores and slashes.
//
+// Anonymous struct fields are usually marshaled as if their inner exported fields
+// were fields in the outer struct, subject to the usual Go visibility rules.
+// An anonymous struct field with a name given in its JSON tag is treated as
+// having that name instead of as anonymous.
+//
+// Handling of anonymous struct fields is new in Go 1.1.
+// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
+// an anonymous struct field in both current and earlier versions, give the field
+// a JSON tag of "-".
+//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
// as map keys.
@@ -312,6 +323,14 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
e.Write(b)
}
case reflect.String:
+ if v.Type() == numberType {
+ numStr := v.String()
+ if numStr == "" {
+ numStr = "0" // Number's zero-val
+ }
+ e.WriteString(numStr)
+ break
+ }
if quoted {
sb, err := Marshal(v.String())
if err != nil {
@@ -325,9 +344,9 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
case reflect.Struct:
e.WriteByte('{')
first := true
- for _, ef := range encodeFields(v.Type()) {
- fieldValue := v.Field(ef.i)
- if ef.omitEmpty && isEmptyValue(fieldValue) {
+ for _, f := range cachedTypeFields(v.Type()) {
+ fv := fieldByIndex(v, f.index)
+ if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) {
continue
}
if first {
@@ -335,9 +354,9 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
} else {
e.WriteByte(',')
}
- e.string(ef.tag)
+ e.string(f.name)
e.WriteByte(':')
- e.reflectValueQuoted(fieldValue, ef.quoted)
+ e.reflectValueQuoted(fv, f.quoted)
}
e.WriteByte('}')
@@ -419,7 +438,7 @@ func isValidTag(s string) bool {
}
for _, c := range s {
switch {
- case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~", c):
+ case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
// Backslash and quote chars are reserved, but
// otherwise any punctuation chars are allowed
// in a tag name.
@@ -432,6 +451,19 @@ func isValidTag(s string) bool {
return true
}
+func fieldByIndex(v reflect.Value, index []int) reflect.Value {
+ for _, i := range index {
+ if v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ return reflect.Value{}
+ }
+ v = v.Elem()
+ }
+ v = v.Field(i)
+ }
+ return v
+}
+
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type stringValues []reflect.Value
@@ -490,67 +522,185 @@ func (e *encodeState) string(s string) (int, error) {
return e.Len() - len0, nil
}
-// encodeField contains information about how to encode a field of a
-// struct.
-type encodeField struct {
- i int // field index in struct
- tag string
- quoted bool
+// A field represents a single field found in a struct.
+type field struct {
+ name string
+ tag bool
+ index []int
+ typ reflect.Type
omitEmpty bool
+ quoted bool
}
-var (
- typeCacheLock sync.RWMutex
- encodeFieldsCache = make(map[reflect.Type][]encodeField)
-)
+// byName sorts field by name, breaking ties with depth,
+// then breaking ties with "name came from json tag", then
+// breaking ties with index sequence.
+type byName []field
-// encodeFields returns a slice of encodeField for a given
-// struct type.
-func encodeFields(t reflect.Type) []encodeField {
- typeCacheLock.RLock()
- fs, ok := encodeFieldsCache[t]
- typeCacheLock.RUnlock()
- if ok {
- return fs
- }
+func (x byName) Len() int { return len(x) }
+
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
- typeCacheLock.Lock()
- defer typeCacheLock.Unlock()
- fs, ok = encodeFieldsCache[t]
- if ok {
- return fs
+func (x byName) Less(i, j int) bool {
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
}
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+}
- v := reflect.Zero(t)
- n := v.NumField()
- for i := 0; i < n; i++ {
- f := t.Field(i)
- if f.PkgPath != "" {
- continue
+// byIndex sorts field by index sequence.
+type byIndex []field
+
+func (x byIndex) Len() int { return len(x) }
+
+func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byIndex) Less(i, j int) bool {
+ for k, xik := range x[i].index {
+ if k >= len(x[j].index) {
+ return false
}
- if f.Anonymous {
- // We want to do a better job with these later,
- // so for now pretend they don't exist.
- continue
+ if xik != x[j].index[k] {
+ return xik < x[j].index[k]
}
- var ef encodeField
- ef.i = i
- ef.tag = f.Name
+ }
+ return len(x[i].index) < len(x[j].index)
+}
+
+// typeFields returns a list of fields that JSON should recognize for the given type.
+// The algorithm is breadth-first search over the set of structs to include - the top struct
+// and then any reachable anonymous structs.
+func typeFields(t reflect.Type) []field {
+ // Anonymous fields to explore at the current level and the next.
+ current := []field{}
+ next := []field{{typ: t}}
+
+ // Count of queued names for current level and the next.
+ count := map[reflect.Type]int{}
+ nextCount := map[reflect.Type]int{}
+
+ // Types already visited at an earlier level.
+ visited := map[reflect.Type]bool{}
+
+ // Fields found.
+ var fields []field
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, map[reflect.Type]int{}
- tv := f.Tag.Get("json")
- if tv != "" {
- if tv == "-" {
+ for _, f := range current {
+ if visited[f.typ] {
continue
}
- name, opts := parseTag(tv)
- if isValidTag(name) {
- ef.tag = name
+ visited[f.typ] = true
+
+ // Scan f.typ for fields to include.
+ for i := 0; i < f.typ.NumField(); i++ {
+ sf := f.typ.Field(i)
+ if sf.PkgPath != "" { // unexported
+ continue
+ }
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ continue
+ }
+ name, opts := parseTag(tag)
+ if !isValidTag(name) {
+ name = ""
+ }
+ index := make([]int, len(f.index)+1)
+ copy(index, f.index)
+ index[len(f.index)] = i
+
+ ft := sf.Type
+ if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+ // Follow pointer.
+ ft = ft.Elem()
+ }
+
+ // Record found field and index sequence.
+ if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
+ tagged := name != ""
+ if name == "" {
+ name = sf.Name
+ }
+ fields = append(fields, field{name, tagged, index, ft,
+ opts.Contains("omitempty"), opts.Contains("string")})
+ if count[f.typ] > 1 {
+ // If there were multiple instances, add a second,
+ // so that the annihilation code will see a duplicate.
+ // It only cares about the distinction between 1 or 2,
+ // so don't bother generating any more copies.
+ fields = append(fields, fields[len(fields)-1])
+ }
+ continue
+ }
+
+ // Record new anonymous struct to explore in next round.
+ nextCount[ft]++
+ if nextCount[ft] == 1 {
+ next = append(next, field{name: ft.Name(), index: index, typ: ft})
+ }
}
- ef.omitEmpty = opts.Contains("omitempty")
- ef.quoted = opts.Contains("string")
}
- fs = append(fs, ef)
}
- encodeFieldsCache[t] = fs
- return fs
+
+ sort.Sort(byName(fields))
+
+ // Remove fields with annihilating name collisions
+ // and also fields shadowed by fields with explicit JSON tags.
+ name := ""
+ out := fields[:0]
+ for _, f := range fields {
+ if f.name != name {
+ name = f.name
+ out = append(out, f)
+ continue
+ }
+ if n := len(out); n > 0 && out[n-1].name == name && (!out[n-1].tag || f.tag) {
+ out = out[:n-1]
+ }
+ }
+ fields = out
+
+ sort.Sort(byIndex(fields))
+
+ return fields
+}
+
+var fieldCache struct {
+ sync.RWMutex
+ m map[reflect.Type][]field
+}
+
+// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
+func cachedTypeFields(t reflect.Type) []field {
+ fieldCache.RLock()
+ f := fieldCache.m[t]
+ fieldCache.RUnlock()
+ if f != nil {
+ return f
+ }
+
+ // Compute fields without lock.
+ // Might duplicate effort but won't hold other computations back.
+ f = typeFields(t)
+ if f == nil {
+ f = []field{}
+ }
+
+ fieldCache.Lock()
+ if fieldCache.m == nil {
+ fieldCache.m = map[reflect.Type][]field{}
+ }
+ fieldCache.m[t] = f
+ fieldCache.Unlock()
+ return f
}
diff --git a/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go
index cb1c77eb5..be74c997c 100644
--- a/src/pkg/encoding/json/encode_test.go
+++ b/src/pkg/encoding/json/encode_test.go
@@ -186,3 +186,23 @@ func TestMarshalerEscaping(t *testing.T) {
t.Errorf("got %q, want %q", got, want)
}
}
+
+type IntType int
+
+type MyStruct struct {
+ IntType
+}
+
+func TestAnonymousNonstruct(t *testing.T) {
+ var i IntType = 11
+ a := MyStruct{i}
+ const want = `{"IntType":11}`
+
+ b, err := Marshal(a)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ if got := string(b); got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+}
diff --git a/src/pkg/encoding/json/scanner_test.go b/src/pkg/encoding/json/scanner_test.go
index 14d850865..77d3455d3 100644
--- a/src/pkg/encoding/json/scanner_test.go
+++ b/src/pkg/encoding/json/scanner_test.go
@@ -92,7 +92,7 @@ func TestCompactBig(t *testing.T) {
t.Fatalf("Compact: %v", err)
}
b := buf.Bytes()
- if bytes.Compare(b, jsonBig) != 0 {
+ if !bytes.Equal(b, jsonBig) {
t.Error("Compact(jsonBig) != jsonBig")
diff(t, b, jsonBig)
return
@@ -118,7 +118,7 @@ func TestIndentBig(t *testing.T) {
t.Fatalf("Indent2: %v", err)
}
b1 := buf1.Bytes()
- if bytes.Compare(b1, b) != 0 {
+ if !bytes.Equal(b1, b) {
t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
diff(t, b1, b)
return
@@ -130,7 +130,7 @@ func TestIndentBig(t *testing.T) {
t.Fatalf("Compact: %v", err)
}
b1 = buf1.Bytes()
- if bytes.Compare(b1, jsonBig) != 0 {
+ if !bytes.Equal(b1, jsonBig) {
t.Error("Compact(Indent(jsonBig)) != jsonBig")
diff(t, b1, jsonBig)
return
@@ -277,9 +277,6 @@ func genArray(n int) []interface{} {
if f > n {
f = n
}
- if n > 0 && f == 0 {
- f = 1
- }
x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
diff --git a/src/pkg/encoding/json/stream.go b/src/pkg/encoding/json/stream.go
index 7d1cc5f11..00f4726cf 100644
--- a/src/pkg/encoding/json/stream.go
+++ b/src/pkg/encoding/json/stream.go
@@ -5,6 +5,7 @@
package json
import (
+ "bytes"
"errors"
"io"
)
@@ -26,6 +27,10 @@ func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r: r}
}
+// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
+// Number instead of as a float64.
+func (dec *Decoder) UseNumber() { dec.d.useNumber = true }
+
// Decode reads the next JSON-encoded value from its
// input and stores it in the value pointed to by v.
//
@@ -54,6 +59,12 @@ func (dec *Decoder) Decode(v interface{}) error {
return err
}
+// Buffered returns a reader of the data remaining in the Decoder's
+// buffer. The reader is valid until the next call to Decode.
+func (dec *Decoder) Buffered() io.Reader {
+ return bytes.NewReader(dec.buf)
+}
+
// readValue reads a JSON value into dec.buf.
// It returns the length of the encoding.
func (dec *Decoder) readValue() (int, error) {
@@ -74,7 +85,7 @@ Input:
// scanEnd is delayed one byte.
// We might block trying to get that byte from src,
// so instead invent a space byte.
- if v == scanEndObject && dec.scan.step(&dec.scan, ' ') == scanEnd {
+ if (v == scanEndObject || v == scanEndArray) && dec.scan.step(&dec.scan, ' ') == scanEnd {
scanp += i + 1
break Input
}
diff --git a/src/pkg/encoding/json/stream_test.go b/src/pkg/encoding/json/stream_test.go
index ce5a7e6d6..07c9e1d39 100644
--- a/src/pkg/encoding/json/stream_test.go
+++ b/src/pkg/encoding/json/stream_test.go
@@ -6,7 +6,10 @@ package json
import (
"bytes"
+ "io/ioutil"
+ "net"
"reflect"
+ "strings"
"testing"
)
@@ -82,6 +85,28 @@ func TestDecoder(t *testing.T) {
}
}
+func TestDecoderBuffered(t *testing.T) {
+ r := strings.NewReader(`{"Name": "Gopher"} extra `)
+ var m struct {
+ Name string
+ }
+ d := NewDecoder(r)
+ err := d.Decode(&m)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if m.Name != "Gopher" {
+ t.Errorf("Name = %q; want Gopher", m.Name)
+ }
+ rest, err := ioutil.ReadAll(d.Buffered())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if g, w := string(rest), " extra "; g != w {
+ t.Errorf("Remaining = %q; want %q", g, w)
+ }
+}
+
func nlines(s string, n int) string {
if n <= 0 {
return ""
@@ -145,3 +170,24 @@ func TestNullRawMessage(t *testing.T) {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
+
+var blockingTests = []string{
+ `{"x": 1}`,
+ `[1, 2, 3]`,
+}
+
+func TestBlocking(t *testing.T) {
+ for _, enc := range blockingTests {
+ r, w := net.Pipe()
+ go w.Write([]byte(enc))
+ var val interface{}
+
+ // If Decode reads beyond what w.Write writes above,
+ // it will block, and the test will deadlock.
+ if err := NewDecoder(r).Decode(&val); err != nil {
+ t.Errorf("decoding %s: %v", enc, err)
+ }
+ r.Close()
+ w.Close()
+ }
+}
diff --git a/src/pkg/encoding/json/tagkey_test.go b/src/pkg/encoding/json/tagkey_test.go
index da8b12bd8..23e71c752 100644
--- a/src/pkg/encoding/json/tagkey_test.go
+++ b/src/pkg/encoding/json/tagkey_test.go
@@ -60,6 +60,14 @@ type badCodeTag struct {
Z string `json:" !\"#&'()*+,."`
}
+type spaceTag struct {
+ Q string `json:"With space"`
+}
+
+type unicodeTag struct {
+ W string `json:"Ελλάδα"`
+}
+
var structTagObjectKeyTests = []struct {
raw interface{}
value string
@@ -78,6 +86,8 @@ var structTagObjectKeyTests = []struct {
{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
{percentSlashTag{"brut"}, "brut", "text/html%"},
{punctuationTag{"Union Rags"}, "Union Rags", "!#$%&()*+-./:<=>?@[]^_{|}~"},
+ {spaceTag{"Perreddu"}, "Perreddu", "With space"},
+ {unicodeTag{"Loukanikos"}, "Loukanikos", "Ελλάδα"},
}
func TestStructTagObjectKey(t *testing.T) {