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

使用FasterXML遍历含重复键JSON数组仅获最后值的问题排查

解决Jackson解析含重复键JSON只取最后一个值的问题

嘿,我来帮你拆解下问题所在,一步步搞定:


先修正DTO字段与JSON键的匹配问题

你后端返回的JSON里是小写的"state",但你的Countries类字段是States(大写开头还多了个s);Test类的字段countries和JSON里的"Countries"(大写C)也不匹配。这虽然不是只取最后一个值的核心原因,但会导致Jackson映射异常,先把这个基础错误改了:

修正后的DTO类(记得加@JsonProperty明确映射关系,还有getter/setter,Jackson需要它们访问字段):

// 类名建议用单数Country更符合语义,你也可以按自己习惯来
private class Countries {
    @JsonProperty("state") // 绑定JSON里的"state"键
    private String state;

    public String getState() { return state; }
    public void setState(String state) { this.state = state; }
}

private class Test {
    @JsonProperty("Countries") // 绑定JSON里的"Countries"键
    private List<Countries> countries;

    public List<Countries> getCountries() { return countries; }
    public void setCountries(List<Countries> countries) { this.countries = countries; }
}

核心问题:Jackson默认会覆盖重复键的值

标准JSON规范不允许同一个对象内出现重复键,所以Jackson的默认行为是遇到重复键时,直接用后面的值覆盖前面的——这就是你只能拿到"Tasmania"的原因。如果后端没法修改返回格式,咱们得自定义反序列化逻辑来收集所有重复的state值。

解决方案:自定义反序列化器+开启重复键支持

要实现把单个对象里的重复state拆成列表里的多个Countries对象,需要两步:

1. 配置ObjectMapper允许重复键

在你的Mapper类里,初始化ObjectMapper时必须开启ALLOW_DUPLICATE_NAMES特性,否则Jackson会直接跳过前面的重复键:

private class Mapper {
    public Test parseJson(String json) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        // 关键:允许JSON对象存在重复键,并保留所有键值对
        mapper.enable(JsonParser.Feature.ALLOW_DUPLICATE_NAMES);
        return mapper.readValue(json, Test.class);
    }
}

2. 写自定义反序列化器收集所有重复的state

我们需要给Test类的countries字段写一个反序列化器,把单个对象里的多个state值拆成独立的Countries对象:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class CountriesListDeserializer extends JsonDeserializer<List<Countries>> {
    @Override
    public List<Countries> deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        List<Countries> countriesList = new ArrayList<>();
        // 跳过JSON数组的START标记
        parser.nextToken();
        // 进入数组里的单个对象
        parser.nextToken();

        // 遍历对象内所有键值对
        while (parser.nextToken() != JsonToken.END_OBJECT) {
            String key = parser.getCurrentName();
            parser.nextToken(); // 跳转到对应值的位置
            if ("state".equals(key)) {
                // 把每个state值封装成Countries对象加入列表
                Countries country = new Countries();
                country.setState(parser.getText());
                countriesList.add(country);
            }
        }
        // 跳过JSON数组的END标记
        parser.nextToken();
        return countriesList;
    }
}

3. 在DTO上绑定反序列化器

修改Test类的countries字段,指定使用我们写的反序列化器:

private class Test {
    @JsonProperty("Countries")
    @JsonDeserialize(using = CountriesListDeserializer.class) // 绑定自定义反序列化器
    private List<Countries> countries;

    // getter/setter 同上
}

最终效果

这样处理后,解析你给的JSON字符串时,Test.countries会变成包含两个对象的列表:

[
  Countries{state='Queens Land'},
  Countries{state='Tasmania'}
]

额外建议

如果能和后端团队沟通的话,最好让他们把JSON改成标准格式,比如:

"Countries": [
  {"state":"Queens Land"},
  {"state":"Tasmania"}
]

这样完全不用自定义反序列化器,Jackson默认就能正常解析,也避免了不符合规范的JSON带来的其他潜在问题。

内容的提问来源于stack exchange,提问作者Jreddy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:12:46