Joe Shaw uploaded a change:
https://go-review.googlesource.com/13914
encoding/json, encoding/xml: 'omitempty' for empty structs
Empty structs (such as time.Time) that are marked omitempty are omitted
when marshaling to JSON and XML.
For #11939
For #4357
Fixes #10648
Change-Id: Ife16dda4ed808df4e927914369646b7ef37154da
---
M src/encoding/json/encode.go
M src/encoding/json/encode_test.go
M src/encoding/xml/marshal.go
M src/encoding/xml/marshal_test.go
4 files changed, 44 insertions(+), 24 deletions(-)
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 90782de..00c3ad7 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -54,7 +54,7 @@
// becomes a member of the object unless
// - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option.
-// The empty values are false, 0, any
+// The empty values are false, 0, an empty struct, any
// nil pointer or interface value, and any array, slice, map, or string of
// length zero. The object's default key string is the struct field name
// but can be specified in the struct field's tag value. The "json" key in
@@ -289,6 +289,8 @@
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
+ case reflect.Struct:
+ return reflect.Zero(v.Type()).Interface() == v.Interface()
}
return false
}
diff --git a/src/encoding/json/encode_test.go
b/src/encoding/json/encode_test.go
index 7abfa85..1f9ecdb 100644
--- a/src/encoding/json/encode_test.go
+++ b/src/encoding/json/encode_test.go
@@ -37,6 +37,14 @@
Str struct{} `json:"str"`
Sto struct{} `json:"sto,omitempty"`
+
+ // non-nil pointers
+ Psr *struct{} `json:"psr"`
+ Pso *struct{} `json:"pso,omitempty"`
+
+ // nil pointers
+ Nsr *struct{} `json:"nsr"`
+ Nso *struct{} `json:"nso,omitempty"`
}
var optionalsExpected = `{
@@ -48,7 +56,9 @@
"br": false,
"ur": 0,
"str": {},
- "sto": {}
+ "psr": {},
+ "pso": {},
+ "nsr": null
}`
func TestOmitEmpty(t *testing.T) {
@@ -56,6 +66,8 @@
o.Sw = "something"
o.Mr = map[string]interface{}{}
o.Mo = map[string]interface{}{}
+ o.Psr = new(struct{})
+ o.Pso = new(struct{})
got, err := MarshalIndent(&o, "", " ")
if err != nil {
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 86d1422..d66761d 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -54,7 +54,8 @@
// subject to the usual marshalling procedure. It must not contain
// the "--" string within it.
// - a field with a tag including the "omitempty" option is omitted
-// if the field value is empty. The empty values are false, 0, any
+// if the field value is empty. The empty values are false, 0, an
+// empty struct, any
// nil pointer or interface value, and any array, slice, map, or
// string of length zero.
// - an anonymous struct field is handled as if the fields of its
@@ -757,13 +758,14 @@
if finfo.flags&fAttr != 0 {
continue
}
- vf := finfo.value(val)
+ ovf := finfo.value(val)
// Dereference or skip nil pointer, interface values.
- switch vf.Kind() {
+ vf := ovf
+ switch ovf.Kind() {
case reflect.Ptr, reflect.Interface:
- if !vf.IsNil() {
- vf = vf.Elem()
+ if !ovf.IsNil() {
+ vf = ovf.Elem()
}
}
@@ -880,7 +882,7 @@
}
}
}
- if err := p.marshalValue(vf, finfo, nil); err != nil {
+ if err := p.marshalValue(ovf, finfo, nil); err != nil {
return err
}
}
@@ -984,6 +986,8 @@
return v.Float() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
+ case reflect.Struct:
+ return reflect.Zero(v.Type()).Interface() == v.Interface()
}
return false
}
diff --git a/src/encoding/xml/marshal_test.go
b/src/encoding/xml/marshal_test.go
index 66675d7..9b66a53 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -204,14 +204,15 @@
}
type OmitFieldTest struct {
- Int int `xml:",omitempty"`
- Named int `xml:"int,omitempty"`
- Float float64 `xml:",omitempty"`
- Uint8 uint8 `xml:",omitempty"`
- Bool bool `xml:",omitempty"`
- Str string `xml:",omitempty"`
- Bytes []byte `xml:",omitempty"`
- Ptr *PresenceTest `xml:",omitempty"`
+ Int int `xml:",omitempty"`
+ Named int `xml:"int,omitempty"`
+ Float float64 `xml:",omitempty"`
+ Uint8 uint8 `xml:",omitempty"`
+ Bool bool `xml:",omitempty"`
+ Str string `xml:",omitempty"`
+ Bytes []byte `xml:",omitempty"`
+ Ptr *PresenceTest `xml:",omitempty"`
+ Struct PresenceTest `xml:",omitempty"`
}
type AnyTest struct {
@@ -838,14 +839,15 @@
// omitempty on fields
{
Value: &OmitFieldTest{
- Int: 8,
- Named: 9,
- Float: 23.5,
- Uint8: 255,
- Bool: true,
- Str: "str",
- Bytes: []byte("byt"),
- Ptr: &PresenceTest{},
+ Int: 8,
+ Named: 9,
+ Float: 23.5,
+ Uint8: 255,
+ Bool: true,
+ Str: "str",
+ Bytes: []byte("byt"),
+ Ptr: &PresenceTest{},
+ Struct: PresenceTest{},
},
ExpectXML: `<OmitFieldTest>` +
`<Int>8</Int>` +
--
https://go-review.googlesource.com/13914