]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json: call (*T).MarshalJSON for addressable T values.
authorDavid Symonds <dsymonds@golang.org>
Fri, 3 Feb 2012 00:15:06 +0000 (11:15 +1100)
committerDavid Symonds <dsymonds@golang.org>
Fri, 3 Feb 2012 00:15:06 +0000 (11:15 +1100)
Fixes #2170.

R=golang-dev, cw, adg
CC=golang-dev
https://golang.org/cl/5618045

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

index cc3103f032fb26c1c23cdfac08cbd7ca3c026eeb..775becfa7c9be2699e127a088f1cc3f5feeaefa6 100644 (file)
@@ -598,3 +598,24 @@ var pallValueIndent = `{
 }`
 
 var pallValueCompact = strings.Map(noSpace, pallValueIndent)
+
+func TestRefUnmarshal(t *testing.T) {
+       type S struct {
+               // Ref is defined in encode_test.go.
+               R0 Ref
+               R1 *Ref
+       }
+       want := S{
+               R0: 12,
+               R1: new(Ref),
+       }
+       *want.R1 = 12
+
+       var got S
+       if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref"}`), &got); err != nil {
+               t.Fatalf("Unmarshal: %v", err)
+       }
+       if !reflect.DeepEqual(got, want) {
+               t.Errorf("got %+v, want %+v", got, want)
+       }
+}
index eac14a47ed7ac1722dfaf595c5ca0ecec0577892..83e73c09cb41c8d3bb80b5dae92e5c29a6487cb4 100644 (file)
@@ -262,8 +262,18 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
                return
        }
 
-       if j, ok := v.Interface().(Marshaler); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
-               b, err := j.MarshalJSON()
+       m, ok := v.Interface().(Marshaler)
+       if !ok {
+               // T doesn't match the interface. Check against *T too.
+               if v.Kind() != reflect.Ptr && v.CanAddr() {
+                       m, ok = v.Addr().Interface().(Marshaler)
+                       if ok {
+                               v = v.Addr()
+                       }
+               }
+       }
+       if ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
+               b, err := m.MarshalJSON()
                if err == nil {
                        // copy JSON into buffer, checking validity.
                        err = Compact(&e.Buffer, b)
index 0e39559a463405ccbe164cd24794737dc2f37481..7a726a91c47bb47816e42e761de3944ebb4ca8ea 100644 (file)
@@ -126,3 +126,44 @@ func TestUnsupportedValues(t *testing.T) {
                }
        }
 }
+
+// Ref has Marshaler and Unmarshaler methods with pointer receiver.
+type Ref int
+
+func (*Ref) MarshalJSON() ([]byte, error) {
+       return []byte(`"ref"`), nil
+}
+
+func (r *Ref) UnmarshalJSON([]byte) error {
+       *r = 12
+       return nil
+}
+
+// Val has Marshaler methods with value receiver.
+type Val int
+
+func (Val) MarshalJSON() ([]byte, error) {
+       return []byte(`"val"`), nil
+}
+
+func TestRefValMarshal(t *testing.T) {
+       var s = struct {
+               R0 Ref
+               R1 *Ref
+               V0 Val
+               V1 *Val
+       }{
+               R0: 12,
+               R1: new(Ref),
+               V0: 13,
+               V1: new(Val),
+       }
+       const want = `{"R0":"ref","R1":"ref","V0":"val","V1":"val"}`
+       b, err := Marshal(&s)
+       if err != nil {
+               t.Fatalf("Marshal: %v", err)
+       }
+       if got := string(b); got != want {
+               t.Errorf("got %q, want %q", got, want)
+       }
+}