Description
Support zero values of structs with omitempty in encoding/json and encoding/xml.
This bites people a lot, especially with time.Time
. Open bugs include #4357 (which has many dups) and #10648. There may be others.
Proposal
Check for zero struct values by adding an additional case to the isEmptyValue
function:
case reflect.Struct:
return reflect.Zero(v.Type()).Interface() == v.Interface()
This will solve the vast majority of cases.
(Optional) Introduce a new encoding.IsZeroer
interface, and use this to check for emptiness:
Update: I am dropping this part of the proposal, see below.
type IsZeroer interface {
IsZero() bool
}
Visit this playground link and note that the unmarshaled time.Time
value does not have a nil
Location
field. This prevents the reflection-based emptiness check from working. IsZero()
already exists on time.Time
, has the correct semantics, and has been adopted as a convention by Go code outside the standard library.
An additional check can be added to the isEmptyValue()
functions before checking the value's Kind
:
if z, ok := v.Interface().(encoding.IsZeroer); ok {
return z.IsZero()
}
Compatibility
The encoding.IsZeroer
interface could introduce issues with existing non-struct types that may have implemented IsZero()
without consideration of omitempty
. If this is undesirable, the encoding.IsZeroer
interface check could be moved only within the struct case:
case reflect.Struct:
val := v.Interface()
if z, ok := val.(encoding.IsZeroer); ok {
return z.IsZero()
}
return reflect.Zero(v.Type()).Interface() == val
Otherwise, this change is backward-compatible with existing valid uses of omitempty
. Users who have applied omitempty
to struct fields incorrectly will get their originally intended behavior for free.
Implementation
I (@joeshaw) have implemented and tested this change locally, and will send the CL when the Go 1.6 tree opens.
Activity