From add721ef91ed533cf578ff7a604124e377329ae4 Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Mon, 24 Oct 2016 21:20:04 -0700 Subject: [PATCH] encoding/json: encode nil Marshaler as "null" Fixes #16042. Change-Id: I0a28aa004246b7b0ffaaab457e077ad9035363c2 Reviewed-on: https://go-review.googlesource.com/31932 Reviewed-by: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Gobot Gobot --- src/encoding/json/encode.go | 6 ++++- src/encoding/json/encode_test.go | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 667df31ce3..98a9899502 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -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. diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go index b2c9e91dde..ebcf07cf38 100644 --- a/src/encoding/json/encode_test.go +++ b/src/encoding/json/encode_test.go @@ -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{ -- 2.48.1