如何将JSON值数组转换为Java对象及解决Jackson反序列化不匹配异常
解决Jackson反序列化JSON数组到Java对象的踩坑经历
最近我在把一段特定结构的JSON数组转换成Java对象时,遇到了Jackson的反序列化错误,折腾了好一会儿才搞定,这里把问题和解决方法分享给大家。
首先看一下我要处理的JSON结构:
[ { "Dummy": { "attr": "PRIMITIVE", "value": { "Initial": "M", "Name": "Potato" } } }, { "Dummy": { "attr": "PRIMITIVE", "value": { "Initial": "A", "Name": "Potatoo1" } } } ]
最开始我写的反序列化代码是这样的:
ObjectMapper mapper = new ObjectMapper(); Dummy[] myObjects = mapper.readValue(resultStr, Dummy[].class);
对应的Java类定义是:
public class Dummy{ public String attr; public value val; } public class value { public String Initial; public String Name; }
结果一运行就炸了,抛出了这个错误:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type com.example.demo.Dummy from Array value
问题分析
仔细对比JSON和Java类的结构,发现两个核心问题:
- 结构不匹配:JSON数组里的每个元素并不是直接的Dummy对象,而是一个包含
"Dummy"键的对象,这个键的值才是真正的Dummy结构。Jackson找不到对应的映射,自然报错。 - 字段名不匹配:Java类里的字段叫
val,但JSON里对应的键是value,默认情况下Jackson会严格按字段名匹配,这也会导致反序列化失败。
解决方案
找到了问题根源,就有两种靠谱的解决办法:
方法一:用包装类适配JSON结构
先创建一个包装类,用来对应数组里的每个元素:
public class DummyWrapper { private Dummy Dummy; // 字段名要和JSON里的键完全一致,包括大小写 // 必须添加getter和setter,Jackson依赖它们完成序列化/反序列化 public Dummy getDummy() { return Dummy; } public void setDummy(Dummy dummy) { Dummy = dummy; } }
然后修正原来的Dummy类,把val改成value,同时把类名value改成Value(符合Java命名规范):
public class Dummy { public String attr; public Value value; } public class Value { public String Initial; public String Name; }
最后修改反序列化代码,先转换成包装类数组,再提取出Dummy对象:
ObjectMapper mapper = new ObjectMapper(); DummyWrapper[] wrappers = mapper.readValue(resultStr, DummyWrapper[].class); // 转成List方便后续操作 List<Dummy> dummyList = Arrays.stream(wrappers) .map(DummyWrapper::getDummy) .collect(Collectors.toList());
方法二:用Jackson注解解包根值
如果不想额外创建包装类,可以用@JsonRootName注解配合配置来解决:
先给Dummy类加上注解,指定它对应的根键名称:
import com.fasterxml.jackson.annotation.JsonRootName; @JsonRootName("Dummy") // 对应JSON里的外层键名 public class Dummy { public String attr; public Value value; } public class Value { public String Initial; public String Name; }
然后给ObjectMapper开启解包根值的配置,再进行反序列化:
ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); // 开启自动解包根节点 Dummy[] myObjects = mapper.readValue(resultStr, Dummy[].class);
这样Jackson就会自动把每个数组元素里的"Dummy"键对应的内容,解包成Dummy对象,完美适配结构。
两种方法都能解决问题,大家可以根据自己的项目场景选择合适的方式。
内容的提问来源于stack exchange,提问作者PotatoGod
相关产品推荐
相关产品推荐

