From 40e395c24e5c8eb3999ba58d3bba267b0d1b3c5d Mon Sep 17 00:00:00 2001 From: pj Date: Sat, 22 Sep 2018 19:24:04 +1000 Subject: [PATCH 1/2] added heednull option for json encoding --- src/encoding/json/encode.go | 20 +++++++++++++++++++- src/encoding/json/encode_test.go | 10 +++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index f10124e67d13c8..658761bd32b63a 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 "heednull" 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 "heednull" and "omitempty" are present, then "heednull" is +// ignored. If the field is not a slice or map, "heednull" 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.heedNull { + 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 + heedNull bool quoted bool encoder encoderFunc @@ -1156,6 +1173,7 @@ func typeFields(t reflect.Type) []field { index: index, typ: ft, omitEmpty: opts.Contains("omitempty"), + heedNull: !opts.Contains("omitempty") && opts.Contains("heednull"), 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..2c617789179680 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,heednull"` + Slb []string `json:"slb,omitempty,heednull"` + + Mh map[string]interface{} `json:"mh,heednull"` + Mb map[string]interface{} `json:"mb,omitempty,heednull"` } var optionalsExpected = `{ @@ -52,7 +58,9 @@ var optionalsExpected = `{ "br": false, "ur": 0, "str": {}, - "sto": {} + "sto": {}, + "slh": [], + "mh": {} }` func TestOmitEmpty(t *testing.T) { From ab41add598bcbb1c45119e97555f2ec8c2bbc1d5 Mon Sep 17 00:00:00 2001 From: pj Date: Tue, 28 Jan 2020 11:17:54 +1100 Subject: [PATCH 2/2] - change from "heednull" to "nonil" --- src/encoding/json/encode.go | 12 ++++++------ src/encoding/json/encode_test.go | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 658761bd32b63a..f9694aa96a9e65 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -71,10 +71,10 @@ import ( // false, 0, a nil pointer, a nil interface value, and any empty array, // slice, map, or string. // -// The "heednull" option specifies that if the field is a slice or map +// 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 "heednull" and "omitempty" are present, then "heednull" is -// ignored. If the field is not a slice or map, "heednull" does nothing. +// 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 "-,". @@ -662,7 +662,7 @@ FieldLoop: } opts.quoted = f.quoted - if f.heedNull { + if f.noNil { if f.typ.Kind() == reflect.Slice && fv.IsNil() { e.WriteString("[]") } else if f.typ.Kind() == reflect.Map && fv.IsNil() { @@ -1055,7 +1055,7 @@ type field struct { index []int typ reflect.Type omitEmpty bool - heedNull bool + noNil bool quoted bool encoder encoderFunc @@ -1173,7 +1173,7 @@ func typeFields(t reflect.Type) []field { index: index, typ: ft, omitEmpty: opts.Contains("omitempty"), - heedNull: !opts.Contains("omitempty") && opts.Contains("heednull"), + 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 2c617789179680..4cbf2f5f551c02 100644 --- a/src/encoding/json/encode_test.go +++ b/src/encoding/json/encode_test.go @@ -42,11 +42,11 @@ type Optionals struct { Str struct{} `json:"str"` Sto struct{} `json:"sto,omitempty"` - Slh []string `json:"slh,heednull"` - Slb []string `json:"slb,omitempty,heednull"` + Slh []string `json:"slh,nonil"` + Slb []string `json:"slb,omitempty,nonil"` - Mh map[string]interface{} `json:"mh,heednull"` - Mb map[string]interface{} `json:"mb,omitempty,heednull"` + Mh map[string]interface{} `json:"mh,nonil"` + Mb map[string]interface{} `json:"mb,omitempty,nonil"` } var optionalsExpected = `{