Reputation: 551
I have a rather unusual situation. I want MarshalJSON to conditionally omit a struct field. In the example below, the idea is to omit output of the B Bool
field if B.Value == B.Undefined
.
type Bool struct {
// Current value
Value bool
// Value if undefined
Undefined bool
}
func (b Bool) MarshalJSON() ([]byte, error) {
if b.Value == b.Undefined {
return []byte{}, nil
} else if b.Value {
return ([]byte)("true"), nil
}
return ([]byte)("false"), nil
}
func main() {
var example = struct {
N int `json:"foo"`
B Bool `json:"value,omitempty"`
}
example.B = Bool{true, true}
output, err := json.Marshal(example)
if err != nil {
panic(err)
}
fmt.Println(string(output))
}
According to the docs:
The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.
I return an empty byte slice, which results in an error:
panic: json: error calling MarshalJSON for type main.Bool: unexpected end of JSON input
goroutine 1 [running]:
main.main()
/tmp/sandbox933539113/prog.go:32 +0x160
If I set example.B = Bool{false, true}
, then it prints the result, but the field still isn't omitted, despite returning "false"
from Bool.MarshalJSON
. What am I doing wrong? Does a value with a type satisfying the Marshaler
interface effectively ignore the omitempty tag entry?
Upvotes: 0
Views: 903
Reputation: 79674
if b.Value == b.Undefined {
return []byte{}, nil
produces invalid JSON: it returns 0 bytes. Your MarshalJSON
method must return valid JSON, which means it must return something.
If your goal is to omit that field entirely, when it's not set, use a pointer, and don't set it:
func main() {
var example = struct {
N int `json:"foo"`
B *Bool `json:"value,omitempty"`
}
example.B = Bool{N: true, B: nil}
output, err := json.Marshal(example)
if err != nil {
panic(err)
}
fmt.Println(string(output))
}
If you want to omit that field entirely when the value of Bool
is a particular value, then you must define your MarshalJSON
method on the containing struct, so that it can properly omit the field when desired.
Upvotes: 5