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