From 27f4166e372084e1d78119183d14b76391c803cb Mon Sep 17 00:00:00 2001 From: Andrew Gerrand Date: Thu, 29 Aug 2013 14:45:59 +1000 Subject: [PATCH] undo CL 13180043 / 318540e7857f MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accidentally submitted. ««« original CL description encoding/json: add "overflow" struct tag option Fixes #6213. R=golang-dev, dsymonds, bradfitz CC=golang-dev https://golang.org/cl/13180043 »»» R=golang-dev CC=golang-dev https://golang.org/cl/13234045 --- src/pkg/encoding/json/decode.go | 102 +++++++++++--------------- src/pkg/encoding/json/decode_test.go | 20 ----- src/pkg/encoding/json/encode.go | 65 ++-------------- src/pkg/encoding/json/encode_test.go | 56 -------------- src/pkg/encoding/json/example_test.go | 46 ------------ 5 files changed, 49 insertions(+), 240 deletions(-) diff --git a/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go index c3167674428..b6c23cc77a1 100644 --- a/src/pkg/encoding/json/decode.go +++ b/src/pkg/encoding/json/decode.go @@ -61,10 +61,6 @@ import ( // Instead, they are replaced by the Unicode replacement // character U+FFFD. // -// When unmarshalling into struct values, a struct field of map type with the -// "overflow" option will store values whose keys do not match the other struct -// fields. -// func Unmarshal(data []byte, v interface{}) error { // Check for well-formedness. // Avoids filling out half a data structure @@ -493,6 +489,8 @@ func (d *decodeState) object(v reflect.Value) { return } + var mapElem reflect.Value + for { // Read opening " of string key or closing }. op := d.scanWhile(scanSkipSpace) @@ -514,7 +512,44 @@ func (d *decodeState) object(v reflect.Value) { } // Figure out field corresponding to key. - subv, mapv, destring := subValue(v, key) + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := v.Type().Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + fields := cachedTypeFields(v.Type()) + for i := range fields { + ff := &fields[i] + if ff.name == key { + f = ff + break + } + if f == nil && strings.EqualFold(ff.name, key) { + f = ff + } + } + 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) + } + } + } // Read : before value. if op == scanSkipSpace { @@ -534,9 +569,9 @@ func (d *decodeState) object(v reflect.Value) { // Write value back to map; // if using struct, subv points into struct already. - if mapv.IsValid() { - kv := reflect.ValueOf(key).Convert(mapv.Type().Key()) - mapv.SetMapIndex(kv, subv) + if v.Kind() == reflect.Map { + kv := reflect.ValueOf(key).Convert(v.Type().Key()) + v.SetMapIndex(kv, subv) } // Next token must be , or }. @@ -550,57 +585,6 @@ func (d *decodeState) object(v reflect.Value) { } } -// subValue returns (and allocates, if necessary) the field in the struct or -// map v whose name matches key. -func subValue(v reflect.Value, key string) (subv, mapv reflect.Value, destring bool) { - // Create new map element. - if v.Kind() == reflect.Map { - subv = reflect.New(v.Type().Elem()).Elem() - mapv = v - return - } - - // Get struct field. - var f *field - fields := cachedTypeFields(v.Type()) - for i := range fields { - ff := &fields[i] - if ff.name == key { - f = ff - break - } - if f == nil && strings.EqualFold(ff.name, key) { - f = ff - } - } - if f != nil { - subv = fieldByIndex(v, f.index, true) - destring = f.quoted - return - } - - // Decode into overflow field if present. - for _, f := range fields { - if f.overflow { - // Find overflow field. - mapv = fieldByIndex(v, f.index, true) - if k := mapv.Kind(); k != reflect.Map { - panic("unsupported overflow field kind: " + k.String()) - } - // Make map if necessary. - if mapv.IsNil() { - mapv.Set(reflect.MakeMap(mapv.Type())) - } - // Create new map element. - subv = reflect.New(mapv.Type().Elem()).Elem() - return - } - } - - // Not found. - return -} - // literal consumes a literal from d.data[d.off-1:], decoding into the value v. // The first byte of the literal has been read already // (that's how the caller knows it's a literal). diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go index 4531e99656a..6635ba6ec68 100644 --- a/src/pkg/encoding/json/decode_test.go +++ b/src/pkg/encoding/json/decode_test.go @@ -1275,23 +1275,3 @@ func TestSkipArrayObjects(t *testing.T) { t.Errorf("got error %q, want nil", err) } } - -func TestDecodeOverflow(t *testing.T) { - json := `{"A":1,"B":2,"C":3}` - type S struct { - A int - E map[string]interface{} `json:",overflow"` - C int - } - var ( - want = S{1, map[string]interface{}{"B": float64(2)}, 3} - dest S - ) - err := Unmarshal([]byte(json), &dest) - if err != nil { - t.Errorf("got error %q, want nil", err) - } - if !reflect.DeepEqual(dest, want) { - t.Errorf("Got %+v; want %+v", dest, want) - } -} diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go index 590010f3b24..f951250e980 100644 --- a/src/pkg/encoding/json/encode.go +++ b/src/pkg/encoding/json/encode.go @@ -109,10 +109,6 @@ import ( // an anonymous struct field in both current and earlier versions, give the field // a JSON tag of "-". // -// The "overflow" option may be used with a struct field of a map type to -// indicate that the map contents should be marshalled as if the keys are part -// of the struct object itself. -// // Map values encode as JSON objects. // The map's key type must be string; the object keys are used directly // as map keys. @@ -243,32 +239,6 @@ var hex = "0123456789abcdef" type encodeState struct { bytes.Buffer // accumulated output scratch [64]byte - overflow int -} - -func (e *encodeState) startOverflow() { - e.overflow = e.Len() -} - -func (e *encodeState) endOverflow() { - if e.overflow == 0 { - panic("endOverflow called before startOverflow") - } - start, end := e.overflow, e.Len() - b := e.Bytes() - if b[start] == '{' && b[end-1] == '}' { - // Remove surrounding { and }. - copy(b[start:], b[start+1:]) - e.Truncate(end - 2) - } else if bytes.Equal(b[start:end], []byte("null")) { - // Drop "null". - e.Truncate(start) - } - // Remove trailing comma if overflow value was null or {}. - if start > 0 && e.Len() == start && b[start-1] == ',' { - e.Truncate(start - 1) - } - e.overflow = 0 } // TODO(bradfitz): use a sync.Cache here @@ -612,7 +582,7 @@ func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { e.WriteByte('{') first := true for i, f := range se.fields { - fv := fieldByIndex(v, f.index, false) + fv := fieldByIndex(v, f.index) if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) { continue } @@ -621,16 +591,6 @@ func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { } else { e.WriteByte(',') } - if f.overflow { - if tenc := se.fieldEncs[i]; tenc != nil { - e.startOverflow() - tenc(e, fv, f.quoted) - e.endOverflow() - } else { - panic("no encoder for " + fv.String()) - } - continue - } e.string(f.name) e.WriteByte(':') if tenc := se.fieldEncs[i]; tenc != nil { @@ -650,7 +610,7 @@ func newStructEncoder(t reflect.Type, vx reflect.Value) encoderFunc { fieldEncs: make([]encoderFunc, len(fields)), } for i, f := range fields { - vxf := fieldByIndex(vx, f.index, false) + vxf := fieldByIndex(vx, f.index) if vxf.IsValid() { se.fieldEncs[i] = typeEncoder(vxf.Type(), vxf) } @@ -790,16 +750,11 @@ func isValidTag(s string) bool { return true } -// fieldByIndex fetches (and allocates, if create is true) the field in v -// indentified by index. -func fieldByIndex(v reflect.Value, index []int, create bool) reflect.Value { +func fieldByIndex(v reflect.Value, index []int) reflect.Value { for _, i := range index { if v.Kind() == reflect.Ptr { if v.IsNil() { - if !create { - return reflect.Value{} - } - v.Set(reflect.New(v.Type().Elem())) + return reflect.Value{} } v = v.Elem() } @@ -971,7 +926,6 @@ type field struct { typ reflect.Type omitEmpty bool quoted bool - overflow bool } // byName sorts field by name, breaking ties with depth, @@ -1073,15 +1027,8 @@ func typeFields(t reflect.Type) []field { if name == "" { name = sf.Name } - fields = append(fields, field{ - name: name, - tag: tagged, - index: index, - typ: ft, - omitEmpty: opts.Contains("omitempty"), - quoted: opts.Contains("string"), - overflow: opts.Contains("overflow")}, - ) + 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. diff --git a/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go index f1bb144a0e7..7052e1db7c9 100644 --- a/src/pkg/encoding/json/encode_test.go +++ b/src/pkg/encoding/json/encode_test.go @@ -401,59 +401,3 @@ func TestStringBytes(t *testing.T) { t.Errorf("encodings differ at %#q vs %#q", enc, encBytes) } } - -func TestEncodeOverflow(t *testing.T) { - for _, c := range []struct { - in interface{} - want string - }{ - { - struct { - A int - E map[string]interface{} `json:",overflow"` - C int - }{ - A: 12, - E: map[string]interface{}{"B": 42}, - C: 64, - }, - `{"A":12,"B":42,"C":64}`, - }, - { - struct { - E map[string]interface{} `json:",overflow"` - }{ - E: map[string]interface{}{"B": 42}, - }, - `{"B":42}`, - }, - { - struct { - A int - E map[string]interface{} `json:",overflow"` - }{ - A: 12, - }, - `{"A":12}`, - }, - { - struct { - A int - E map[string]interface{} `json:",overflow"` - }{ - A: 12, - E: map[string]interface{}{}, - }, - `{"A":12}`, - }, - } { - b, err := Marshal(c.in) - if err != nil { - t.Error(err) - continue - } - if got := string(b); got != c.want { - t.Errorf("Marshal(%q) = %s, want %s", c.in, got, c.want) - } - } -} diff --git a/src/pkg/encoding/json/example_test.go b/src/pkg/encoding/json/example_test.go index 1f84e151e55..b8d150eda50 100644 --- a/src/pkg/encoding/json/example_test.go +++ b/src/pkg/encoding/json/example_test.go @@ -33,29 +33,6 @@ func ExampleMarshal() { // {"ID":1,"Name":"Reds","Colors":["Crimson","Red","Ruby","Maroon"]} } -func ExampleMarshal_overflow() { - type Record struct { - ID string - Seq int - Meta map[string]string `json:",overflow"` - } - r := Record{ - ID: "CheeseWhiz", - Seq: 42, - Meta: map[string]string{ - "Created": "1980-06-20", - "Destroyed": "1998-02-06", - }, - } - b, err := json.Marshal(r) - if err != nil { - fmt.Println("error:", err) - } - os.Stdout.Write(b) - // Output: - // {"ID":"CheeseWhiz","Seq":42,"Created":"1980-06-20","Destroyed":"1998-02-06"} -} - func ExampleUnmarshal() { var jsonBlob = []byte(`[ {"Name": "Platypus", "Order": "Monotremata"}, @@ -75,29 +52,6 @@ func ExampleUnmarshal() { // [{Name:Platypus Order:Monotremata} {Name:Quoll Order:Dasyuromorphia}] } -func ExampleUnmarshal_overflow() { - var jsonBlob = []byte(` - { - "Token": "Kaip4uM1ieng6Eiw", - "User": "bimmler", - "Animal": "rabbit" - } - `) - type Auth struct { - Token string - User string - Extra map[string]string `json:",overflow"` - } - var auth Auth - err := json.Unmarshal(jsonBlob, &auth) - if err != nil { - fmt.Println("error:", err) - } - fmt.Printf("%+v", auth) - // Output: - // {Token:Kaip4uM1ieng6Eiw User:bimmler Extra:map[Animal:rabbit]} -} - // This example uses a Decoder to decode a stream of distinct JSON values. func ExampleDecoder() { const jsonStream = `