golang jsoniter extension 处理动态字段的实现方法
作者:皿小草 发布时间:2024-02-10 09:43:17
标签:go,json,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
来源:https://blog.csdn.net/oqqYuan1234567890/article/details/129970519


猜你喜欢
- 例如我们有如下结构的文件:pkg/ __init__.py libs/ some_lib.py __init__.py components
- 本文实例为大家分享了python可视化动态CPU性能监控的具体代码,供大家参考,具体内容如下打算开发web性能监控,以后会去学js,现在用m
- 如下所示:#!/usr/bin/env python# -*- coding:utf-8 -*-import datetimetime_de
- 本文实例为大家分享了python图形用户接口实例的具体代码,供大家参考,具体内容如下运用tkinter图形库,模拟聊天应用界面,实现信息发送
- 目录前后端传输数据的编码格式Ajax提交urlencoded格式数据Ajax通过FormData上传文件Ajax提交Json格式数据Ajax
- 107条javascript(js)常用的方法技巧,十分的实用,相信看了下面的这些js编程技巧和方法,能够给javascript初学者解决很
- 今天我们用python和python的工具包pygame来编写一个贪吃蛇的小游戏贪吃蛇游戏功能介绍贪吃蛇的游戏规则如下:通过上下左右键或者W
- 相信很多人都跟小编一样不管是什么账号,如果很久不用就会忘记登录密码,像数据库SQL Server2008也一样有用户名和登录密码,下面小编就
- 运行一段程序,警告:service/mysqlconfig.go:63::error: golang.guazi-corp.com/tool
- 昨天刚刚发表了一个前端跨域新方案尝试,今天在开发中就遇到的了问题。起因前端使用的是vue-router组件的history模式,但是由于我们
- 上一篇博客介绍了 如何使用Python,OpenCV上下左右(或任意组合)平移图像。这篇博客将介绍如何使用OpenCV旋转图像任意角度。并演
- 本文实例讲述了Python读取properties配置文件操作。分享给大家供大家参考,具体如下:工作需要将Java项目的逻辑改为python
- 本文实例讲述了Python实现的NN神经网络算法。分享给大家供大家参考,具体如下:参考自Github开源代码:https://github.
- 点工具栏中〔显示估计的查询计划〕,结果提示Documents and Settings\XXX\Local Settings\Temp\1\
- 昨天在用用Pycharm读取一个200+M的CSV的过程中,竟然出现了Memory Error!简直让我怀疑自己买了个假电脑,毕竟是8G内存
- CKeditor是目前最优秀的可见即可得网页编辑器之一,它采用JavaScript编写。具备功能强大、配置容易、跨浏览器、支持多种编程语言、
- 一、 什么是遗传算法?遗传算法是仿真生物遗传学和自然选择机理,通过人工方式所构造的一类搜索算法,从某种程度上说遗传算法是对生物进化过程进行的
- 本文实例为大家分享了opencv实现答题卡识别的具体代码,供大家参考,具体内容如下"""识别答题卡"
- 这篇文章是入门级别的应用Python + Selenium进行自动化测试,包括环境搭建及简单的实例。基本思想是用Firefox Seleni
- ASP中RegExp是什么 '名字字符检验Public Function CheckName(Str) &nbs