带有omitempty json tag的结构体序列化

不知道大家在使用go实现rpc服务的时候有没有这样的困惑,因为pb文件生成的桩代码中,是自动附带 omitempty json tag的,因此我们在序列化结构体时,如果某个字段的值是零值,则会导致序列化后的字符串不存在这个字段,而这个时候如果下游服务对反序列化要求比较严格,则会出现字段缺失的问题。或者直接访问这个字段,例如在Python中,我们很可能这样写:

response = requests.post(url, headers=headers, data=json.dumps(data))
result = response.json()
value = result["key"]

这样会出现异常:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'key'

比如下面的例子:

package main

import (
	"encoding/json"
	"fmt"
)

type data struct {
	X string `json:"x,omitempty"`
	Y string `json:"y"`
}

func main() {
	d0 := &data{
		X: "x",
		Y: "y",
	}
	d1 := &data{}
	sd0, _ := json.Marshal(d0)
	sd1, _ := json.Marshal(d1)
	fmt.Println(string(sd0), string(sd1))
}

这里打印的结果为:

{"x":"x","y":"y"} {"y":""}

由于 data.Y 使用了 omitemty json tag,导致当 data.Y 为空时,序列化后的字符串不会含有字段 Y

为了解决上面的问题,我们引入第三方sdk:

package main

import (
	"fmt"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
	"github.com/modern-go/reflect2"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

type data struct {
	X string `json:"x,omitempty"`
	Y string `json:"y"`
}

func main() {
	d0 := &data{
		X: "x",
		Y: "y",
	}
	d1 := &data{}
	sd0, _ := json.Marshal(d0)
	sd1, _ := json.Marshal(d1)
	fmt.Println(string(sd0), string(sd1))
}

type NotOmitemptyValEncoder struct {
	encoder jsoniter.ValEncoder
}

func (codec *NotOmitemptyValEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
	codec.encoder.Encode(ptr, stream)
}

func (codec *NotOmitemptyValEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	return false
}

type NotOmitemptyEncoderExtension struct {
	jsoniter.DummyExtension
}

func (extension *NotOmitemptyEncoderExtension) DecorateEncoder(typ reflect2.Type, encoder jsoniter.ValEncoder) jsoniter.ValEncoder {
	return &NotOmitemptyValEncoder{encoder: encoder}
}

func init() {
	jsoniter.RegisterExtension(new(NotOmitemptyEncoderExtension))
}

执行链接在这里,打印的结果为:

{"x":"x","y":"y"} {"x":"","y":""}

可以看到符合预期,所有的字段都序列化出来了。

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值