Jackson无注解List反序列化异常:自定义反序列化器返回单个元素
我之前踩过一模一样的坑!这种情况90%是因为自定义反序列化器里没做好重复元素的累积逻辑,或者Jackson XML模块的类型映射没配置到位。既然你不想用注解,那咱们从自定义反序列化器的核心逻辑和XmlMapper配置入手解决:
先排查自定义反序列化器的核心问题
最常见的错误是:你的反序列化器只处理了单个元素,每次遇到新元素就覆盖了之前的对象,而不是把它们添加到集合里。比如如果你的反序列化器是针对单个Item类型的,Jackson会默认把最后一个元素覆盖前面的——你得把反序列化器的目标改成List<Item>,并在逻辑里维护一个集合:
public class CustomItemListDeserializer extends StdDeserializer<List<Item>> { // 必须指定父类类型为List.class public CustomItemListDeserializer() { super(List.class); } @Override public List<Item> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { List<Item> itemList = new ArrayList<>(); // 循环遍历所有item元素,直到遇到数组/对象结束标记 while (p.nextToken() != JsonToken.END_ARRAY && p.nextToken() != JsonToken.END_OBJECT) { // 解析单个Item的逻辑(这里根据你的复杂结构调整) Item item = new Item(); p.nextToken(); // 跳过字段名(比如<name>) item.setName(p.getText()); // ... 其他字段解析逻辑 // 关键:把当前元素添加到集合,而不是替换 itemList.add(item); } return itemList; } }
再确认XmlMapper的注册配置
注册反序列化器时,一定要确保是针对集合类型,而不是单个元素类型,否则Jackson还是会按单个对象处理:
XmlMapper xmlMapper = new XmlMapper(); SimpleModule customModule = new SimpleModule(); // 两种注册方式:精确指定泛型类型,避免和其他List类型冲突 customModule.addDeserializer(new TypeReference<List<Item>>() {}, new CustomItemListDeserializer()); // 或者如果全局所有List都用这个反序列化器(不推荐,容易冲突) // customModule.addDeserializer(List.class, new CustomItemListDeserializer()); xmlMapper.registerModule(customModule);
额外调试技巧
如果还是没解决,可以在反序列化器里加日志打印Token流转,看看是不是漏掉了元素:
// 在deserialize方法里添加 System.out.println("当前Token类型:" + p.getCurrentToken() + ",值:" + p.getText());
通过打印可以清楚看到Jackson是不是遍历了所有<item>元素,还是中途提前退出了循环。
特殊情况:XML无外层数组标签
如果你的XML结构是没有外层<items>包裹的重复元素(比如直接在根节点下有多个<item>),那你需要把反序列化器的目标改成根对象,在根对象的反序列化逻辑里收集所有<item>子元素,而不是直接处理List。
内容的提问来源于stack exchange,提问作者lukaspp
相关产品推荐
相关产品推荐

