我的编程空间,编程开发者的网络收藏夹
学习永远不晚

golangjsoniterextension处理动态字段的实现方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

golangjsoniterextension处理动态字段的实现方法

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

总结

jsoniter 包提供了比较完善的定制能力,通过例子可以感受一下扩展性。后续大家可以根据业务需求发掘更多的能力

到此这篇关于golang jsoniter extension 处理动态字段的文章就介绍到这了,更多相关go动态字段内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

golangjsoniterextension处理动态字段的实现方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

golangjsoniterextension处理动态字段的实现方法

这篇文章主要介绍了golangjsoniterextension处理动态字段的实现方法,我们使用实例级别的extension,而非全局,可以针对不同业务逻辑有所区分,jsoniter包提供了比较完善的定制能力,通过例子可以感受一下扩展性,需要的朋友可以参考下
2023-05-14

mysql之动态增添字段实现方式

这篇文章主要介绍了mysql之动态增添字段实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-05-20

Vue动态组件实现异常处理方法

Vue3动态组件怎么进行异常处理?下面本篇文章带大家聊聊Vue3动态组件异常处理的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2023-02-01

java动态代理的实现方法

这篇文章主要介绍“java动态代理的实现方法”,在日常操作中,相信很多人在java动态代理的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java动态代理的实现方法”的疑惑有所帮助!接下来,请跟着小编
2023-06-20

mybatis动态字段查询的方法是什么

MyBatis提供了动态字段查询的方法,可以根据不同的条件动态选择需要查询的字段。以下是MyBatis中实现动态字段查询的方法:1. 使用``标签实现动态字段查询:```xmlSELECTidname*FROM user```在上述示例中,
2023-09-29

利用java实现动态代理的方法

这篇文章将为大家详细讲解有关利用java实现动态代理的方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java 动态代理的方法总结AOP的拦截功能是由java中的动态代理来实现的。说白了,
2023-05-31

go结构体动态添加字段的方法是什么

在Go语言中,结构体是一种固定字段的数据类型,无法动态添加字段。这是因为Go语言是静态类型语言,所有的变量和字段必须在编译时确定。如果需要在运行时动态添加字段,可以考虑使用map来代替结构体。使用map可以动态添加键值对,相当于动态添加字段
2023-10-10

SpringBoot2动态@Value的实现方法

这篇文章主要介绍“SpringBoot2动态@Value的实现方法”,在日常操作中,相信很多人在SpringBoot2动态@Value的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoo
2023-06-20

Java实现动态代理的方法有哪些

这篇文章将为大家详细讲解有关Java实现动态代理的方法有哪些,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。详解Java动态代理的实现及应用Java动态代理其实写日常业务代码是不常用的,但在框
2023-05-31

dedecms5.7sp1评论添加字段的实现方法

dedecms5.7sp1评论添加字段的解决方法问题,问题得以解决: 实现方法如下: 1,后台:系统—SQL命令运行器 中输入: alter table dede_feedback add column website varc
2022-06-12

java实现动态编译并动态加载的方法

小编给大家分享一下java实现动态编译并动态加载的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在D盘test目录下有个java文件:AlTest.javap
2023-06-14

前方高能 实现PPT动态文字效果的三种方法

  什么?你竟然知道怎么在PPT中怎么制作动态文字效果?这么好玩而且高大上的技能大家怎么能错过呢?今天我们将会讲到三种在PPT中的实现动态文字效果的方法,让大家轻松制作出一个独特而且极具美感的PPT,多学到一项新技能!  首先我们来看一下三种动态文字效果吧!然后小编再给大家逐一讲解不同的动态文字效果的制作方法。。  &
前方高能 实现PPT动态文字效果的三种方法
2024-04-17

Java动态代理的原理及实现方法是什么

本篇内容主要讲解“Java动态代理的原理及实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java动态代理的原理及实现方法是什么”吧!代理是指:某些场景下对象会找一个代理对象,来辅助
2023-07-02

C语言动态内存管理的原理及实现方法

C语言动态内存管理的原理是通过malloc()函数申请一块连续的内存空间,并返回其地址,通过free()函数释放该内存空间。实现方法是通过在程序运行时动态地管理内存,即在需要内存时申请,不需要时释放,避免了静态内存分配的浪费和不足
2023-05-16

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录