如何用Jackson解决Kafka中带继承的嵌套Java对象序列化反序列化问题
解决SpringBoot Kafka中第三方子类嵌套对象的Jackson序列化/反序列化问题
问题场景
- 嵌套对象结构:
A类包含第三方基类B类型的字段,运行时实际传入B的子类(子类额外包含约100个B没有的字段) - 无法修改第三方类
B及其子类 - 已基于Jackson实现自定义Kafka序列化器
ASerializer和反序列化器ADeserializer,但反序列化时抛出UnrecognizedPropertyException,提示子类的额外字段无法被基类B识别
错误信息
Caused by: org.apache.kafka.common.errors.SerializationException: Error deserializing key/value for partition test-0 at offset 0. If needed, please seek past the record to continue consumption. Caused by: java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "SomeFieldName" (class com.sample.V8.B), not marked as ignorable (42 known properties: [xxx...])
解决方案(仅使用Jackson)
需要同时处理序列化时保留子类类型信息和反序列化时兼容子类额外字段两个核心问题,具体修改如下:
1. 修改序列化器ASerializer
// serializer public class ASerializer implements Serializer<A> { private final ObjectMapper mapper; public ASerializer() { mapper = new ObjectMapper(); // 启用多态类型标记,序列化时写入实际子类的类型信息 mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); // 避免因类型标识符问题抛出序列化异常 mapper.configure(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS, false); } @Override public byte[] serialize(String topic, A data) { try { return mapper.writeValueAsBytes(data); } catch (JsonProcessingException e) { throw new RuntimeException("序列化对象A失败", e); } } @Override public void configure(Map<String, ?> configs, boolean isKey) {} @Override public void close() {} }
2. 修改反序列化器ADeserializer
// deserializer public class ADeserializer implements Deserializer<A> { private ObjectMapper mapper; @Override public void configure(Map<String, ?> configs, boolean isKey) { JsonFactory jsonFactory = new JsonFactory(); jsonFactory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); mapper = new ObjectMapper(jsonFactory); // 启用多态类型解析,识别序列化时写入的子类类型标记 mapper.activateDefaultTyping( mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY ); // 忽略基类B未定义的子类额外字段,避免抛出未识别字段异常 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } @Override public A deserialize(String topic, byte[] data) { try { return mapper.readValue(data, A.class); } catch (IOException e) { throw new RuntimeException("反序列化对象A失败", e); } } @Override public void close() {} }
3. 关键配置说明
activateDefaultTyping:开启多态类型支持,序列化时会在JSON中自动添加@type字段记录对象实际子类的全限定名,反序列化时根据该字段实例化对应子类,而非仅按声明的基类B解析DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES:设置为false,让Jackson忽略基类中未定义的子类额外字段,避免触发未识别字段异常- 序列化器与反序列化器需使用相同的多态配置规则,确保类型信息能正确传递和解析
额外优化点
- 不要在
serialize方法中重复创建ObjectMapper(原代码存在的问题),ObjectMapper是线程安全的,应在构造方法或configure中初始化一次
内容的提问来源于stack exchange,提问作者anurag tripathi
相关产品推荐
相关产品推荐

