Jackson反序列化因额外Getter致List字段出现重复值的原因
Jackson反序列化List字段出现重复值的原因解析
问题说明
给Wrapper类的values List字段新增getAllValues()方法后,反序列化包含values和allValues的JSON时,values列表出现重复值。原本以为无对应Setter的allValues会被忽略,实际它的内容被追加到了values列表中,最终输出Wrapper{values=[value1, value1]}。
相关代码片段
Wrapper类定义
public class Wrapper { private List<String> values; public List<String> getAllValues() { if (values == null) { values = new ArrayList<>(); } return values; } public void setValues(final List<String> values) { this.values = values; } public List<String> getValues() { return values; } public String toString() { return MoreObjects.toStringHelper(this).add("values", values).toString(); } }
待反序列化JSON
{ "values": [ "value1" ], "allValues": [ "value1" ] }
测试代码
public static void main(String[] args) throws Exception { final ObjectMapper mapper = new ObjectMapper(); final String wrapperJson = "{ \"values\": [ \"value1\" ], \"allValues\": [\"value1\"] }"; System.out.println(mapper.readValue(wrapperJson.getBytes(), Wrapper.class)); }
实际输出
Wrapper{values=[value1, value1]}
原因解析
在Jackson Databind 2.13.5版本中,反序列化的字段匹配逻辑不仅会寻找setXxx()形式的Setter方法,还会对返回可变集合的Getter方法做特殊处理:
- 处理JSON中的
values字段时,Jackson找到setValues()方法,直接将values属性赋值为包含"value1"的列表。 - 处理
allValues字段时,既找不到对应的allValues成员变量,也没有setAllValues()方法,但存在getAllValues()方法——该方法返回的是可变的ArrayList实例(还会在values为null时初始化它)。 - Jackson会将这种返回可变集合的Getter方法视为可修改集合的入口,直接把JSON中
allValues的元素"value1"追加到getAllValues()返回的列表(也就是values列表)中,最终导致列表出现重复值。
简单来说,Jackson默认认为返回可变集合的Getter可以用于更新集合,即使没有对应的Setter,也会直接操作Getter返回的对象。
可选解决方法
- 在
getAllValues()方法上添加@JsonIgnore注解,明确告诉Jackson序列化/反序列化时忽略该方法。 - 升级Jackson到2.14及以上版本,后续版本对Getter方法的处理逻辑做了优化,能避免这类意外行为。
内容的提问来源于stack exchange,提问作者divinedragon
相关产品推荐
相关产品推荐

