diff options
author | Kyle Erf <erf@mongodb.com> | 2015-08-04 15:54:54 -0400 |
---|---|---|
committer | Kyle Erf <erf@mongodb.com> | 2015-08-18 15:25:22 -0400 |
commit | 61bfea23b0bc95c0859d893f80b3b48ed82567f4 (patch) | |
tree | eb8bfb815055d36be9db7f2e72acce05aeb1b586 | |
parent | 720440f7d66a49c89fd7adda5ce7c9560272359f (diff) | |
download | mongo-61bfea23b0bc95c0859d893f80b3b48ed82567f4.tar.gz |
TOOLS-767 fix decoding 'null' JSON into bson.D
-rw-r--r-- | common/json/decode.go | 49 | ||||
-rw-r--r-- | common/json/decode_d_test.go | 33 |
2 files changed, 42 insertions, 40 deletions
diff --git a/common/json/decode.go b/common/json/decode.go index 941c9df2265..850b17a5059 100644 --- a/common/json/decode.go +++ b/common/json/decode.go @@ -599,14 +599,18 @@ func (d *decodeState) object(v reflect.Value) { if v.IsNil() { v.Set(reflect.MakeMap(t)) } + + case reflect.Struct: + // do nothing + case reflect.Slice: // this is only a valid case if the output type is a bson.D t := v.Type() - if t != orderedBSONType { - d.saveError(&UnmarshalTypeError{"object", v.Type()}) - break + if t == orderedBSONType { + v.Set(reflect.ValueOf(d.bsonDInterface())) + return } - case reflect.Struct: + fallthrough // can't unmarshal into a regular slice, goto "default" error case default: d.saveError(&UnmarshalTypeError{"object", v.Type()}) @@ -617,8 +621,6 @@ func (d *decodeState) object(v reflect.Value) { var mapElem reflect.Value - i := 0 - bsonDMode := false for { // Read opening " of string key or closing }. op := d.scanWhile(scanSkipSpace) @@ -651,14 +653,6 @@ func (d *decodeState) object(v reflect.Value) { mapElem.Set(reflect.Zero(elemType)) } subv = mapElem - } else if v.Kind() == reflect.Slice { - bsonDMode = true - elemType := interfaceType.Elem() - if !mapElem.IsValid() { - subv = reflect.New(elemType).Elem() - } else { - mapElem.Set(reflect.Zero(elemType)) - } } else { var f *field fields := cachedTypeFields(v.Type()) @@ -695,18 +689,12 @@ func (d *decodeState) object(v reflect.Value) { d.error(errPhase) } // Read value. - var docElemValue interface{} if destring { d.value(reflect.ValueOf(&d.tempstr)) d.literalStore([]byte(d.tempstr), subv, true) d.tempstr = "" // Zero scratch space for successive values. } else { - if bsonDMode { - docElemValue = d.valueInterface() - subv.Set(reflect.ValueOf(docElemValue)) - } else { - d.value(subv) - } + d.value(subv) } // Write value back to map; @@ -714,24 +702,6 @@ func (d *decodeState) object(v reflect.Value) { if v.Kind() == reflect.Map { kv := reflect.ValueOf(key).Convert(v.Type().Key()) v.SetMapIndex(kv, subv) - } else if v.Kind() == reflect.Slice { - kv := reflect.ValueOf(key).Convert(stringType) - newDocElem := &bson.DocElem{kv.String(), subv.Interface()} - // Slice construction/resizing code is from decodeState.array() - if i >= v.Cap() { - newcap := v.Cap() + v.Cap()/2 - if newcap < 4 { - newcap = 4 - } - newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) - reflect.Copy(newv, v) - v.Set(newv) - } - if i >= v.Len() { - v.SetLen(i + 1) - } - v3 := v.Index(i) - v3.Set(reflect.ValueOf(newDocElem).Elem()) } // Next token must be , or }. @@ -742,7 +712,6 @@ func (d *decodeState) object(v reflect.Value) { if op != scanObjectValue { d.error(errPhase) } - i++ } } diff --git a/common/json/decode_d_test.go b/common/json/decode_d_test.go index 63e4bd89d65..76223ddecd1 100644 --- a/common/json/decode_d_test.go +++ b/common/json/decode_d_test.go @@ -23,6 +23,24 @@ func TestDecodeBsonD(t *testing.T) { }) + Convey("A nested bson.D should be parsed", func() { + data := `{"a": 17, "b":{"foo":"bar", "baz":"boo"}, c:"wow" }` + out := struct { + A int `json:"a"` + B bson.D `json:"b"` + C string `json:"c"` + }{} + err := Unmarshal([]byte(data), &out) + So(err, ShouldBeNil) + So(out.A, ShouldEqual, 17) + So(out.C, ShouldEqual, "wow") + So(len(out.B), ShouldEqual, 2) + So(out.B[0].Name, ShouldEqual, "foo") + So(out.B[0].Value, ShouldEqual, "bar") + So(out.B[1].Name, ShouldEqual, "baz") + So(out.B[1].Value, ShouldEqual, "boo") + }) + Convey("Objects nested within DocElems should still be parsed", func() { data := `{"a":["x", "y","z"], "b":{"foo":"bar", "baz":"boo"}}` out := bson.D{} @@ -34,6 +52,21 @@ func TestDecodeBsonD(t *testing.T) { So(out[0].Value, ShouldResemble, []interface{}{"x", "y", "z"}) So(out[1].Value, ShouldResemble, map[string]interface{}{"foo": "bar", "baz": "boo"}) }) + + Convey("null should be a valid value", func() { + data := `{"a":true, "b":null, "c": 5}` + out := bson.D{} + err := Unmarshal([]byte(data), &out) + So(err, ShouldBeNil) + So(len(out), ShouldEqual, 3) + So(out[0].Name, ShouldEqual, "a") + So(out[0].Value, ShouldEqual, true) + So(out[1].Name, ShouldEqual, "b") + So(out[1].Value, ShouldBeNil) + So(out[2].Name, ShouldEqual, "c") + So(out[2].Value, ShouldEqual, 5) + }) + }) Convey("Unmarshalling to a non-bson.D slice types should fail", t, func() { data := `{"a":["x", "y","z"], "b":{"foo":"bar", "baz":"boo"}}` |