当前位置: 首页 > news >正文

Gson源码解读

一,概述

gson作为流行的json工具,笔者使用较多。本文主要目的是解读下Gson的源码实现,就没有然后了。

二,实例

实例如下图所示,笔者简单调用gson的toJson方法获得json字符串,fromJson则从json字符串解析成对应类型实例。

三,源码解读

1,构造方法

在创建gson时,虽说笔者只是简单new了一个Gson,但其内部初始化过程还是很多的,笔者看下。

可以看到,Gson构造方法默认了许多参数,我们看下真正的构造方法参数,

笔者简单介绍下各个参数的意思,

(1)excluder:此类选择要省略的字段和类型,如根据修饰符等。

(2)fieldNamingStrategy:将Gson配置为在序列化和反序列化期间将特定的命名策略应用于对象的字段。

(3)instanceCreators:自定义Type类型的实例生成器的Map。

(4)serializeNulls:是否支持序列化null字段。

(5)generateNonExecutableJson:通过在生成的JSON前面加一些特殊文本,使输出的JSON在Javascript中不可执行

(6)complexMapKeySerialization:如果映射键是序列化JSON形式的复杂类型(即非基元),则启用此功能只会更改序列化形式。

(7)longSerializationPolicy:将Gson配置为对长对象和长对象应用特定的序列化策略。

(8)objectToNumberStrategy:将Gson配置为在对象的反序列化过程中应用特定的数字策略。

(9)numberToNumberStrategy:将Gson配置为在number的反序列化过程中应用特定的数字策略。

(10)prettyPrinting:将Gson配置为输出适合页面进行漂亮打印的Json。此选项仅影响Json序列化。

(11)lenient:将Gson配置为允许不严格遵守JSON规范的JSON数据。

(12)escapeHtmlChars:默认情况下,Gson转义HTML字符,如<>等。使用此选项可将Gson配置为按原样传递HTML字符。

(13)datePattern:将Gson配置为根据提供的模式序列化Date对象。可以多次调用此方法或setDateFormat(int),但只有最后一次调用才会用于决定序列化格式。

(14)builderFactories:配置Gson以进行自定义序列化或反序列化。

(15)serializeSpecialFloatingPointValues:特殊浮点数处理策略,(NaN,Infinity,-Infinity)。

(16)useJdkUnsafe:禁止使用JDK的sun.msc.Unsafe。

(17)reflectionFilters:添加反射访问筛选器。反射访问筛选器阻止Gson使用反射对某些类进行序列化和反序列化。筛选器中的逻辑指定这些是哪些类。

读者可自行了解默认参数。

笔者通过对Gson构造方法参数解读,发现Gson采用了适配器设计模式和策略设计模式,便于后续扩展,记录一下。

接下来,笔者看下一些核心接口的定义。

2,InstanceCreator

根据type创建实例。

3,TypeAdapterFactory

根据type返回对应TypeAdapter,

4,TypeAdapter

TypeAdapter是一个抽象类,抽象方法有两个,如下,

这提供了对应TypeAdapter的序列化和反序列化操作。众所周知,Gson内置了许多TypeAdapter类,笔者简单看下,

在Gson构造方法中,factories内置了一些TypeAdapterFactory,看下,

有byte、short、char、int、long、double、float、uri、uuid、url、原子类等。笔者重点介绍下最后添加的ReflectiveTypeAdapterFactory,即所有object序列化/反序列化策略默认反射方式。我们看下ReflectiveTypeAdapterFactory的create方法,

如果是record类,则返回record适配器。否则,返回FieldReflectionAdapter。FieldReflectionAdapter继承ReflectiveTypeAdapterFactory$Adapter,跟进看下read方法,

核心是通过BoundField去遍历对象所有field,读取值或者写入值。

read中提供了三个抽象方法,如下

createAccmulator,笔者理解这是创建对象接口。

readField在反序列化时将值反射进对象中。

笔者跟进write中

核心仍是遍历Field,通过BoundField写入值到json中。

这里笔者了解到BoundField,跟进看下。

其唯一实现在ReflectiveTypeAdapterFactory#createBoundField方法中,

不多跟了,笔者下文看toJson实现。

5,toJson

