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.rhkb.cn/news/252311.html

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

相关文章

无人零售模式下,“IoT+鸿蒙”实现零代码搭建自动售货机监控大屏的可能性摸索

前言 新零售模式下,对loT的探索与应用还在继续。 而数字时代,数字化转型在零售行业中蔓延,而对于新的消费方式的探索,也在如火如荼的进行中。于是,一种新零售的形式——无人零售逐渐形成概念。 如果说,人…

PySpark(四)PySpark SQL、Catalyst优化器、Spark SQL的执行流程

目录 PySpark SQL 基础 SparkSession对象 DataFrame入门 DataFrame构建 DataFrame代码风格 DSL SQL SparkSQL Shuffle 分区数目 DataFrame数据写出 Spark UDF Catalyst优化器 Spark SQL的执行流程 PySpark SQL 基础 PySpark SQL与Hive的异同 Hive和Spark 均是:“分…

掌握CSS网格函数fit-content()的妙用

CSS网格布局是一种强大的布局系统,它提供了灵活的网格化设计能力。其中,fit-content()函数是一项重要的功能,它可以帮助我们在网格容器中自动调整网格项的尺寸。本文将详细讲解fit-content()函数的使用方法及其常见应用场景,助你掌…

【笔记】React Native实战练习(仿网易云游戏网页移动端)

/** * 如果系统看一遍RN相关官方文档,可能很快就忘记了。一味看文档也很枯燥无味, * 于是大概看了关键文档后,想着直接开发一个Demo出来,边学边写,对往后工作 * 开发衔接上能够更顺。这期间肯定会遇到各种各样的问题&a…

12. onnx转为rknn测试时有很多重叠框的修改(python)

我们下载rknn-toolkit2-master后并进行前面的处理后,进入到rknn-toolkit2-master\examples\onnx\yolov5文件夹,里面有个test.py文件,打开该文件,其代码如下: # -*- coding: utf-8 -*- # coding:utf-8import os import…

<.Net>使用visual Studio 2022在VB.net中新添自定义画图函数(优化版)

前言 这是基于我之前的一篇博文: 使用visual Studio 2019在VB.net中新添自定义画图函数 在此基础上,我优化了一下,改进了UI,添加了示例功能,即以画圆函数为基础,添加了走马灯功能。 先看一下最终效果&#…

计算机毕业设计 | SSM 医药信息管理系统(附源码)

1, 概述 1.1 课题背景 本系统由说书客面向广大民营药店、县区级医院、个体诊所等群体的药品和客户等信息的管理需求,采用SpringSpringMVCMybatisEasyui架构实现,为单体药店、批发企业、零售连锁企业,提供有针对性的信息数据管理…

react 之 zustand

zustand可以说是redux的平替 官网地址:https://zustand-demo.pmnd.rs/ 1.安装 npm i zustand2.基础使用 // zustand import { create } from zustand// 1. 创建store // 语法容易出错 // 1. 函数参数必须返回一个对象 对象内部编写状态数据和方法 // 2. set是用来…

23、数据结构/查找相关练习20240205

一、请编程实现哈希表的创建存储数组{12,24,234,234,23,234,23},输入key查找的值&#xff0c;实现查找功能。 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h> #include<math.h> typedef struct Node {int data;struct n…

re:从0开始的CSS学习之路 2. 选择器超长大合集

0. 写在前面 虽然现在还是不到25的青年人&#xff0c;有时仍会感到恐慌&#xff0c;害怕不定的未来&#xff0c;后悔失去的时间&#xff0c;但细细想来&#xff0c;只有自己才知道&#xff0c;再来一次也不会有太多的改变。 CSS的选择器五花八门&#xff0c;而且以后在JavaScr…

2024年了,如何更好的搭建Kafka集群?

Kafka的Kraft模式简单来说就是基于raft协议重新实现了zookeeper的功能。传统的zookeeper集群已经被标记为弃用&#xff0c;将在kafka4.0中完全移除。由于去掉了zk组件&#xff0c;部署也简化了不少。我们基于Kraft模式和Docker Compose同时采用最新版Kafka v3.6.1来搭建集群。 …

【ARM 嵌入式 编译系列 2.7 -- GCC 编译优化参数详细介绍】

请阅读【嵌入式开发学习必备专栏 】 文章目录 GCC 编译优化概述常用优化等级-O1 打开的优化选项-O2 打开的优化选项-O3 打开的优化选项-Os 打开的优化选项优化技术使用优化选项的注意事项GCC 编译优化概述 GCC(GNU Compiler Collection)包含了用于C、C++、Objective-C、Fort…

ubuntu系统下c++ cmakelist vscode debug(带传参的debug)的详细示例

c和cmake的debug&#xff0c;网上很多都需要配置launch.json&#xff0c;cpp.json啥的&#xff0c;记不住也太复杂了&#xff0c;我这里使用cmake插件带有的设置&#xff0c;各位可以看一看啊✌(不知不觉&#xff0c;竟然了解了vscode中配置文件的生效逻辑&#x1f923;) 克隆…

linux中的mtime,ctime,atime

目录 结论 文件 touch新文件 调整文件内容 echo直接修改 vi修改 修改文件属性 调整归属 调整权限 读取文件 目录 增加文件 调整目录下文件属性 访问目录下文件 删除文件 结论 mtime&#xff1a;文件内容的修改时间&#xff08;不含权限、属组修改&#xff09; …

centos7 在线编译安装 CMake 3.5.1 shell脚本

脚本 要在CentOS 7上在线编译安装CMake 3.5.1&#xff0c;你可以使用以下shell脚本作为参考&#xff1a; #!/bin/bash# 设置下载和安装目录 DOWNLOAD_DIR"/tmp/cmake_download" INSTALL_DIR"/opt/cmake"# 创建目录 mkdir -p $DOWNLOAD_DIR mkdir -p $INS…

浅谈QT的几种线程的使用和区别。

简介&#xff1a; 线程是操作系统中的基本执行单元&#xff0c;是一个独立的执行路径。每个线程都有自己的栈空间&#xff0c;用于存储本地变量和函数调用的上下文。多个线程可以在同一进程中并发执行&#xff0c;从而实现并发处理&#xff0c;提高程序的性能和响应能力。 与进…

【Leetcode】1696. 跳跃游戏 VI

文章目录 题目思路代码结果 题目 题目链接 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 一开始你在下标 0 处。每一步&#xff0c;你最多可以往前跳 k 步&#xff0c;但你不能跳出数组的边界。也就是说&#xff0c;你可以从下标 i 跳到 [i 1&#xff0c; min(n -…

【Unity3D小技巧】Unity3D中UI控制解决方案

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 在开发中总是会控制UI界面&#xff0c;如何优雅的控制UI界面是…

3.0 Zookeeper linux 服务端集群搭建步骤

本章节将示范三台 zookeeper 服务端集群搭建步骤。 所需准备工作&#xff0c;创建三台虚拟机环境并安装好 java 开发工具包 JDK&#xff0c;可以使用 VM 或者 vagrantvirtualbox 搭建 centos/ubuntu 环境&#xff0c;本案例基于宿主机 windows10 系统同时使用 vagrantvirtualb…

centos 7.6 安装 openldap 2.5.17

centos 7.6 安装ldap 1、下载ldap2、安装ldap2.1、官方参考文档2.2、安装前准备2.2.1、安装gcc2.2.2、安装Cyrus SASL 2.1.272.2.3、安装OpenSSL 1.1.12.2.3.1、下载openssl 3.02.2.3.2、安装依赖包2.2.3.3、编译安装openssl 3.0 2.2.3、安装libevent 2.1.82.2.4、安装libargon…