golang jsoniter extension怎么处理动态字段
这篇文章主要讲解了“golang jsoniter extension怎么处理动态字段”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“golang jsoniter extension怎么处理动态字段”吧!
1. 背景
golang 原生 json 包,在处理 json 对象的字段的时候,是需要严格匹配类型的。但是,实际上,当我们与一些老系统或者脚本语言的系统对接的时候,有时候需要对类型需要做一下兼容,假设我们有以下需求
目标类型 | 输入 | 解析后 | |
---|---|---|---|
int | int, string | 123, “123” | 123 |
string | int, string | 123, “123” | “123” |
time | unix_seconds, RFC3339 | 1680676884, “2023-04-05T14:41:24Z”, | “2023-04-05T14:41:24Z” |
2. 可选项
我们以 time 作为一个样例
包装类,然后重新实现 Unmarshal 接口
type MyTime struct { t time.Time }
功能可以实现,但是如果使用的地方很多的情况下,就可能要改动多处
,而且,这是全局级别
的,可能会影响到很多包的行为
使用 jsonter 的 extension 实现
jsoniter 的插件文档参考
我们使用实例级别的 extension, 而非全局,可以针对不同业务逻辑有所区分
package main import ( "fmt" "reflect" "strconv" "time" "unsafe" jsoniter "github.com/json-iterator/go" "github.com/modern-go/reflect2" ) type sampleExtension struct { jsoniter.DummyExtension } type wrapEncoder struct { encodeFunc func(ptr unsafe.Pointer, stream *jsoniter.Stream) isEmptyFunc func(ptr unsafe.Pointer) bool decodeFunc func(ptr unsafe.Pointer, iter *jsoniter.Iterator) } func (enc *wrapEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { enc.encodeFunc(ptr, stream) } func (codec *wrapEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { codec.decodeFunc(ptr, iter) } func (enc *wrapEncoder) IsEmpty(ptr unsafe.Pointer) bool { if enc.isEmptyFunc == nil { return false } return enc.isEmptyFunc(ptr) } // 这里统一改用 unix seconds 进行输出 func (e *sampleExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder { if typ.Kind() == reflect.Struct && typ.Type1().PkgPath() == "time" && typ.String() == "time.Time" { return &wrapEncoder{ func(ptr unsafe.Pointer, stream *jsoniter.Stream) { t := *(*time.Time)(ptr) data := strconv.Itoa(int(t.Unix())) stream.WriteRaw(data) }, nil, nil, } } return nil } func (e *sampleExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder { if typ.Kind() == reflect.Struct && typ.Type1().PkgPath() == "time" && typ.String() == "time.Time" { return &wrapEncoder{ decodeFunc: func(ptr unsafe.Pointer, iter *jsoniter.Iterator) { switch iter.WhatIsNext() { case jsoniter.NumberValue: // 兼容 unix 数字解析 timeUnix := iter.ReadInt() newTime := time.Unix(int64(timeUnix), 0) *(*time.Time)(ptr) = newTime case jsoniter.NilValue: iter.Skip() case jsoniter.StringValue: timeStr := iter.ReadString() newTime, err := time.Parse(time.RFC3339, timeStr) if err != nil { fmt.Println("Unmarshal err", err) } *(*time.Time)(ptr) = newTime } }, } } return nil } type Person struct { Birth time.Time `json:"birth"` } func main() { extension := &sampleExtension{} jsoniterAPI := jsoniter.Config{}.Froze() jsoniterAPI.RegisterExtension(extension) var p1 = Person{ Birth: time.Now(), } j, err := jsoniterAPI.MarshalToString(p1) if err != nil { panic(err) } fmt.Println(j) var p2 Person err = jsoniterAPI.Unmarshal([]byte(`{"birth": 1680254527}`), &p2) if err != nil { panic(err) } fmt.Println("p2", p2) var p3 Person err = jsoniterAPI.Unmarshal([]byte(`{"birth": "2023-03-21T07:20:04+00:00"}`), &p3) if err != nil { panic(err) } fmt.Println("p3", p3) var p4 Person err = jsoniterAPI.Unmarshal([]byte(`{"birth": null}`), &p4) if err != nil { panic(err) } fmt.Println("p4", p4) }
我们在例子中,实现了:
把 p1 使用了 unix 数字进行序列化
在反序列化 p2/p3/p4的时候,兼容了
字符串/数字/null
感谢各位的阅读,以上就是“golang jsoniter extension怎么处理动态字段”的内容了,经过本文的学习后,相信大家对golang jsoniter extension怎么处理动态字段这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是蜗牛博客,小编将为大家推送更多相关知识点的文章,欢迎关注!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。版权声明:如无特殊标注,文章均为本站原创,转载时请以链接形式注明文章出处。
评论