]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: encode nil Marshaler as "null"
authorEmmanuel Odeke <emm.odeke@gmail.com>
Tue, 25 Oct 2016 04:20:04 +0000 (21:20 -0700)
committerRuss Cox <rsc@golang.org>
Fri, 11 Nov 2016 14:50:51 +0000 (14:50 +0000)
Fixes #16042.

Change-Id: I0a28aa004246b7b0ffaaab457e077ad9035363c2
Reviewed-on: https://go-review.googlesource.com/31932
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/encoding/json/encode.go
src/encoding/json/encode_test.go

index 667df31ce3f9cdd896e189b69bd4bfbd342e61e9..98a98995024fa4944407b6831b8e173992c54fec 100644 (file)
@@ -443,7 +443,11 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
                e.WriteString("null")
                return
        }
-       m := v.Interface().(Marshaler)
+       m, ok := v.Interface().(Marshaler)
+       if !ok {
+               e.WriteString("null")
+               return
+       }
        b, err := m.MarshalJSON()
        if err == nil {
                // copy JSON into buffer, checking validity.
index b2c9e91dde7ff5239d23f885e9768d9c57ab8fb7..ebcf07cf382e2501e1d726b63ed898b034c9d33c 100644 (file)
@@ -293,6 +293,44 @@ type BugX struct {
        BugB
 }
 
+// Issue 16042. Even if a nil interface value is passed in
+// as long as it implements MarshalJSON, it should be marshaled.
+type nilMarshaler string
+
+func (nm *nilMarshaler) MarshalJSON() ([]byte, error) {
+       if nm == nil {
+               return Marshal("0zenil0")
+       }
+       return Marshal("zenil:" + string(*nm))
+}
+
+// Issue 16042.
+func TestNilMarshal(t *testing.T) {
+       testCases := []struct {
+               v    interface{}
+               want string
+       }{
+               {v: nil, want: `null`},
+               {v: new(float64), want: `0`},
+               {v: []interface{}(nil), want: `null`},
+               {v: []string(nil), want: `null`},
+               {v: map[string]string(nil), want: `null`},
+               {v: []byte(nil), want: `null`},
+               {v: struct{ M string }{"gopher"}, want: `{"M":"gopher"}`},
+               {v: struct{ M Marshaler }{}, want: `{"M":null}`},
+               {v: struct{ M Marshaler }{(*nilMarshaler)(nil)}, want: `{"M":"0zenil0"}`},
+               {v: struct{ M interface{} }{(*nilMarshaler)(nil)}, want: `{"M":null}`},
+       }
+
+       for _, tt := range testCases {
+               out, err := Marshal(tt.v)
+               if err != nil || string(out) != tt.want {
+                       t.Errorf("Marshal(%#v) = %#q, %#v, want %#q, nil", tt.v, out, err, tt.want)
+                       continue
+               }
+       }
+}
+
 // Issue 5245.
 func TestEmbeddedBug(t *testing.T) {
        v := BugB{