diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index b4fba476c82362..a7473a7eba5d9f 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -261,14 +261,22 @@ func (e *InvalidUTF8Error) Error() string { // A MarshalerError represents an error from calling a MarshalJSON or MarshalText method. type MarshalerError struct { - Type reflect.Type - Err error + Type reflect.Type + Err error + sourceFunc string } func (e *MarshalerError) Error() string { - return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Err.Error() + srcFunc := e.sourceFunc + if srcFunc == "" { + srcFunc = "MarshalJSON" + } + return "json: error calling " + srcFunc + + " for type " + e.Type.String() + + ": " + e.Err.Error() } +// Unwrap returns the underlying error. func (e *MarshalerError) Unwrap() error { return e.Err } var hex = "0123456789abcdef" @@ -455,7 +463,7 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { err = compact(&e.Buffer, b, opts.escapeHTML) } if err != nil { - e.error(&MarshalerError{v.Type(), err}) + e.error(&MarshalerError{v.Type(), err, "MarshalJSON"}) } } @@ -472,7 +480,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { err = compact(&e.Buffer, b, opts.escapeHTML) } if err != nil { - e.error(&MarshalerError{v.Type(), err}) + e.error(&MarshalerError{v.Type(), err, "MarshalJSON"}) } } @@ -488,7 +496,7 @@ func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { } b, err := m.MarshalText() if err != nil { - e.error(&MarshalerError{v.Type(), err}) + e.error(&MarshalerError{v.Type(), err, "MarshalText"}) } e.stringBytes(b, opts.escapeHTML) } @@ -502,7 +510,7 @@ func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { m := va.Interface().(encoding.TextMarshaler) b, err := m.MarshalText() if err != nil { - e.error(&MarshalerError{v.Type(), err}) + e.error(&MarshalerError{v.Type(), err, "MarshalText"}) } e.stringBytes(b, opts.escapeHTML) } @@ -761,7 +769,7 @@ func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { for i, v := range keys { sv[i].v = v if err := sv[i].resolve(); err != nil { - e.error(&MarshalerError{v.Type(), err}) + e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error())) } } sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s }) diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go index 8d3503b1ba23ea..40f16d86ff8752 100644 --- a/src/encoding/json/encode_test.go +++ b/src/encoding/json/encode_test.go @@ -1064,3 +1064,30 @@ func TestMarshalUncommonFieldNames(t *testing.T) { t.Fatalf("Marshal: got %s want %s", got, want) } } + +func TestMarshalerError(t *testing.T) { + s := "test variable" + st := reflect.TypeOf(s) + errText := "json: test error" + + tests := []struct { + err *MarshalerError + want string + }{ + { + &MarshalerError{st, fmt.Errorf(errText), ""}, + "json: error calling MarshalJSON for type " + st.String() + ": " + errText, + }, + { + &MarshalerError{st, fmt.Errorf(errText), "TestMarshalerError"}, + "json: error calling TestMarshalerError for type " + st.String() + ": " + errText, + }, + } + + for i, tt := range tests { + got := tt.err.Error() + if got != tt.want { + t.Errorf("MarshalerError test %d, got: %s, want: %s", i, got, tt.want) + } + } +}