1
0
mirror of https://github.com/golang/go synced 2024-11-19 21:14:43 -07:00

encoding/json: call (*T).MarshalJSON for addressable T values.

Fixes #2170.

R=golang-dev, cw, adg
CC=golang-dev
https://golang.org/cl/5618045
This commit is contained in:
David Symonds 2012-02-03 11:15:06 +11:00
parent 102638cb53
commit bf89d58e73
3 changed files with 74 additions and 2 deletions

View File

@ -598,3 +598,24 @@ var pallValueIndent = `{
}` }`
var pallValueCompact = strings.Map(noSpace, 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)
}
}

View File

@ -262,8 +262,18 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
return return
} }
if j, ok := v.Interface().(Marshaler); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) { m, ok := v.Interface().(Marshaler)
b, err := j.MarshalJSON() 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 { if err == nil {
// copy JSON into buffer, checking validity. // copy JSON into buffer, checking validity.
err = Compact(&e.Buffer, b) err = Compact(&e.Buffer, b)

View 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)
}
}