diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index f10124e67d13c8..f9694aa96a9e65 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -71,6 +71,11 @@ import ( // false, 0, a nil pointer, a nil interface value, and any empty array, // slice, map, or string. // +// The "nonil" option specifies that if the field is a slice or map +// of nil value, then the value encoded will be [] or {} respectively (instead +// of "null"). If both "nonil" and "omitempty" are present, then "nonil" is +// ignored. If the field is not a slice or map, "nonil" does nothing. +// // 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 "-,". // @@ -656,7 +661,18 @@ FieldLoop: e.WriteString(f.nameNonEsc) } opts.quoted = f.quoted - f.encoder(e, fv, opts) + + if f.noNil { + if f.typ.Kind() == reflect.Slice && fv.IsNil() { + e.WriteString("[]") + } else if f.typ.Kind() == reflect.Map && fv.IsNil() { + e.WriteString("{}") + } else { + f.encoder(e, fv, opts) + } + } else { + f.encoder(e, fv, opts) + } } if next == '{' { e.WriteString("{}") @@ -1039,6 +1055,7 @@ type field struct { index []int typ reflect.Type omitEmpty bool + noNil bool quoted bool encoder encoderFunc @@ -1156,6 +1173,7 @@ func typeFields(t reflect.Type) []field { index: index, typ: ft, omitEmpty: opts.Contains("omitempty"), + noNil: !opts.Contains("omitempty") && opts.Contains("nonil"), quoted: quoted, } field.nameBytes = []byte(field.name) diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go index cd5eadf3c1cd2a..4cbf2f5f551c02 100644 --- a/src/encoding/json/encode_test.go +++ b/src/encoding/json/encode_test.go @@ -41,6 +41,12 @@ type Optionals struct { Str struct{} `json:"str"` Sto struct{} `json:"sto,omitempty"` + + Slh []string `json:"slh,nonil"` + Slb []string `json:"slb,omitempty,nonil"` + + Mh map[string]interface{} `json:"mh,nonil"` + Mb map[string]interface{} `json:"mb,omitempty,nonil"` } var optionalsExpected = `{ @@ -52,7 +58,9 @@ var optionalsExpected = `{ "br": false, "ur": 0, "str": {}, - "sto": {} + "sto": {}, + "slh": [], + "mh": {} }` func TestOmitEmpty(t *testing.T) {