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:
parent
102638cb53
commit
bf89d58e73
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user