Jackson @JsonUnwrapped注解:共享与新建ObjectMapper序列化不一致问题
Jackson 2.16.1共享ObjectMapper实例导致@JsonUnwrapped前缀序列化异常的解决方案
问题现象
在使用Jackson 2.16.1时,遵循官方建议使用共享ObjectMapper实例,但序列化结果与新建实例不一致:先序列化带有空前缀@JsonUnwrapped(prefix = "")的对象后,再序列化带有非空前缀的嵌套对象,前缀未正确叠加;而新建ObjectMapper实例则能得到正确的拼接结果。
复现代码
public class First { @JsonUnwrapped(prefix = "") final Thrid thrid = new Thrid(); } public class Second { @JsonUnwrapped(prefix = "fromSecond") final Thrid thrid = new Thrid(); } public class Thrid { @JsonUnwrapped(prefix = "fromThird") final Common common = new Common("1", "2"); } @JsonInclude(JsonInclude.Include.NON_NULL) public class Common { public String getA() { return a; } public String getB() { return b; } String a; String b; public Common() {} public Common(String a, String b) { this.a = a; this.b = b; } } public static void main(String[] args) throws JsonProcessingException { First first = new First(); Second second = new Second(); ObjectMapper objectMapper = new ObjectMapper(); System.out.println(objectMapper.writeValueAsString(first)); System.out.println(objectMapper.writeValueAsString(second)); System.out.println(new ObjectMapper().writeValueAsString(second)); }
输出结果
{"fromThirda":"1","fromThirdb":"2"} {"fromThirda":"1","fromThirdb":"2"} {"fromSecondfromThirda":"1","fromSecondfromThirdb":"2"}
可以看到,共享ObjectMapper序列化Second的结果未正确拼接fromSecond前缀,而新建实例的结果符合预期。
问题原因
这是Jackson的类元数据缓存机制导致的问题:ObjectMapper会缓存已解析的类序列化规则(包括@JsonUnwrapped的前缀配置)。当第一次处理First类中Thrid字段的空前缀@JsonUnwrapped时,Thrid类的序列化元数据被缓存为无前缀叠加的状态;后续处理Second类中带有非空前缀的Thrid字段时,直接复用了缓存的元数据,导致前缀未正确拼接。
解决方案
1. 避免使用空前缀的@JsonUnwrapped
将First类中的@JsonUnwrapped(prefix = "")改为非空值(比如prefix = "fromFirst"),这样Thrid类的元数据会根据不同的前缀生成独立的缓存条目,不会互相干扰。
2. 使用独立的ObjectWriter处理不同场景
针对不同的序列化场景创建独立的ObjectWriter实例,绕过共享缓存:
ObjectMapper objectMapper = new ObjectMapper(); ObjectWriter firstWriter = objectMapper.writerFor(First.class); ObjectWriter secondWriter = objectMapper.writerFor(Second.class); System.out.println(firstWriter.writeValueAsString(first)); System.out.println(secondWriter.writeValueAsString(second));
3. 禁用序列化元数据缓存(不推荐)
通过关闭ObjectMapper的缓存开关解决问题,但会影响序列化性能,仅建议在测试场景使用:
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(MapperFeature.CACHE_SERIALIZER_PROVIDER);
4. 升级Jackson版本
该问题大概率是Jackson 2.16.x的已知bug,尝试升级到2.17及以上版本,官方可能已修复该缓存逻辑缺陷。
内容的提问来源于stack exchange,提问作者Sandeep Gaur
相关产品推荐
相关产品推荐

