Skip to content

Commit 95bb00d

Browse files
caarlos0odeke-em
authored andcommitted
encoding/json: implement Is on all errors
Allows users to check: errors.Is(err, &UnmarshalTypeError{}) errors.Is(err, &UnmarshalFieldError{}) errors.Is(err, &InvalidUnmarshalError{}) errors.Is(err, &UnsupportedValueError{}) errors.Is(err, &MarshalerError{}) which is the recommended way of checking for kinds of errors. SyntaxError.Is was implemented in CL 253037. As and Unwrap relevant methods will be added in future CLs. Change-Id: I1f8a503b8fdc0f3afdfe9669a91f3af8d960e028 GitHub-Last-Rev: 930cda5 GitHub-Pull-Request: #41360 Reviewed-on: https://go-review.googlesource.com/c/go/+/254537 Run-TryBot: Emmanuel Odeke <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]> Trust: Emmanuel Odeke <[email protected]>
1 parent b3ef90e commit 95bb00d

File tree

4 files changed

+84
-1
lines changed

4 files changed

+84
-1
lines changed

src/encoding/json/decode.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ func (e *UnmarshalTypeError) Error() string {
136136
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
137137
}
138138

139+
// Is returns true if target is a UnmarshalTypeError.
140+
func (e *UnmarshalTypeError) Is(target error) bool {
141+
_, ok := target.(*UnmarshalTypeError)
142+
return ok
143+
}
144+
139145
// An UnmarshalFieldError describes a JSON object key that
140146
// led to an unexported (and therefore unwritable) struct field.
141147
//
@@ -150,12 +156,24 @@ func (e *UnmarshalFieldError) Error() string {
150156
return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
151157
}
152158

159+
// Is returns true if target is a UnmarshalFieldError.
160+
func (e *UnmarshalFieldError) Is(target error) bool {
161+
_, ok := target.(*UnmarshalFieldError)
162+
return ok
163+
}
164+
153165
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
154166
// (The argument to Unmarshal must be a non-nil pointer.)
155167
type InvalidUnmarshalError struct {
156168
Type reflect.Type
157169
}
158170

171+
// Is returns true if target is a InvalidUnmarshalError.
172+
func (e *InvalidUnmarshalError) Is(target error) bool {
173+
_, ok := target.(*InvalidUnmarshalError)
174+
return ok
175+
}
176+
159177
func (e *InvalidUnmarshalError) Error() string {
160178
if e.Type == nil {
161179
return "json: Unmarshal(nil)"

src/encoding/json/decode_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,3 +2572,34 @@ func TestUnmarshalMaxDepth(t *testing.T) {
25722572
}
25732573
}
25742574
}
2575+
2576+
func TestInvalidUnmarshalErrorIs(t *testing.T) {
2577+
err := fmt.Errorf("apackage: %w: failed to parse struct", &InvalidUnmarshalError{reflect.TypeOf("a")})
2578+
if !errors.Is(err, &InvalidUnmarshalError{}) {
2579+
t.Fatalf("%v should be unwrapped to a InvalidUnmarshalError", err)
2580+
}
2581+
}
2582+
2583+
func TestUnmarshalFieldErrorIs(t *testing.T) {
2584+
err := fmt.Errorf("apackage: %w: failed to parse struct", &UnmarshalFieldError{
2585+
Key: "foo",
2586+
Type: reflect.TypeOf("a"),
2587+
Field: reflect.StructField{Name: "b"},
2588+
})
2589+
if !errors.Is(err, &UnmarshalFieldError{}) {
2590+
t.Fatalf("%v should be unwrapped to a UnmarshalFieldError", err)
2591+
}
2592+
}
2593+
2594+
func TestUnmarshalTypeErrorIs(t *testing.T) {
2595+
err := fmt.Errorf("apackage: %w: failed to parse struct", &UnmarshalTypeError{
2596+
Value: "foo",
2597+
Type: reflect.TypeOf("a"),
2598+
Offset: 1,
2599+
Struct: "Foo",
2600+
Field: "Bar",
2601+
})
2602+
if !errors.Is(err, &UnmarshalTypeError{}) {
2603+
t.Fatalf("%v should be unwrapped to a UnmarshalTypeError", err)
2604+
}
2605+
}

src/encoding/json/encode.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,12 @@ func (e *UnsupportedValueError) Error() string {
245245
return "json: unsupported value: " + e.Str
246246
}
247247

248+
// Is returns true if target is a UnsupportedValueError.
249+
func (e *UnsupportedValueError) Is(target error) bool {
250+
_, ok := target.(*UnsupportedValueError)
251+
return ok
252+
}
253+
248254
// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when
249255
// attempting to encode a string value with invalid UTF-8 sequences.
250256
// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by
@@ -279,6 +285,12 @@ func (e *MarshalerError) Error() string {
279285
// Unwrap returns the underlying error.
280286
func (e *MarshalerError) Unwrap() error { return e.Err }
281287

288+
// Is returns true if target is a MarshalerError.
289+
func (e *MarshalerError) Is(target error) bool {
290+
_, ok := target.(*MarshalerError)
291+
return ok
292+
}
293+
282294
var hex = "0123456789abcdef"
283295

284296
// An encodeState encodes JSON into a bytes.Buffer.

src/encoding/json/encode_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package json
77
import (
88
"bytes"
99
"encoding"
10+
"errors"
1011
"fmt"
1112
"log"
1213
"math"
@@ -211,7 +212,7 @@ var unsupportedValues = []interface{}{
211212
func TestUnsupportedValues(t *testing.T) {
212213
for _, v := range unsupportedValues {
213214
if _, err := Marshal(v); err != nil {
214-
if _, ok := err.(*UnsupportedValueError); !ok {
215+
if !errors.Is(err, &UnsupportedValueError{}) {
215216
t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
216217
}
217218
} else {
@@ -1155,3 +1156,24 @@ func TestMarshalerError(t *testing.T) {
11551156
}
11561157
}
11571158
}
1159+
1160+
func TestMarshalerErrorIs(t *testing.T) {
1161+
err := fmt.Errorf("apackage: %w: failed to parse struct", &MarshalerError{
1162+
reflect.TypeOf("a"),
1163+
fmt.Errorf("something"),
1164+
"TestMarshalerErrorIs",
1165+
})
1166+
if !errors.Is(err, &MarshalerError{}) {
1167+
t.Fatalf("%v should be unwrapped to a MarshalerError", err)
1168+
}
1169+
}
1170+
1171+
func TestUnsupportedValueErrorIs(t *testing.T) {
1172+
err := fmt.Errorf("apackage: %w: failed to parse struct", &UnsupportedValueError{
1173+
Value: reflect.Value{},
1174+
Str: "Foo",
1175+
})
1176+
if !errors.Is(err, &UnsupportedValueError{}) {
1177+
t.Fatalf("%v should be unwrapped to a UnsupportedValueError", err)
1178+
}
1179+
}

0 commit comments

Comments
 (0)