Record自定义反序列化正常,@Jacksonized+@Builder组合失效求助
可行解决方案汇总
针对你遇到的Lombok注解类反序列化器未触发、且需要运行时动态切换反序列化器的问题,以下是几种可行方案:
1. 动态注册Jackson Module
创建多个SimpleModule实例,每个实例绑定对应场景的Person自定义反序列化器,运行时根据业务需求将指定Module注册到ObjectMapper中(切换时可先解绑旧Module再注册新的,或直接创建不同的ObjectMapper实例)。
示例代码:
// 定义不同的反序列化器 public class PersonDeserializerV1 extends StdDeserializer<Person> { // 实现对应场景的反序列化逻辑 } public class PersonDeserializerV2 extends StdDeserializer<Person> { // 实现对应场景的反序列化逻辑 } // 注册并切换Module ObjectMapper mapper = new ObjectMapper(); // 切换到V1反序列化器 SimpleModule moduleV1 = new SimpleModule(); moduleV1.addDeserializer(Person.class, new PersonDeserializerV1()); mapper.registerModule(moduleV1); // 切换到V2反序列化器 mapper.unregisterModule(moduleV1); SimpleModule moduleV2 = new SimpleModule(); moduleV2.addDeserializer(Person.class, new PersonDeserializerV2()); mapper.registerModule(moduleV2);
2. 利用BeanDeserializerModifier扩展
通过BeanDeserializerModifier介入Jackson的反序列化流程,动态替换反序列化器。可以结合ThreadLocal或业务上下文参数,在Modifier中判断当前场景需要的反序列化器类型。
示例代码:
public class DynamicPersonDeserializerModifier extends BeanDeserializerModifier { private static final ThreadLocal<Class<? extends StdDeserializer<Person>>> DESERIALIZER_TYPE = new ThreadLocal<>(); // 提供设置当前反序列化器的入口 public static void setCurrentDeserializerType(Class<? extends StdDeserializer<Person>> type) { DESERIALIZER_TYPE.set(type); } @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { if (beanDesc.getBeanClass() == Person.class) { try { // 根据ThreadLocal中的类型实例化对应反序列化器 return DESERIALIZER_TYPE.get().getConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException("实例化反序列化器失败", e); } } return super.modifyDeserializer(config, beanDesc, deserializer); } } // 注册Modifier到ObjectMapper ObjectMapper mapper = new ObjectMapper(); mapper.setConfig(mapper.getDeserializationConfig() .with(new DynamicPersonDeserializerModifier())); // 业务中切换反序列化器 DynamicPersonDeserializerModifier.setCurrentDeserializerType(PersonDeserializerV1.class); Person person = mapper.readValue(csvData, Person.class);
3. 实现ContextualDeserializer接口
让自定义反序列化器实现ContextualDeserializer,在反序列化时根据上下文(如业务标识、注解参数等)动态调整反序列化逻辑,或切换不同的子反序列化器。
示例代码:
public class DynamicPersonDeserializer extends StdDeserializer<Person> implements ContextualDeserializer { private StdDeserializer<Person> delegate; public DynamicPersonDeserializer() { super(Person.class); } private DynamicPersonDeserializer(StdDeserializer<Person> delegate) { super(Person.class); this.delegate = delegate; } @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { // 根据上下文属性选择对应反序列化器 String deserializerType = (String) ctxt.getAttribute("DESERIALIZER_TYPE"); if ("V1".equals(deserializerType)) { return new DynamicPersonDeserializer(new PersonDeserializerV1()); } else { return new DynamicPersonDeserializer(new PersonDeserializerV2()); } } @Override public Person deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { return delegate.deserialize(p, ctxt); } } // 使用时设置上下文标识 ObjectMapper mapper = new ObjectMapper(); DeserializationContext ctxt = mapper.getDeserializationContext(); ctxt.setAttribute("DESERIALIZER_TYPE", "V1"); Person person = mapper.readValue(csvData, Person.class);
4. 维护ObjectMapper实例池
为每个反序列化器场景创建独立的ObjectMapper实例,运行时直接根据业务需求获取对应的实例解析CSV。这种方式逻辑简单,避免动态切换的复杂度,适合场景固定的业务。
示例代码:
// 初始化实例池 public class ObjectMapperPool { private static final Map<String, ObjectMapper> MAPPER_POOL = new HashMap<>(); static { ObjectMapper mapperV1 = new ObjectMapper(); mapperV1.registerModule(new SimpleModule().addDeserializer(Person.class, new PersonDeserializerV1())); MAPPER_POOL.put("V1", mapperV1); ObjectMapper mapperV2 = new ObjectMapper(); mapperV2.registerModule(new SimpleModule().addDeserializer(Person.class, new PersonDeserializerV2())); MAPPER_POOL.put("V2", mapperV2); } public static ObjectMapper getMapper(String type) { return MAPPER_POOL.get(type); } } // 业务中使用 ObjectMapper mapper = ObjectMapperPool.getMapper("V1"); Person person = mapper.readValue(csvData, Person.class);
补充说明
使用Lombok的@Builder+@Jacksonized时,Jackson默认会优先使用Builder生成的反序列化逻辑,导致类上的全局反序列化器被忽略。上述方案通过直接注册反序列化器到Jackson的核心流程中,能够绕过Builder的优先级限制,确保自定义反序列化器被触发。
内容的提问来源于stack exchange,提问作者Jan Nielsen
相关产品推荐
相关产品推荐

