out: []int{1, 2, 0, 4, 5},
err: &UnmarshalTypeError{Value: "bool", Type: reflect.TypeFor[int](), Offset: 9},
},
+
+ {
+ CaseName: Name("DashComma"),
+ in: `{"-":"hello"}`,
+ ptr: new(struct {
+ F string `json:"-,"`
+ }),
+ out: struct {
+ F string `json:"-,"`
+ }{"hello"},
+ },
+ {
+ CaseName: Name("DashCommaOmitEmpty"),
+ in: `{"-":"hello"}`,
+ ptr: new(struct {
+ F string `json:"-,omitempty"`
+ }),
+ out: struct {
+ F string `json:"-,omitempty"`
+ }{"hello"},
+ },
}
func TestMarshal(t *testing.T) {
// the JSON member name and other features.
func parseFieldOptions(sf reflect.StructField) (out fieldOptions, ignored bool, err error) {
tag, hasTag := sf.Tag.Lookup("json")
+ tagOrig := tag
// Check whether this field is explicitly ignored.
if tag == "-" {
err = cmp.Or(err, fmt.Errorf("Go struct field %s has JSON object name %q with invalid UTF-8", sf.Name, name))
name = string([]rune(name)) // replace invalid UTF-8 with utf8.RuneError
}
+ if name == "-" && tag[0] == '-' {
+ defer func() { // defer to let other errors take precedence
+ err = cmp.Or(err, fmt.Errorf("Go struct field %s has JSON object name %q; either "+
+ "use `json:\"-\"` to ignore the field or "+
+ "use `json:\"'-'%s` to specify %q as the name", sf.Name, out.name, strings.TrimPrefix(strconv.Quote(tagOrig), `"-`), name))
+ }()
+ }
if err2 == nil {
out.hasName = true
out.name = name
}{},
wantOpts: fieldOptions{hasName: true, name: "-", quotedName: `"-"`},
wantErr: errors.New("Go struct field V has malformed `json` tag: invalid trailing ',' character"),
+ }, {
+ name: jsontest.Name("DashCommaOmitEmpty"),
+ in: struct {
+ V int `json:"-,omitempty"`
+ }{},
+ wantOpts: fieldOptions{hasName: true, name: "-", quotedName: `"-"`, omitempty: true},
+ wantErr: errors.New("Go struct field V has JSON object name \"-\"; either use `json:\"-\"` to ignore the field or use `json:\"'-',omitempty\"` to specify \"-\" as the name"),
+ }, {
+ name: jsontest.Name("QuotedDashCommaOmitEmpty"),
+ in: struct {
+ V int `json:"'-',omitempty"`
+ }{},
+ wantOpts: fieldOptions{hasName: true, name: "-", quotedName: `"-"`, omitempty: true},
}, {
name: jsontest.Name("QuotedDashName"),
in: struct {
out: []int{1, 2, 0, 4, 5},
err: &UnmarshalTypeError{Value: "bool", Type: reflect.TypeFor[int](), Field: "2", Offset: len64(`[1,2,`)},
},
+
+ {
+ CaseName: Name("DashComma"),
+ in: `{"-":"hello"}`,
+ ptr: new(struct {
+ F string `json:"-,"`
+ }),
+ out: struct {
+ F string `json:"-,"`
+ }{"hello"},
+ },
+ {
+ CaseName: Name("DashCommaOmitEmpty"),
+ in: `{"-":"hello"}`,
+ ptr: new(struct {
+ F string `json:"-,omitempty"`
+ }),
+ out: struct {
+ F string `json:"-,omitempty"`
+ }{"hello"},
+ },
}
func TestMarshal(t *testing.T) {
// slice, map, or string of length zero.
//
// As a special case, if the field tag is "-", the field is always omitted.
-// Note that a field with name "-" can still be generated using the tag "-,".
+// JSON names containing commas or quotes, or names identical to "" or "-",
+// can be specified using a single-quoted string literal, where the syntax
+// is identical to the Go grammar for a double-quoted string literal,
+// but instead uses single quotes as the delimiters.
//
// Examples of struct field tags and their meanings:
//
// Field int `json:"-"`
//
// // Field appears in JSON as key "-".
-// Field int `json:"-,"`
+// Field int `json:"'-'"`
//
// The "omitzero" option specifies that the field should be omitted
// from the encoding if the field has a zero value, according to rules: