You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:27:22