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设置进这个对象中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452323.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Abap与eCharts

一,简介 利用html与eCharts来绘图,然后用cl_gui_html_viewer将html呈现到abap屏幕中。 二,使用eCharts画图 在一个文件夹中准备如下文件,index.html和echarts.js是必须的,data.json(作为数据源)和jquery.js如果用到就可…

Git快速入门+常用指令+提交规范

目录 Git创建本地仓库 IDEA集成Git Git和IDEA连接使用2 忽略文件 本地仓库常用命令 远程仓库常用命令 分支常用命令 标签操作 提交规范 Git创建本地仓库 1、创建一个文件夹,右键选择Git Bash Here 2、选择下列其中一个方法 方法一:创建初始化…

同济大学|高等数学|第八版|习题1-2

同济大学|高等数学|第八版|习题1-2|2.1 同济大学|高等数学|第八版|习题1-2|2.2 同济大学|高等数学|第八版|习题1-2|2.3 同济大学&…

【Linux进程间通信】匿名管道

【Linux进程间通信】匿名管道 目录 【Linux进程间通信】匿名管道进程间通信介绍进程间通信目的进程间通信发展进程间通信分类 管道用fork来共享管道原理站在文件描述符角度——深度理解管道站在内核角度——管道本质 匿名管道在myshell中添加管道的实现:管道读写规则…

从0到1学Binder-环境准备

前言 终于要开始啃 binder 了,其实还没准备好,但是先走出去吧,目标是 2024 年一个整年能把 binder 学完。 我的微信公众号“ZZH的Android”,还有更多 Android 系统源码解析的干货文章等着你。 1 环境配置 Ubuntu 22.04 Cuttl…

1997-2022年中央对各省份一般公共预算转移支付数据

1997-2022年中央对各省份一般公共预算转移支付数据 1、时间:1997-2022年 2、范围:31省 3、指标:一般公共预算转移支付 4、来源:wind 财政部 5、指标解释:一般性转移支付又称体制性转移支付,是指上级政…

【考研408】计算机网络笔记

文章目录 计算机网络体系结构计算机网络概述计算机网络的组成计算机网络的功能计算机网络的分类计算机网络的性能指标课后习题 计算机网络体系结构与参考模型计算机网络协议、接口、服务的概念ISO/OSI参考模型和TCP/IP模型课后习题 物理层通信基础基本概念奈奎斯特定理与香农定…

[Python] 什么是逻辑回归模型?使用scikit-learn中的LogisticRegression来解决乳腺癌数据集上的二分类问题

什么是线性回归和逻辑回归? 线性回归是一种用于解决回归问题的统计模型。它通过建立自变量(或特征)与因变量之间的线性关系来预测连续数值的输出。线性回归的目标是找到一条直线(或超平面),使得预测值与观…

WordPress Plugin HTML5 Video Player SQL注入漏洞复现(CVE-2024-1061)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 0x02 漏洞概述 WordPress Plugin HTML5 Video Player 插件 get_v…

vue3+threejs+koa可视化项目——模型文件上传(第四步)

文章目录 ⭐前言💖往期node系列文章💖threejs系列相关文章💖vue3threejs系列 ⭐koa后端文件上传(koa-body)💖自动创建目录💖自定义目录上传💖apifox自测上传接口 ⭐vue3前端上传模型文件💖 axio…

CHS_09.2.3.6_2+多生产者-多消费者

CHS_09.2.3.6_2多生产者-多消费者 问题描述问题分析如何实现如何实现假如我们把盘子的容量设为二知识回顾 在这个小节中 我们会学习一个多生产者 多消费者的这样一个问题模型 问题描述 先来看一下问题的描述 假设桌子上面有一个盘子 每次只能向这个盘子里放一个水果 有四个人…

Matomo 访问图形显示异常

近期我们的把 PHP 系统完全升级后,访问 Matomo 的站点有关访问的曲线无法显示。 出现的情况如下图: 我们可以看到图片中有关的访问曲线无法显示。 如果具体直接访问链接的话,会有下面的错误信息。 问题和解决 出现上面问题的原因是缺少 ph…