有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
源码地址:https://gitee.com/pearl-organization/study-jaskson-demo
1. 概述
Java Bean对象的序列化过程是比较复杂的,因为它可能包含了各种类型的属性,在Jackson中该过程是交由BeanSerializer来负责的。同时Jackson也提供了扩展机制,允许通过BeanSerializerModifier在BeanSerializer的创建过程中进行干预和修改,从而实现对序列化过程的自定义。
2. 抽象方法
BeanSerializerModifier定义了很多抽象的钩子方法。
2.1 changeProperties
changeProperties是最常用的方法的,目的是提供一个钩子,允许用户自定义和调整BeanSerializer序列化过程中使用的属性集合。通过修改这个集合,可以控制哪些属性应该被序列化,哪些应该被忽略,或者替换为其他属性等。
/**
* 自定义和调整 BeanSerializer 序列化过程中使用的属性集合
*
* @param config 序列化配置
* @param beanDesc Bean 对象信息
* @param beanProperties 属性集合
* @return 属性集合
*/
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties) {
return beanProperties;
}
2.2 orderProperties
orderProperties方法看名字就很好理解,允许自定义和调整序列化过程中属性的顺序。
public List<BeanPropertyWriter> orderProperties(SerializationConfig config,
BeanDescription beanDesc,
List<BeanPropertyWriter> beanProperties) {
return beanProperties;
}
2.3 updateBuilder
updateBuilder方法允许在序列化器构建的最后阶段进行自定义修改或替换。
/**
* 序列化器构建的最后阶段进行自定义修改或替换
*
* @param config 序列化配置
* @param beanDesc Bean 对象信息
* @param builder BeanSerializer 构建者
* @return 属性集合
*/
public BeanSerializerBuilder updateBuilder(SerializationConfig config,
BeanDescription beanDesc,
BeanSerializerBuilder builder) {
return builder;
}
2.4 modifyXx
BeanSerializerModifier定义了很多modify开头的方法,在DeserializerFactory根据类型创建了对应的序列化器之后进行调用,允许替换或增强这个反序列化器,为其添加额外的功能。
/**
* 允许在 BeanSerializer 构造完成后对其进行修改或替换。
*
* @param config 序列化配置
* @param beanDesc Bean 对象信息
* @param serializer 序列化器
* @return 序列化器
*/
public JsonSerializer<?> modifySerializer(SerializationConfig config,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* 增强或替换 ArrayType 对应的序列化器
*
* @param config 序列化配置
* @param valueType 类型
* @param beanDesc Bean 对象信息
* @param serializer 序列化器
* @return 序列化器
*/
public JsonSerializer<?> modifyArraySerializer(SerializationConfig config,
ArrayType valueType,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* @since 2.2
*/
public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config,
CollectionType valueType,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* @since 2.2
*/
public JsonSerializer<?> modifyCollectionLikeSerializer(SerializationConfig config,
CollectionLikeType valueType,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* @since 2.2
*/
public JsonSerializer<?> modifyMapSerializer(SerializationConfig config,
MapType valueType,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* @since 2.2
*/
public JsonSerializer<?> modifyMapLikeSerializer(SerializationConfig config,
MapLikeType valueType,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* @since 2.2
*/
public JsonSerializer<?> modifyEnumSerializer(SerializationConfig config,
JavaType valueType,
BeanDescription beanDesc,
JsonSerializer<?> serializer) {
return serializer;
}
/**
* @since 2.2
*/
public JsonSerializer<?> modifyKeySerializer(SerializationConfig config,
JavaType valueType, BeanDescription beanDesc, JsonSerializer<?> serializer) {
return serializer;
}
3. 案例演示
BeanSerializerModifier的功能非常强大,几乎可以自定义很多序列化的骚操作,例如:添加额外字段、更改字段值、自定义序列化器、null值处理、字典翻译、数据脱敏等等....
下面演示一个最简单的需求,修改某个属性序列化的值,其他高级用法后面会单独介绍。当前对象有一个password属性,需要序列化为********显示:
public class UserVO {
Long id;
String username;
// 省略.............
}
3.1 实现
实现BeanSerializerModifier,当存在password属性时,注册一个自定义的JsonSerializer,将值写为********:
public class ModifyPasswordBeanSerializerModifier extends BeanSerializerModifier {
/**
* 自定义和调整 BeanSerializer 序列化过程中使用的属性集合
*
* @param config 序列化配置
* @param beanDesc Bean 对象信息
* @param beanProperties 属性集合
* @return 属性集合
*/
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
System.out.println("changeProperties");
// 查询是否开启某个特征
boolean enabled = config.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES);
// 获取当前Bean 的类型、真实 Class
JavaType javaType = beanDesc.getType();
Class<?> rawClass = javaType.getRawClass();
// 循环所有属性集合
for (BeanPropertyWriter beanPropertyWriter : beanProperties) {
// 属性类型
JavaType type = beanPropertyWriter.getType();
// 属性名称
String name = beanPropertyWriter.getName();
// 属性的序列化器
JsonSerializer<Object> serializer = beanPropertyWriter.getSerializer();
// 属性的类型列化器
TypeSerializer typeSerializer = beanPropertyWriter.getTypeSerializer();
// 是否有Null值序列化器
boolean hasNullSerializer = beanPropertyWriter.hasNullSerializer();
// 获取注解
Annotation annotation = beanPropertyWriter.getAnnotation(JsonSerialize.class);
// 修改字段名称
if("password".equals(name)){
// 当前属性Writer对象,注册自定义的序列化器
beanPropertyWriter.assignSerializer(new JsonSerializer<>() {
@Override
public void serialize(Object value, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
jg.writeString("********");
}
});
}
}
return beanProperties;
}
}
PS:实际开发中,不推荐这么用,这个逻辑是全局的,会作用于所有Java Bean,重点是了解基础用法,这里可以添加自定义注解(后续讲解)。
3.2 注册
可以直接在ObjectMapper对象中注册BeanSerializerModifier:
ObjectMapper objectMapper = new ObjectMapper();
// 创建新的 SerializerFactory,并设置 BeanSerializerModifier
SerializerFactory serializerFactory = objectMapper.getSerializerFactory().withSerializerModifier(new ModifyPasswordBeanSerializerModifier());
// 需要重新设置进去,因为SerializerFactory 是不可变对象
objectMapper.setSerializerFactory(serializerFactory);
也可以新建模块并注册:
// 使用模块注册BeanSerializerModifier:
SimpleModule simpleModule=new SimpleModule("myModule");
simpleModule.setSerializerModifier(new ModifyPasswordBeanSerializerModifier());
objectMapper.registerModule(simpleModule);// 注册模块
3.3 测试
执行序列化操作:
UserVO userVO = new UserVO();
userVO.setId(1699657986705854464L);
userVO.setPassword("123456");
userVO.setUsername("jack");
userVO.setCreateTime(LocalDateTime.now());
String userVoJson = objectMapper.writeValueAsString(userVO);
System.out.println(userVoJson);
可以看到原有的password值被修改了:
changeProperties
{"id":1699657986705854464,"username":"jack","password":"********","createTime":"2024-04-11 14:57:51"}
4. BeanDeserializerModifier
同样也提供了用于反序列化Java Bean对象的扩展机制,也就是BeanDeserializerModifier抽象类,在BeanDeserializer的创建过程中进行干预和修改,从而实现对反序列化过程的自定义。和BeanSerializerModifier用法一致,这里简单提一下,没必要赘述了。
public abstract class BeanDeserializerModifier implements Serializable {
private static final long serialVersionUID = 1L;
public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) {
return propDefs;
}
public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) {
return builder;
}
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyEnumDeserializer(DeserializationConfig config, JavaType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyReferenceDeserializer(DeserializationConfig config, ReferenceType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyArrayDeserializer(DeserializationConfig config, ArrayType valueType, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyCollectionDeserializer(DeserializationConfig config, CollectionType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyCollectionLikeDeserializer(DeserializationConfig config, CollectionLikeType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyMapDeserializer(DeserializationConfig config, MapType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public JsonDeserializer<?> modifyMapLikeDeserializer(DeserializationConfig config, MapLikeType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
public KeyDeserializer modifyKeyDeserializer(DeserializationConfig config, JavaType type, KeyDeserializer deserializer) {
return deserializer;
}
}