]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/json/v2: remove `unknown` tag option and DiscardUnknownMembers master
authorJoe Tsai <joetsai@digital-static.net>
Tue, 3 Feb 2026 01:52:37 +0000 (17:52 -0800)
committerJoseph Tsai <joetsai@digital-static.net>
Fri, 13 Feb 2026 00:09:06 +0000 (16:09 -0800)
WARNING: This commit contains breaking changes
for those already using GOEXPERIMENT=jsonv2.

This removes support for the `unknown` tag option and
the DiscardUnknownMembers marshal option.

The `unknown` tag option semantics are a bit too subtle
even for experienced Go programmers to understand.
Remove support for it. The exact same feature (or something similar)
can be added back into a future release of json/v2.

We already support the `inline` tag option,
which can handle most cases of what someone might want to do
with unknown fields (such as preserve them).

Fixes #77271
Updates #76444

Change-Id: I875952f0755e58aac4c571869b2cdb56e75cfda9
Reviewed-on: https://go-review.googlesource.com/c/go/+/741320
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/encoding/json/internal/jsonflags/flags.go
src/encoding/json/v2/arshal_default.go
src/encoding/json/v2/arshal_test.go
src/encoding/json/v2/doc.go
src/encoding/json/v2/example_test.go
src/encoding/json/v2/fields.go
src/encoding/json/v2/fields_test.go
src/encoding/json/v2/options.go

index a53dfe7985601d6869ef53c105a5efe291c0e024..3a581a08df2891df7cbd9128edc7f854ae6616ac 100644 (file)
@@ -120,7 +120,6 @@ const (
        FormatNilSliceAsNull      // marshal only
        OmitZeroStructFields      // marshal only
        MatchCaseInsensitiveNames // marshal or unmarshal
-       DiscardUnknownMembers     // marshal only
        RejectUnknownMembers      // unmarshal only
        Marshalers                // marshal only; non-boolean flag
        Unmarshalers              // unmarshal only; non-boolean flag
@@ -151,7 +150,7 @@ const (
 )
 
 // bitsUsed is the number of bits used in the 64-bit boolean flags
-const bitsUsed = 42
+const bitsUsed = 41
 
 // Static compile check that bitsUsed and maxArshalV1Flag are in sync.
 const _ = uint64((1<<bitsUsed)-maxArshalV1Flag) + uint64(maxArshalV1Flag-(1<<bitsUsed))
index 33931af17e642343485004d273aebc5d3a1e52bb..6af5a37260453df077ced5e43311fc37af9f924d 100644 (file)
@@ -1198,7 +1198,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
                        }
                        prevIdx = f.id
                }
-               if fields.inlinedFallback != nil && !(mo.Flags.Get(jsonflags.DiscardUnknownMembers) && fields.inlinedFallback.unknown) {
+               if fields.inlinedFallback != nil {
                        var insertUnquotedName func([]byte) bool
                        if !mo.Flags.Get(jsonflags.AllowDuplicateNames) {
                                insertUnquotedName = func(name []byte) bool {
@@ -1270,7 +1270,7 @@ func makeStructArshaler(t reflect.Type) *arshaler {
                                                }
                                        }
                                        if f == nil {
-                                               if uo.Flags.Get(jsonflags.RejectUnknownMembers) && (fields.inlinedFallback == nil || fields.inlinedFallback.unknown) {
+                                               if uo.Flags.Get(jsonflags.RejectUnknownMembers) && fields.inlinedFallback == nil {
                                                        err := newUnmarshalErrorAfter(dec, t, ErrUnknownName)
                                                        if !uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
                                                                return err
index dc15c5a5f531b53b468dedb992d75f1a01769aaa..1a7ed4b886f91ecd0d199be9cce4939097730f91 100644 (file)
@@ -416,14 +416,9 @@ type (
                X            *structInlinedL2 `json:",inline"`
                StructEmbed1 `json:",inline"`
        }
-       structInlinedL2        struct{ A, B, C string }
-       StructEmbed1           struct{ C, D, E string }
-       StructEmbed2           struct{ E, F, G string }
-       structUnknownTextValue struct {
-               A int            `json:",omitzero"`
-               X jsontext.Value `json:",unknown"`
-               B int            `json:",omitzero"`
-       }
+       structInlinedL2       struct{ A, B, C string }
+       StructEmbed1          struct{ C, D, E string }
+       StructEmbed2          struct{ E, F, G string }
        structInlineTextValue struct {
                A int            `json:",omitzero"`
                X jsontext.Value `json:",inline"`
@@ -2744,33 +2739,6 @@ func TestMarshal(t *testing.T) {
                },
                in:   structInlineMapNamedStringAny{X: map[namedString]any{"fizz": 3.14159}},
                want: `{"fizz":"3.14159"}`,
-       }, {
-               name: jsontest.Name("Structs/InlinedFallback/DiscardUnknownMembers"),
-               opts: []Options{DiscardUnknownMembers(true)},
-               in: structInlineTextValue{
-                       A: 1,
-                       X: jsontext.Value(` { "fizz" : "buzz" } `),
-                       B: 2,
-               },
-               // NOTE: DiscardUnknownMembers has no effect since this is "inline".
-               want: `{"A":1,"B":2,"fizz":"buzz"}`,
-       }, {
-               name: jsontest.Name("Structs/UnknownFallback/DiscardUnknownMembers"),
-               opts: []Options{DiscardUnknownMembers(true)},
-               in: structUnknownTextValue{
-                       A: 1,
-                       X: jsontext.Value(` { "fizz" : "buzz" } `),
-                       B: 2,
-               },
-               want: `{"A":1,"B":2}`,
-       }, {
-               name: jsontest.Name("Structs/UnknownFallback"),
-               in: structUnknownTextValue{
-                       A: 1,
-                       X: jsontext.Value(` { "fizz" : "buzz" } `),
-                       B: 2,
-               },
-               want: `{"A":1,"B":2,"fizz":"buzz"}`,
        }, {
                name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/Other"),
                in: structNoCaseInlineTextValue{
@@ -6999,28 +6967,11 @@ func TestUnmarshal(t *testing.T) {
                opts:  []Options{RejectUnknownMembers(true)},
                inBuf: `{"A":1,"fizz":"buzz","B":2}`,
                inVal: new(structInlineTextValue),
-               // NOTE: DiscardUnknownMembers has no effect since this is "inline".
                want: addr(structInlineTextValue{
                        A: 1,
                        X: jsontext.Value(`{"fizz":"buzz"}`),
                        B: 2,
                }),
-       }, {
-               name:    jsontest.Name("Structs/UnknownFallback/RejectUnknownMembers"),
-               opts:    []Options{RejectUnknownMembers(true)},
-               inBuf:   `{"A":1,"fizz":"buzz","B":2}`,
-               inVal:   new(structUnknownTextValue),
-               want:    addr(structUnknownTextValue{A: 1}),
-               wantErr: EU(ErrUnknownName).withPos(`{"A":1,`, "/fizz").withType('"', T[structUnknownTextValue]()),
-       }, {
-               name:  jsontest.Name("Structs/UnknownFallback"),
-               inBuf: `{"A":1,"fizz":"buzz","B":2}`,
-               inVal: new(structUnknownTextValue),
-               want: addr(structUnknownTextValue{
-                       A: 1,
-                       X: jsontext.Value(`{"fizz":"buzz"}`),
-                       B: 2,
-               }),
        }, {
                name:  jsontest.Name("Structs/UnknownIgnored"),
                opts:  []Options{RejectUnknownMembers(false)},
index 8179f8ab179504d44d3900262b178519d600f6eb..adbb200c703e1f18ff028cbe5d6d9b00f3be9786 100644 (file)
 //     while many non-fallback fields may be specified. This option
 //     must not be specified with any other option (including the JSON name).
 //
-//   - unknown: The "unknown" option is a specialized variant
-//     of the inlined fallback to indicate that this Go struct field
-//     contains any number of unknown JSON object members. The field type must
-//     be a [jsontext.Value], map[~string]T, or an unnamed pointer to such types.
-//     If [DiscardUnknownMembers] is specified when marshaling,
-//     the contents of this field are ignored.
-//     If [RejectUnknownMembers] is specified when unmarshaling,
-//     any unknown object members are rejected regardless of whether
-//     an inlined fallback with the "unknown" option exists. This option
-//     must not be specified with any other option (including the JSON name).
-//
 //   - format: The "format" option specifies a format flag
 //     used to specialize the formatting of the field value.
 //     The option is a key-value pair specified as "format:value" where
index dc1f06674ce24a0c2dd75da1b18bdb4eaf2b87d8..684ca9c6a2b53fff4ca956003c191d78402d6453 100644 (file)
@@ -8,7 +8,6 @@ package json_test
 
 import (
        "bytes"
-       "errors"
        "fmt"
        "log"
        "math"
@@ -338,67 +337,6 @@ func Example_inlinedFields() {
        // }
 }
 
-// Due to version skew, the set of JSON object members known at compile-time
-// may differ from the set of members encountered at execution-time.
-// As such, it may be useful to have finer grain handling of unknown members.
-// This package supports preserving, rejecting, or discarding such members.
-func Example_unknownMembers() {
-       const input = `{
-               "Name": "Teal",
-               "Value": "#008080",
-               "WebSafe": false
-       }`
-       type Color struct {
-               Name  string
-               Value string
-
-               // Unknown is a Go struct field that holds unknown JSON object members.
-               // It is marked as having this behavior with the "unknown" tag option.
-               //
-               // The type may be a jsontext.Value or map[string]T.
-               Unknown jsontext.Value `json:",unknown"`
-       }
-
-       // By default, unknown members are stored in a Go field marked as "unknown"
-       // or ignored if no such field exists.
-       var color Color
-       err := json.Unmarshal([]byte(input), &color)
-       if err != nil {
-               log.Fatal(err)
-       }
-       fmt.Println("Unknown members:", string(color.Unknown))
-
-       // Specifying RejectUnknownMembers causes Unmarshal
-       // to reject the presence of any unknown members.
-       err = json.Unmarshal([]byte(input), new(Color), json.RejectUnknownMembers(true))
-       serr, ok := errors.AsType[*json.SemanticError](err)
-       if ok && serr.Err == json.ErrUnknownName {
-               fmt.Println("Unmarshal error:", serr.Err, strconv.Quote(serr.JSONPointer.LastToken()))
-       }
-
-       // By default, Marshal preserves unknown members stored in
-       // a Go struct field marked as "unknown".
-       b, err := json.Marshal(color)
-       if err != nil {
-               log.Fatal(err)
-       }
-       fmt.Println("Output with unknown members:   ", string(b))
-
-       // Specifying DiscardUnknownMembers causes Marshal
-       // to discard any unknown members.
-       b, err = json.Marshal(color, json.DiscardUnknownMembers(true))
-       if err != nil {
-               log.Fatal(err)
-       }
-       fmt.Println("Output without unknown members:", string(b))
-
-       // Output:
-       // Unknown members: {"WebSafe":false}
-       // Unmarshal error: unknown object member name "WebSafe"
-       // Output with unknown members:    {"Name":"Teal","Value":"#008080","WebSafe":false}
-       // Output without unknown members: {"Name":"Teal","Value":"#008080"}
-}
-
 // The "format" tag option can be used to alter the formatting of certain types.
 func Example_formatFlags() {
        value := struct {
index 4a02be7327a04b9ffae1ab3e8e565b9318d9c7a7..5c560ec5d5bff350a7e07959c975e55e3b90b02e 100644 (file)
@@ -129,25 +129,16 @@ func makeStructFields(root reflect.Type) (fs structFields, serr *SemanticError)
                                        f.inline = true // implied by use of Go embedding without an explicit name
                                }
                        }
-                       if f.inline || f.unknown {
+                       if f.inline {
                                // Handle an inlined field that serializes to/from
                                // zero or more JSON object members.
 
-                               switch f.fieldOptions {
-                               case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true}:
-                               case fieldOptions{name: f.name, quotedName: f.quotedName, unknown: true}:
-                               case fieldOptions{name: f.name, quotedName: f.quotedName, inline: true, unknown: true}:
-                                       serr = orErrorf(serr, t, "Go struct field %s cannot have both `inline` and `unknown` specified", sf.Name)
-                                       f.inline = false // let `unknown` take precedence
-                               default:
-                                       serr = orErrorf(serr, t, "Go struct field %s cannot have any options other than `inline` or `unknown` specified", sf.Name)
+                               if f.fieldOptions != (fieldOptions{name: f.name, quotedName: f.quotedName, inline: true}) {
+                                       serr = orErrorf(serr, t, "Go struct field %s cannot have any options other than `inline` specified", sf.Name)
                                        if f.hasName {
                                                continue // invalid inlined field; treat as ignored
                                        }
-                                       f.fieldOptions = fieldOptions{name: f.name, quotedName: f.quotedName, inline: f.inline, unknown: f.unknown}
-                                       if f.inline && f.unknown {
-                                               f.inline = false // let `unknown` take precedence
-                                       }
+                                       f.fieldOptions = fieldOptions{name: f.name, quotedName: f.quotedName, inline: f.inline}
                                }
 
                                // Reject any types with custom serialization otherwise
@@ -160,10 +151,6 @@ func makeStructFields(root reflect.Type) (fs structFields, serr *SemanticError)
                                // Handle an inlined field that serializes to/from
                                // a finite number of JSON object members backed by a Go struct.
                                if tf.Kind() == reflect.Struct {
-                                       if f.unknown {
-                                               serr = orErrorf(serr, t, "inlined Go struct field %s of type %s with `unknown` tag must be a Go map of string key or a jsontext.Value", sf.Name, tf)
-                                               continue // invalid inlined field; treat as ignored
-                                       }
                                        if qe.visitChildren {
                                                queue = append(queue, queueEntry{tf, f.index, !seen[tf]})
                                        }
@@ -392,7 +379,6 @@ type fieldOptions struct {
        nameNeedEscape bool
        casing         int8 // either 0, caseIgnore, or caseStrict
        inline         bool
-       unknown        bool
        omitzero       bool
        omitempty      bool
        string         bool
@@ -526,8 +512,6 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool,
                        }
                case "inline":
                        out.inline = true
-               case "unknown":
-                       out.unknown = true
                case "omitzero":
                        out.omitzero = true
                case "omitempty":
@@ -553,7 +537,7 @@ func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool,
                        // This catches invalid mutants such as "omitEmpty" or "omit_empty".
                        normOpt := strings.ReplaceAll(strings.ToLower(opt), "_", "")
                        switch normOpt {
-                       case "case", "inline", "unknown", "omitzero", "omitempty", "string", "format":
+                       case "case", "inline", "omitzero", "omitempty", "string", "format":
                                err = cmp.Or(err, fmt.Errorf("Go struct field %s has invalid appearance of `%s` tag option; specify `%s` instead", sf.Name, opt, normOpt))
                        }
 
index ae58182f298ab4d05b7758a3533d7bfbb4d74033..dbfabd4aef29d1046ee0c520bb35aa8ff68b6bd2 100644 (file)
@@ -183,7 +183,7 @@ func TestMakeStructFields(t *testing.T) {
                                X jsontext.Value `json:",inline"`
                        } `json:",inline"`
                        X2 struct {
-                               X map[string]any `json:",unknown"`
+                               X map[string]any `json:",inline"`
                        } `json:",inline"`
                }{},
                want: structFields{},
@@ -194,12 +194,12 @@ func TestMakeStructFields(t *testing.T) {
                                X jsontext.Value `json:",inline"`
                        } `json:",inline"`
                        X2 struct {
-                               X map[string]any `json:",unknown"`
+                               X map[string]any `json:",inline"`
                        } `json:",inline"`
-                       X map[string]jsontext.Value `json:",unknown"`
+                       X map[string]jsontext.Value `json:",inline"`
                }{},
                want: structFields{
-                       inlinedFallback: &structField{id: 0, index: []int{2}, typ: T[map[string]jsontext.Value](), fieldOptions: fieldOptions{name: "X", quotedName: `"X"`, unknown: true}},
+                       inlinedFallback: &structField{id: 0, index: []int{2}, typ: T[map[string]jsontext.Value](), fieldOptions: fieldOptions{name: "X", quotedName: `"X"`, inline: true}},
                },
        }, {
                name: jsontest.Name("InlinedFallback/InvalidImplicit"),
@@ -231,18 +231,12 @@ func TestMakeStructFields(t *testing.T) {
                }{},
                want:    structFields{flattened: []structField{}},
                wantErr: errors.New(`Go struct fields A and B conflict over JSON object name "same"`),
-       }, {
-               name: jsontest.Name("BothInlineAndUnknown"),
-               in: struct {
-                       A struct{} `json:",inline,unknown"`
-               }{},
-               wantErr: errors.New("Go struct field A cannot have both `inline` and `unknown` specified"),
        }, {
                name: jsontest.Name("InlineWithOptions"),
                in: struct {
                        A struct{} `json:",inline,omitempty"`
                }{},
-               wantErr: errors.New("Go struct field A cannot have any options other than `inline` or `unknown` specified"),
+               wantErr: errors.New("Go struct field A cannot have any options other than `inline` specified"),
        }, {
                name: jsontest.Name("UnknownWithOptions"),
                in: struct {
@@ -257,7 +251,7 @@ func TestMakeStructFields(t *testing.T) {
                                inline:     true,
                        },
                }},
-               wantErr: errors.New("Go struct field A cannot have any options other than `inline` or `unknown` specified"),
+               wantErr: errors.New("Go struct field A cannot have any options other than `inline` specified"),
        }, {
                name: jsontest.Name("InlineTextMarshaler"),
                in: struct {
@@ -287,10 +281,18 @@ func TestMakeStructFields(t *testing.T) {
                }}},
                wantErr: errors.New(`inlined Go struct field A of type struct { encoding.TextAppender } must not implement marshal or unmarshal methods`),
        }, {
-               name: jsontest.Name("UnknownJSONMarshaler"),
+               name: jsontest.Name("InlineJSONMarshaler"),
                in: struct {
-                       A struct{ Marshaler } `json:",unknown"`
+                       A struct{ Marshaler } `json:",inline"`
                }{},
+               want: structFields{flattened: []structField{{
+                       index: []int{0, 0},
+                       typ:   reflect.TypeFor[Marshaler](),
+                       fieldOptions: fieldOptions{
+                               name:       "Marshaler",
+                               quotedName: `"Marshaler"`,
+                       },
+               }}},
                wantErr: errors.New(`inlined Go struct field A of type struct { json.Marshaler } must not implement marshal or unmarshal methods`),
        }, {
                name: jsontest.Name("InlineJSONMarshalerTo"),
@@ -307,10 +309,18 @@ func TestMakeStructFields(t *testing.T) {
                }}},
                wantErr: errors.New(`inlined Go struct field A of type struct { json.MarshalerTo } must not implement marshal or unmarshal methods`),
        }, {
-               name: jsontest.Name("UnknownTextUnmarshaler"),
+               name: jsontest.Name("InlineTextUnmarshaler"),
                in: struct {
-                       A *struct{ encoding.TextUnmarshaler } `json:",unknown"`
+                       A *struct{ encoding.TextUnmarshaler } `json:",inline"`
                }{},
+               want: structFields{flattened: []structField{{
+                       index: []int{0, 0},
+                       typ:   reflect.TypeFor[encoding.TextUnmarshaler](),
+                       fieldOptions: fieldOptions{
+                               name:       "TextUnmarshaler",
+                               quotedName: `"TextUnmarshaler"`,
+                       },
+               }}},
                wantErr: errors.New(`inlined Go struct field A of type struct { encoding.TextUnmarshaler } must not implement marshal or unmarshal methods`),
        }, {
                name: jsontest.Name("InlineJSONUnmarshaler"),
@@ -327,23 +337,23 @@ func TestMakeStructFields(t *testing.T) {
                }}},
                wantErr: errors.New(`inlined Go struct field A of type struct { json.Unmarshaler } must not implement marshal or unmarshal methods`),
        }, {
-               name: jsontest.Name("UnknownJSONUnmarshalerFrom"),
+               name: jsontest.Name("InlineJSONUnmarshalerFrom"),
                in: struct {
-                       A struct{ UnmarshalerFrom } `json:",unknown"`
+                       A struct{ UnmarshalerFrom } `json:",inline"`
                }{},
+               want: structFields{flattened: []structField{{
+                       index: []int{0, 0},
+                       typ:   reflect.TypeFor[UnmarshalerFrom](),
+                       fieldOptions: fieldOptions{
+                               name:       "UnmarshalerFrom",
+                               quotedName: `"UnmarshalerFrom"`,
+                       },
+               }}},
                wantErr: errors.New(`inlined Go struct field A of type struct { json.UnmarshalerFrom } must not implement marshal or unmarshal methods`),
-       }, {
-               name: jsontest.Name("UnknownStruct"),
-               in: struct {
-                       A struct {
-                               X, Y, Z string
-                       } `json:",unknown"`
-               }{},
-               wantErr: errors.New("inlined Go struct field A of type struct { X string; Y string; Z string } with `unknown` tag must be a Go map of string key or a jsontext.Value"),
        }, {
                name: jsontest.Name("InlineUnsupported/MapIntKey"),
                in: struct {
-                       A map[int]any `json:",unknown"`
+                       A map[int]any `json:",inline"`
                }{},
                wantErr: errors.New(`inlined Go struct field A of type map[int]interface {} must be a Go struct, Go map of string key, or jsontext.Value`),
        }, {
@@ -633,9 +643,9 @@ func TestParseTagOptions(t *testing.T) {
        }, {
                name: jsontest.Name("SuperfluousCommas"),
                in: struct {
-                       V int `json:",,,,\"\",,inline,unknown,,,,"`
+                       V int `json:",,,,\"\",,inline,,,,,"`
                }{},
-               wantOpts: fieldOptions{name: "V", quotedName: `"V"`, inline: true, unknown: true},
+               wantOpts: fieldOptions{name: "V", quotedName: `"V"`, inline: true},
                wantErr:  errors.New("Go struct field V has malformed `json` tag: invalid character ',' at start of option (expecting Unicode letter or single quote)"),
        }, {
                name: jsontest.Name("CaseAloneOption"),
@@ -683,12 +693,6 @@ func TestParseTagOptions(t *testing.T) {
                        FieldName int `json:",inline"`
                }{},
                wantOpts: fieldOptions{name: "FieldName", quotedName: `"FieldName"`, inline: true},
-       }, {
-               name: jsontest.Name("UnknownOption"),
-               in: struct {
-                       FieldName int `json:",unknown"`
-               }{},
-               wantOpts: fieldOptions{name: "FieldName", quotedName: `"FieldName"`, unknown: true},
        }, {
                name: jsontest.Name("OmitZeroOption"),
                in: struct {
@@ -743,14 +747,13 @@ func TestParseTagOptions(t *testing.T) {
        }, {
                name: jsontest.Name("AllOptions"),
                in: struct {
-                       FieldName int `json:",case:ignore,inline,unknown,omitzero,omitempty,string,format:format"`
+                       FieldName int `json:",case:ignore,inline,omitzero,omitempty,string,format:format"`
                }{},
                wantOpts: fieldOptions{
                        name:       "FieldName",
                        quotedName: `"FieldName"`,
                        casing:     caseIgnore,
                        inline:     true,
-                       unknown:    true,
                        omitzero:   true,
                        omitempty:  true,
                        string:     true,
@@ -759,14 +762,13 @@ func TestParseTagOptions(t *testing.T) {
        }, {
                name: jsontest.Name("AllOptionsQuoted"),
                in: struct {
-                       FieldName int `json:",'case':'ignore','inline','unknown','omitzero','omitempty','string','format':'format'"`
+                       FieldName int `json:",'case':'ignore','inline','omitzero','omitempty','string','format':'format'"`
                }{},
                wantOpts: fieldOptions{
                        name:       "FieldName",
                        quotedName: `"FieldName"`,
                        casing:     caseIgnore,
                        inline:     true,
-                       unknown:    true,
                        omitzero:   true,
                        omitempty:  true,
                        string:     true,
@@ -783,7 +785,7 @@ func TestParseTagOptions(t *testing.T) {
        }, {
                name: jsontest.Name("AllOptionsSpaceSensitive"),
                in: struct {
-                       FieldName int `json:", case:ignore , inline , unknown , omitzero , omitempty , string , format:format "`
+                       FieldName int `json:", case:ignore , inline , omitzero , omitempty , string , format:format "`
                }{},
                wantOpts: fieldOptions{name: "FieldName", quotedName: `"FieldName"`},
                wantErr:  errors.New("Go struct field FieldName has malformed `json` tag: invalid character ' ' at start of option (expecting Unicode letter or single quote)"),
index 9685f20f9f805f220142366e8f72467c50f7bca5..ce6517c901c73946075e379b7ee8c877ca0031a2 100644 (file)
@@ -65,7 +65,6 @@ import (
 //   - [FormatNilMapAsNull] affects marshaling only
 //   - [OmitZeroStructFields] affects marshaling only
 //   - [MatchCaseInsensitiveNames] affects marshaling and unmarshaling
-//   - [DiscardUnknownMembers] affects marshaling only
 //   - [RejectUnknownMembers] affects unmarshaling only
 //   - [WithMarshalers] affects marshaling only
 //   - [WithUnmarshalers] affects unmarshaling only
@@ -200,22 +199,8 @@ func MatchCaseInsensitiveNames(v bool) Options {
        }
 }
 
-// DiscardUnknownMembers specifies that marshaling should ignore any
-// JSON object members stored in Go struct fields dedicated to storing
-// unknown JSON object members.
-//
-// This only affects marshaling and is ignored when unmarshaling.
-func DiscardUnknownMembers(v bool) Options {
-       if v {
-               return jsonflags.DiscardUnknownMembers | 1
-       } else {
-               return jsonflags.DiscardUnknownMembers | 0
-       }
-}
-
 // RejectUnknownMembers specifies that unknown members should be rejected
-// when unmarshaling a JSON object, regardless of whether there is a field
-// to store unknown members.
+// when unmarshaling a JSON object.
 //
 // This only affects unmarshaling and is ignored when marshaling.
 func RejectUnknownMembers(v bool) Options {