Thats because they aren't empty.. You are setting them to 0/false. 0/false doesn't mean that they aren't there, you've given then a space in memory by assigning them a value.
package main
import (
"encoding/json"
"fmt"
)
type Foo struct {
Bar Bar `json:"bar,omitempty"`
A *int `json:"a,omitempty"` //Does not get omitted when a = 0
B *bool `json:"b,omitempty"` //Does not get omitted when b = false
}
type Bar struct {
X *int `json:"x,omitempty"` //Gets omitted when x = 0
Y *bool `json:"y,omitempty"` //Gets omitted when y = false
}
func main() {
var obj Foo
a := 0 // a will not be not empty, it's set to 0
obj.A = &a
b, _ := json.MarshalIndent(obj, "", " ")
fmt.Println(string(b))
var obj2 Foo
// a and everything else will be empty, nothing is set
b, _ = json.MarshalIndent(obj2, "", " ")
fmt.Println(string(b))
}
From the documentation
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.
The wording could be better, but empty in this case means that nothing has been assigned to that field. It doesn't mean if the field is literally set to 0 or false it will be empty. False and 0 are values as well and if you assign them then the field becomes 0 or false.