Skip to content

Commit dbedf54

Browse files
committed
4
Change-Id: I84c74a84f5d69fcd9abd5933ca2923dcc8ff2220
1 parent 561d82b commit dbedf54

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

src/encoding/json/encode.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -329,13 +329,37 @@ func isEmptyValue(v reflect.Value) bool {
329329
return false
330330
}
331331

332+
type isZeroer interface {
333+
IsZero() bool
334+
}
335+
336+
var isZeroerType = reflect.TypeFor[isZeroer]()
337+
332338
func isZeroValue(v reflect.Value) bool {
333-
if z, ok := v.Interface().(interface {
334-
IsZero() bool
335-
}); ok {
336-
return z.IsZero()
339+
// Provide a function that uses a type's IsZero method.
340+
var isZero func(reflect.Value) bool
341+
342+
switch {
343+
case v.Kind() == reflect.Interface && v.Type().Implements(isZeroerType):
344+
isZero = func(va reflect.Value) bool {
345+
// Avoid panics calling IsZero on a nil interface or
346+
// non-nil interface with nil pointer.
347+
return va.IsNil() ||
348+
(va.Elem().Kind() == reflect.Pointer && va.Elem().IsNil()) ||
349+
va.Interface().(isZeroer).IsZero()
350+
}
351+
case v.Kind() == reflect.Pointer && v.Type().Implements(isZeroerType):
352+
isZero = func(va reflect.Value) bool {
353+
// Avoid panics calling IsZero on nil pointer.
354+
return va.IsNil() || va.Interface().(isZeroer).IsZero()
355+
}
356+
case v.Type().Implements(isZeroerType):
357+
isZero = func(va reflect.Value) bool { return va.Interface().(isZeroer).IsZero() }
358+
case reflect.PointerTo(v.Type()).Implements(isZeroerType):
359+
isZero = func(va reflect.Value) bool { return va.Addr().Interface().(isZeroer).IsZero() }
337360
}
338-
return v.IsZero()
361+
362+
return (isZero == nil && v.IsZero() || (isZero != nil && isZero(v)))
339363
}
340364

341365
func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {

src/encoding/json/encode_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ func (nzs NonZeroStruct) IsZero() bool {
7777
return false
7878
}
7979

80+
type NoPanicStruct struct {
81+
Int int `json:"int,omitzero"`
82+
}
83+
84+
func (nps *NoPanicStruct) IsZero() bool {
85+
return nps.Int == 0
86+
}
87+
8088
type OptionalsZero struct {
8189
Sr string `json:"sr"`
8290
So string `json:"so,omitzero"`
@@ -106,6 +114,12 @@ type OptionalsZero struct {
106114

107115
Time time.Time `json:"time,omitzero"`
108116
Nzs NonZeroStruct `json:"nzs,omitzero"`
117+
118+
IsZeroer interface {
119+
IsZero() bool
120+
} `json:"iszeroer,omitzero"`
121+
NoPanicStruct1 *NoPanicStruct `json:"nps1,omitzero"`
122+
NoPanicStruct2 NoPanicStruct `json:"nps2,omitzero"`
109123
}
110124

111125
func TestOmitZero(t *testing.T) {

0 commit comments

Comments
 (0)