PostProcessingBeanDeserializer 使用指南
1. 什么是 PostProcessingBeanDeserializer
PostProcessingBeanDeserializer 是一个自定义的 Jackson 反序列化器,用于在 JSON 反序列化完成后对对象进行后置处理(如数据清洗、字段修正、默认值填充等)。
2. 实现方式
方式一:继承 BeanDeserializerBase 并包装原始反序列化器
java
package com.xiaomi.car.universal.common.config.jackson;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* 后置处理反序列化器
* 在反序列化完成后执行自定义处理逻辑
*/
public class PostProcessingBeanDeserializer extends BeanDeserializer {
public PostProcessingBeanDeserializer(BeanDeserializerBase src) {
super(src);
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// 1. 先执行原始的反序列化
Object bean = super.deserialize(p, ctxt);
// 2. 执行后置处理
if (bean != null) {
postProcess(bean);
}
return bean;
}
/**
* 后置处理方法 - 子类可以重写此方法实现自定义逻辑
*/
protected void postProcess(Object bean) {
// 默认实现:什么都不做
// 子类可以重写此方法实现具体逻辑
}
}
方式二:使用 BeanDeserializerModifier 注册
java
package com.xiaomi.car.universal.common.config.jackson;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.stereotype.Component;
/**
* 自定义反序列化器修改器
*/
@Component
public class CustomBeanDeserializerModifier extends BeanDeserializerModifier {
@Override
public JsonDeserializer<?> modifyDeserializer(
DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
// 只对特定类型进行包装
if (deserializer instanceof BeanDeserializerBase) {
return new PostProcessingBeanDeserializer((BeanDeserializerBase) deserializer) {
@Override
protected void postProcess(Object bean) {
// 在这里实现具体的后置处理逻辑
handlePostProcessing(bean);
}
};
}
return deserializer;
}
/**
* 具体的后置处理逻辑
*/
private void handlePostProcessing(Object bean) {
// 示例1: 字符串字段统一trim
if (bean instanceof StringTrimable) {
trimStringFields(bean);
}
// 示例2: 填充默认值
if (bean instanceof DefaultValueFillable) {
fillDefaultValues(bean);
}
// 示例3: 数据格式转换
if (bean instanceof DataTransformable) {
transformData(bean);
}
}
private void trimStringFields(Object bean) {
// 使用反射或工具类处理字符串字段
// 例如:Apache Commons BeanUtils 或 Spring BeanWrapper
}
private void fillDefaultValues(Object bean) {
// 填充默认值逻辑
}
private void transformData(Object bean) {
// 数据转换逻辑
}
}
3. 配置到 ObjectMapper
方式一:在配置类中注册
java
package com.xiaomi.car.universal.common.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.xiaomi.car.universal.common.config.jackson.CustomBeanDeserializerModifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper(CustomBeanDeserializerModifier modifier) {
ObjectMapper mapper = new ObjectMapper();
// 创建模块并注册修改器
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(modifier);
mapper.registerModule(module);
return mapper;
}
}
方式二:针对特定类型使用
java
package com.xiaomi.car.universal.common.config.jackson;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
/**
* 示例:针对特定DTO使用自定义反序列化器
*/
@JsonDeserialize(using = UserDTODeserializer.class)
public class UserDTO {
private String name;
private String email;
// getters and setters
}
/**
* 自定义反序列化器
*/
class UserDTODeserializer extends JsonDeserializer<UserDTO> {
@Override
public UserDTO deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
// 1. 使用默认反序列化
UserDTO dto = p.getCodec().readValue(p, UserDTO.class);
// 2. 后置处理
if (dto != null) {
// 字符串trim
if (StringUtils.isNotBlank(dto.getName())) {
dto.setName(dto.getName().trim());
}
if (StringUtils.isNotBlank(dto.getEmail())) {
dto.setEmail(dto.getEmail().trim().toLowerCase());
}
}
return dto;
}
}
4. 实际应用场景示例
场景1:字符串字段统一trim
java
public class PostProcessingBeanDeserializer extends BeanDeserializer {
public PostProcessingBeanDeserializer(BeanDeserializerBase src) {
super(src);
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
Object bean = super.deserialize(p, ctxt);
if (bean != null) {
trimStringFields(bean);
}
return bean;
}
private void trimStringFields(Object bean) {
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getType() == String.class) {
field.setAccessible(true);
try {
String value = (String) field.get(bean);
if (value != null) {
field.set(bean, value.trim());
}
} catch (IllegalAccessException e) {
// 忽略
}
}
}
}
}
场景2:空字符串转null
java
@Override
protected void postProcess(Object bean) {
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getType() == String.class) {
field.setAccessible(true);
try {
String value = (String) field.get(bean);
if (value != null && value.isEmpty()) {
field.set(bean, null);
}
} catch (IllegalAccessException e) {
// 忽略
}
}
}
}
场景3:日期格式兼容处理
java
@Override
protected void postProcess(Object bean) {
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getType() == Date.class || field.getType() == LocalDateTime.class) {
// 处理日期字段的兼容性
// 例如:将旧格式转换为新格式
}
}
}
5. 与 @Validated 的区别
| 特性 | PostProcessingBeanDeserializer | @Validated |
|---|---|---|
| 触发时机 | JSON反序列化完成后立即执行 | Spring MVC参数绑定后,方法执行前 |
| 主要作用 | 数据清洗、格式转换、默认值填充 | 数据校验、规则验证 |
| 是否修改数据 | ✅ 可以修改对象数据 | ❌ 只校验,不修改 |
| 作用范围 | 全局(所有使用该ObjectMapper的地方) | 局部(只对加了注解的参数生效) |
| 错误处理 | 可以静默处理或抛出异常 | 统一抛出 MethodArgumentNotValidException |
6. 最佳实践
✅ 推荐使用场景
- 数据清洗:统一trim、空字符串转null
- 格式转换:旧版本JSON格式兼容
- 默认值填充:根据业务规则填充默认值
- 字段映射:将旧字段名映射到新字段名
❌ 不推荐使用场景
- 业务校验 :应该使用
@Validated+ Bean Validation - 复杂业务逻辑:应该在Service层处理
- 数据库操作:不应该在反序列化器中执行
7. 完整示例
java
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(
DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
if (deserializer instanceof BeanDeserializerBase) {
return new PostProcessingBeanDeserializer(
(BeanDeserializerBase) deserializer) {
@Override
protected void postProcess(Object bean) {
// 统一处理:字符串trim
trimStringFields(bean);
// 统一处理:空字符串转null
emptyStringToNull(bean);
}
};
}
return deserializer;
}
});
mapper.registerModule(module);
return mapper;
}
}
8. 注意事项
- 性能考虑:后置处理会增加反序列化时间,避免复杂逻辑
- 异常处理:后置处理中的异常要妥善处理,避免影响反序列化
- 线程安全:确保后置处理逻辑是线程安全的
- 调试困难:后置处理在底层执行,调试相对困难,建议添加日志