I have a generated type A
,
I want to json.Marshal
the type and to ignore any empty fields while testing.
The generated type comes without json:",omitempty"
for any struct fields, nor would I want to for purposes of the application itself.
What would be the best way to marshal my type without providing empty fields?
Cheers!
The simples way is crate new type for testing with the same field as A
and use one in tests:
type A struct {
Val string `json:"val"`
Val2 int `json:"val2"`
}
type testA struct {
Val string `json:"val,omitempty"`
Val2 int `json:"val2,omitempty"`
}
func Test(t *testing.T) {
a := A{
Val: "some",
Val2: 0,
}
t.Run("cast", func(t *testing.T) {
ab, _ := json.Marshal(a)
t.Log(string(ab))
ab, _ = json.Marshal(testA(a))
t.Log(string(ab))
})
}
=== RUN Test
=== RUN Test/cust
some_test.go:26: {"val":"some","val2":0}
some_test.go:28: {"val":"some"}
--- PASS: Test (0.00s)
--- PASS: Test/cust (0.00s)
Other way is creating new type base on A
, implements Marshaler for new type and create struct with the same fields and tags (with omitempty
) dynamically use reflect package:
type testAV2 A
func (u testAV2) MarshalJSON() ([]byte, error) {
value := reflect.ValueOf(u)
t := value.Type()
sf := make([]reflect.StructField, 0)
// modify the 'fori' snippet for more complicated cases
for i := 0; i < t.NumField(); i++ {
sf = append(sf, t.Field(i))
tag := t.Field(i).Tag
if !strings.Contains(string(tag), ",omitempty") {
r := regexp.MustCompile(`json:"\s*(.*?)\s*"`)
matches := r.FindAllStringSubmatch(string(tag), -1)
for _, v := range matches {
tagKey := v[1]
sf[i].Tag = reflect.StructTag(fmt.Sprintf(`json:"%s,omitempty"`, tagKey))
}
}
}
newType := reflect.StructOf(sf)
newValue := value.Convert(newType)
return json.Marshal(newValue.Interface())
}