有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
源码地址:https://gitee.com/pearl-organization/study-jaskson-demo
1. 前言
Jackson
三大核心模块支持标准的JDK
类和自定义Java Bean
对象和Json
之间的互相转换,当需要扩展以支持其他数据类型时,可以使用Module
构建自定义的模块并注册到ObjectMapper
中。
Jackson
已经提供了多个扩展模块,在Jackson 2.x 系列【1】概述中已经有讲述过,接下来讲解Module
并实现注册自定义模块。
2. 核心类
2.1 Module
Module
抽象类用于在ObjectMapper
中注册扩展,提供了一套定义良好的扩展功能,例如对新数据类型的支持、自定义的序列化/反序列化逻辑等。
定义了三个方法,用于返回模块名称、版本、类型ID
,这些模块的基础信息是必须可少的,在实现抽象类时,需要提供这些信息:
java
public abstract String getModuleName();
@Override
public abstract Version version();
public Object getTypeId() {
return getClass().getName();
}
Module
包含了一个SetupContext
内部接口,一般由ObjectMapper
去实现并调用setupModule
方法执行真正的注册逻辑:
java
public abstract void setupModule(SetupContext context);
public static interface SetupContext
{
// 省略...........
2.2 SimpleModule
SimpleModule
是Module
的默认实现,提供了注册序列化/反序列化器、Bean
序列化/反序列化器修饰器、子类型、Mixin
等功能,也可添加自定义的AbstractTypeResolver
、ValueInstantiator
。在创建自定义模块时,可以直接使用或者继承该类来实现。
注意事项:
- 注册的序列化器和反序列化器都会被作为默认的,优先级会低于注解指定的
- 子类实现中,不推荐重写
#setupModule(SetupContext)
,如果重写了必须调用super.setupModule(context)
确保注册操作能够正常执行 - 在注册
JsonSerializer
、JsonDeserializer
时,仅比较类型擦除后的Class
,所有泛型参数不要使用Collection
、Map
等结构化的类型,不然处理时会抛出异常
SimpleModule
包含了多个成员属性:
java
// 名称
protected final String _name;
// 版本
protected final Version _version;
// 序列化器/反序列化器
protected SimpleSerializers _serializers = null;
protected SimpleDeserializers _deserializers = null;
// Key 序列化器/反序列化器
protected SimpleSerializers _keySerializers = null;
protected SimpleKeyDeserializers _keyDeserializers = null;
// Bean 序列化/反序列化装饰器
protected BeanDeserializerModifier _deserializerModifier = null;
protected BeanSerializerModifier _serializerModifier = null
提供了多个添加注册内容的方法:
3. 案例演示
3.1 自定义模块
在创建自定义模块时,可以直接使用SimpleModule
创建,或者继承来实现。
例如直接创建:
java
// 创建版本
Version version = VersionUtil.parseVersion("1.0.0", "com.pearl", "jackson-datatype-my");
// 创建模块
SimpleModule myModule = new SimpleModule("myModule", version);
// 添加序列化器/反序列化器
myModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
myModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
例如继承实现:
java
public class MyModule extends SimpleModule {
private static final long serialVersionUID = 1L;
public static final Version VERSION = VersionUtil.parseVersion("1.0.0", "com.pearl", "jackson-datatype-my");
public MyModule() {
super("myModule",VERSION);
}
public void setupModule(Module.SetupContext context) {
// 必须调用父类的
super.setupModule(context);
// 添加序列化器
SimpleDeserializers desers = new SimpleDeserializers();
desers.addDeserializer(ZoneOffset.class, JSR310StringParsableDeserializer.ZONE_OFFSET);
context.addDeserializers(desers);
// 添加反序列化器
SimpleSerializers sers = new SimpleSerializers();
sers.addSerializer(ZoneOffset.class, new ToStringSerializer(ZoneOffset.class));
context.addSerializers(sers);
}
}
3.2 注册
3.2.1 API
ObjectMapper
提供了多种注册模块的方法:
java
public ObjectMapper registerModule(Module module);
public ObjectMapper registerModules(Module... modules) ;
public ObjectMapper registerModules(Iterable<? extends Module> modules) ;
代码示例:
java
ObjectMapper objectMapper = new ObjectMapper();
// 创建版本
Version version = VersionUtil.parseVersion("1.0.0", "com.pearl", "jackson-datatype-my");
// 创建模块
SimpleModule myModule = new SimpleModule("myModule", version);
// 添加序列化器/反序列化器
myModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
myModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// 注册
objectMapper.registerModule(myModule);
3.2.2 SPI
Jackson
也提供了SPI
的方式进行注册,适用于独立的第三方模块,例如jackson-datatype-jsr310
就是使用的这种方式。
示例,Idea
创建一个模块,使用SPI
机制加载自定义模块类: 其他项目引入该模块:
xml
<dependency>
<groupId>com.example</groupId>
<artifactId>jackson-datatype-my</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
查询所有注册的模块:
java
objectMapper.findAndRegisterModules();// SPI发现并注册
Set<Object> moduleIds = objectMapper.getRegisteredModuleIds();
System.out.println(moduleIds);
输出如下:
java
[jackson-datatype-jsr310, myModule]
3.3 查询
ObjectMapper
提供了两个静态方法用于查询注册的模块对象:
java
public static List<Module> findModules() ;
public static List<Module> findModules(ClassLoader classLoader) ;
查询结果如下: