如何使用Jackson映射未知可变字段?汇率JSON反序列化报错处理
解决JSON汇率数据反序列化问题
报错的核心原因是JSON中的rates是一个键值对对象(键为货币代码,值为汇率),但你定义的Java实体类CurrencyExchangeRateResponse中,rates字段被声明为List<Rate>类型。Jackson无法自动将JSON对象转换为List集合,因此抛出类型不匹配的异常。
以下是两种可行的解决方案:
方案一:直接使用Map映射(最简单)
修改CurrencyExchangeRateResponse中的rates字段类型为Map<Currency, Double>,直接匹配JSON的键值对结构:
import lombok.Getter; import lombok.Setter; import java.util.Map; @Getter @Setter public class CurrencyExchangeRateResponse { private Boolean success; private Boolean historical; private String date; private long timestamp; private String base; // 替换List<Rate>为Map,键是Currency枚举,值为汇率 private Map<Currency, Double> rates; }
- 注意:
Currency枚举的枚举值必须和JSON中的货币代码完全一致(包括大小写)。如果存在大小写不匹配的情况,可在枚举值上添加@JsonProperty注解指定映射关系,例如:
public enum Currency { AUD, @JsonProperty("GBP") // 若JSON中是小写"gbp",则改为@JsonProperty("gbp") GBP, HKD, // 其他货币代码 }
方案二:自定义反序列化器(保留List结构)
如果业务逻辑必须使用List<Rate>,可以编写自定义Jackson反序列化器,将JSON对象转换为List集合:
步骤1:编写自定义反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; public class RatesListDeserializer extends JsonDeserializer<List<Rate>> { @Override public List<Rate> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode ratesNode = p.getCodec().readTree(p); List<Rate> rateList = new ArrayList<>(); // 遍历JSON对象的所有键值对 Iterator<Map.Entry<String, JsonNode>> fieldIterator = ratesNode.fields(); while (fieldIterator.hasNext()) { Map.Entry<String, JsonNode> entry = fieldIterator.next(); Rate rate = new Rate(); // 将货币代码字符串转换为Currency枚举 rate.setCurrency(Currency.valueOf(entry.getKey())); // 将JSON值转换为Double类型 rate.setValue(entry.getValue().asDouble()); rateList.add(rate); } return rateList; } }
步骤2:在实体类字段上指定反序列化器
修改CurrencyExchangeRateResponse的rates字段,添加@JsonDeserialize注解指定自定义反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Getter; import lombok.Setter; import java.util.List; @Getter @Setter public class CurrencyExchangeRateResponse { private Boolean success; private Boolean historical; private String date; private long timestamp; private String base; // 指定使用自定义反序列化器 @JsonDeserialize(using = RatesListDeserializer.class) private List<Rate> rates; }
内容的提问来源于stack exchange,提问作者ka3ak
相关产品推荐
相关产品推荐

