golang jsoniter extension 处理动态字段的实现方法

作者:皿小草 时间:2024-02-10 09:43:17 

1. 背景

golang 原生 json 包,在处理 json 对象的字段的时候,是需要严格匹配类型的。但是,实际上,当我们与一些老系统或者脚本语言的系统对接的时候,有时候需要对类型需要做一下兼容,假设我们有以下需求


目标类型输入解析后
intint, string123, “123”123
stringint, string123, “123”“123”
timeunix_seconds, RFC33391680676884, “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

来源:https://blog.csdn.net/oqqYuan1234567890/article/details/129970519

标签:go,json,jsoniter,extension,动态字段
0
投稿

猜你喜欢

  • matplotlib图形整合之多个子图绘制的实例代码

    2023-10-23 23:17:47
  • Python用list或dict字段模式读取文件的方法

    2022-07-16 18:29:07
  • python利用urllib实现爬取京东网站商品图片的爬虫实例

    2022-05-01 12:32:56
  • Python PyQt5-图形界面的美化操作

    2023-11-08 23:04:34
  • ASP.NET Core中的静态文件

    2024-05-21 10:13:23
  • Django小白教程之Django用户注册与登录

    2022-01-14 10:30:06
  • pyinstaller将含有多个py文件的python程序做成exe

    2021-03-04 21:02:22
  • Python制作脚本帮女朋友抢购清空购物车

    2021-08-30 04:40:01
  • 采用python实现简单QQ单用户机器人的方法

    2022-06-26 03:28:40
  • 解决pandas中读取中文名称的csv文件报错的问题

    2021-08-07 00:53:40
  • Golang实现单链表的示例代码

    2024-02-11 15:09:27
  • Qt操作SQLite数据库的教程详解

    2024-01-16 14:10:04
  • 微信小程序开发之组件设计规范

    2024-04-18 09:35:15
  • Vite版本更新检查实现页面自动刷新的解决思路

    2024-04-27 16:17:07
  • Python Django实现layui风格+django分页功能的例子

    2023-10-07 00:04:28
  • Python基础学习之基本数据结构详解【数字、字符串、列表、元组、集合、字典】

    2021-09-16 17:17:44
  • python实现拼图小游戏

    2023-05-14 14:54:15
  • Mysql 乘法除法精度不一致问题(除法后四位小数)

    2024-01-13 09:44:16
  • XML HttpRequst对象学习

    2007-10-12 19:04:00
  • 基于Python和openCV实现图像的全景拼接详细步骤

    2023-05-30 17:35:07
  • asp之家 网络编程 m.aspxhome.com