// 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
return
}
+ var mapElem reflect.Value
+
for {
// Read opening " of string key or closing }.
op := d.scanWhile(scanSkipSpace)
}
// 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 {
// 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 }.
}
}
-// 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).
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)
- }
-}
// 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.
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
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
}
} 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 {
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)
}
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()
}
typ reflect.Type
omitEmpty bool
quoted bool
- overflow bool
}
// byName sorts field by name, breaking ties with depth,
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.
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)
- }
- }
-}
// {"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"},
// [{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 = `