创建了一个StringWriter,跟进toJson,

这里创建了一个JsonWriter,跟进toJson。

这里根据type类型获取一个Adapter,如果是java基本类型,这里就是基本类型的适配器。如果不是,且没有添加对应的适配器,那么就使用反射Adapter,即ReflectiveTypeAdapterFactory$FieldReflectionAdapter。

最重要的是获取到FieldReflectionAdapter中BoundFields,笔者跟进getBoundFields看下,

通过getDeclaredFields方法获取所有fields,遍历,

(1)对每个field,通过getFieldName获得序列化名,

如果没有@SerializedName注解,通过fieldNamingPolicy策略去获取名字,否则通过注解内容获取。注意返回的是个list,意思是一个field可以有多个别名,然后分别创建BoundField对象。

回到正轨,跟进createBoundField,但在跟进之前,注意到fieldType,这个是什么呢?笔者提醒读者,Gson支持解析简单泛型,而java是泛型擦除的,怎么拿到的呢?

笔者为了搞明白这个问题,准备通过调试看看,

如笔者所见,返回了一个ParameterizedTypeImpl,其存在一个方法,可以返回实际泛型对象,但注意这是参数化Type才拥有。而Field#getGenericType,如果是泛型Field,就能返回一个ParameterizedTypeImpl,感兴趣的读者可自行了解。

笔者继续跟进$Gson$Types.resolve方法,

因此,泛型信息看来不是完全擦除了。

回到正轨,跟进createBoundField。简单将fieldType(ParameterizedTypeImpl),field,name,以及一些策略保存到BoundField中,随后就能完成一个Bean的序列化了。

6,fromJson

笔者从toJson知道,参数化的Type可以保存一些泛型信息,如笔者验证

ok,这不是重点,我们跟进,fromJson。

创建一个StringReader,传入json,跟进fromJson,

拿到adapter,解析,直接看反射适配器,

通过creatAccumulator创建对象,通过JsonReader#nextName方法读取。默认创建对象工厂是Gson构造方法中构建的,笔者看下,

先从instanceCreators或获取构造器,如果没有则通过反射创建一个默认对象,笔者不细跟踪了。最后将field设置进这个对象中。

相关文章:

  • 自动化报告pptx-python|高效通过PPT模版制造报告(三)
  • Jupyter Notebook中的%matplotlib inline详解
  • A系统数据表同步到B系统数据表
  • 2.6作业
  • Java持久化机制和实现的过程
  • 电商推荐系统
  • LabVIEW高精度微小电容测量
  • Django通过Json配置文件分配多个定时任务
  • re:从0开始的CSS学习之路 2. 选择器超长大合集
  • 【数据结构和算法】--- 基于c语言排序算法的实现(1)
  • (篇九)MySQL常用内置函数
  • ffmpeg 时间裁剪之-ss -t与滤镜中trim=start=*:duration=*的区别和联系
  • HTTP中传输协议的数据格式
  • 数字化时代下如何做好事件营销?
  • 市场复盘总结 20240206
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 【Amaple教程】5. 插件
  • 345-反转字符串中的元音字母
  • const let
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Java 最常见的 200+ 面试题:面试必备
  • Leetcode 27 Remove Element
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • vue学习系列(二)vue-cli
  • Vue组件定义
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 试着探索高并发下的系统架构面貌
  • 小李飞刀:SQL题目刷起来!
  • 追踪解析 FutureTask 源码
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 说说我为什么看好Spring Cloud Alibaba
  • 正则表达式-基础知识Review
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • ###C语言程序设计-----C语言学习(6)#
  • (07)Hive——窗口函数详解
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (libusb) usb口自动刷新
  • (WSI分类)WSI分类文献小综述 2024
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (强烈推荐)移动端音视频从零到上手(下)
  • (一)kafka实战——kafka源码编译启动
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (译)2019年前端性能优化清单 — 下篇
  • (转)甲方乙方——赵民谈找工作
  • *** 2003
  • **python多态
  • *1 计算机基础和操作系统基础及几大协议
  • .htaccess 强制https 单独排除某个目录
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .Net 代码性能 - (1)
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET/C# 的字符串暂存池
  • .NET4.0并行计算技术基础(1)