如何在结构体字段上不遗漏JSON编组

busg9geu  于 2023-10-21  发布在  其他
关注(0)|答案(1)|浏览(84)

我有一个生成的类型A
我想json.Marshal类型,并忽略任何空字段,而测试。
生成的类型没有任何结构字段的json:",omitempty",我也不想为了应用程序本身的目的而这样做。
在不提供空字段的情况下封送类型的最佳方法是什么?
干杯!干杯!

monwx1rj

monwx1rj1#

最简单的方法是使用与A相同的字段创建新类型进行测试,并在测试中使用一个:

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)

PLAYGROUND
另一种方法是基于A创建新类型,实现新类型的Marshaler,并动态使用reflect包创建具有相同字段和标记的结构体(使用omitempty):

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())
}

PLAYGROUND

相关问题