diff --git a/decode_test.go b/decode_test.go index 8f32cedb..f0bbb1c4 100644 --- a/decode_test.go +++ b/decode_test.go @@ -3698,6 +3698,73 @@ func TestDecodeContextOption(t *testing.T) { }) } +type onlyContextUnmarshaler struct { + called bool + data string +} + +func (u *onlyContextUnmarshaler) UnmarshalJSON(_ context.Context, b []byte) error { + u.called = true + u.data = string(b) + return nil +} + +type onlyStdUnmarshaler struct { + called bool + data string +} + +func (u *onlyStdUnmarshaler) UnmarshalJSON(b []byte) error { + u.called = true + u.data = string(b) + return nil +} + +func TestUnmarshalerContextDispatch(t *testing.T) { + data := []byte(`{"name":"John"}`) + + t.Run("context unmarshaler via Unmarshal", func(t *testing.T) { + var v onlyContextUnmarshaler + if err := json.Unmarshal(data, &v); err != nil { + t.Fatal(err) + } + if !v.called { + t.Fatal("UnmarshalJSON(context.Context, []byte) was not called") + } + }) + t.Run("context unmarshaler via UnmarshalContext", func(t *testing.T) { + var v onlyContextUnmarshaler + if err := json.UnmarshalContext(context.Background(), data, &v); err != nil { + t.Fatal(err) + } + if !v.called { + t.Fatal("UnmarshalJSON(context.Context, []byte) was not called") + } + }) + t.Run("std unmarshaler via UnmarshalContext", func(t *testing.T) { + var v onlyStdUnmarshaler + if err := json.UnmarshalContext(context.Background(), data, &v); err != nil { + t.Fatal(err) + } + if !v.called { + t.Fatal("UnmarshalJSON([]byte) was not called") + } + }) + t.Run("std unmarshaler via Unmarshal matches encoding/json", func(t *testing.T) { + var v onlyStdUnmarshaler + if err := json.Unmarshal(data, &v); err != nil { + t.Fatal(err) + } + var std onlyStdUnmarshaler + if err := stdjson.Unmarshal(data, &std); err != nil { + t.Fatal(err) + } + if v.data != std.data { + t.Fatalf("go-json passed %q to UnmarshalJSON, encoding/json passed %q", v.data, std.data) + } + }) +} + func TestIssue251(t *testing.T) { array := [3]int{1, 2, 3} err := stdjson.Unmarshal([]byte("[ ]"), &array) diff --git a/internal/decoder/unmarshal_json.go b/internal/decoder/unmarshal_json.go index 4cd6dbd5..caa1b691 100644 --- a/internal/decoder/unmarshal_json.go +++ b/internal/decoder/unmarshal_json.go @@ -85,13 +85,20 @@ func (d *unmarshalJSONDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, typ: d.typ, ptr: p, })) - if (ctx.Option.Flags & ContextOption) != 0 { - if err := v.(unmarshalerContext).UnmarshalJSON(ctx.Option.Context, dst); err != nil { + switch v := v.(type) { + case unmarshalerContext: + var c context.Context + if (ctx.Option.Flags & ContextOption) != 0 { + c = ctx.Option.Context + } else { + c = context.Background() + } + if err := v.UnmarshalJSON(c, dst); err != nil { d.annotateError(cursor, err) return 0, err } - } else { - if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil { + case json.Unmarshaler: + if err := v.UnmarshalJSON(dst); err != nil { d.annotateError(cursor, err) return 0, err }