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

使用Jackson反序列化含列表的XML时遇ArrayList反序列化异常如何解决?

解决Jackson XML反序列化时单个元素转List的异常问题

兄弟,这个坑我之前刚踩过!你遇到的Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.ArrayList out of VALUE_STRING token本质是Jackson XML反序列化的常见问题:当XML里的<bar>元素只有单个实例时,Jackson会默认把它解析成字符串(VALUE_STRING token),但你的Java字段定义的是List类型,类型不匹配就抛出异常了。下面给你几个靠谱的解决办法,按优先级推荐:

方法1:用Jackson XML注解精准控制(推荐)

这是最精准的方式,只针对特定字段生效,不会影响全局配置。核心是用@JacksonXmlElementWrapper和@JacksonXmlProperty组合:

  • @JacksonXmlElementWrapper(useWrapping = false):告诉Jackson不要期望<bar>有外层包裹元素(比如<bars><bar>...</bar></bars>),直接把单个或多个<bar>解析成List。
  • @JacksonXmlProperty(localName = "bar"):指定XML中对应的元素名。

示例代码:

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;

@JacksonXmlRootElement(localName = "foo")
public class Foo {
    // 针对bar字段配置,单个或多个<bar>都会被解析成List<String>
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "bar")
    private List<String> barList;

    // 别忘了getter和setter
    public List<String> getBarList() {
        return barList;
    }

    public void setBarList(List<String> barList) {
        this.barList = barList;
    }
}

不管你的XML是<foo><bar>test1</bar></foo>(单个bar)还是<foo><bar>test1</bar><bar>test2</bar></foo>(多个bar),都能正常解析成List<String>。

方法2:全局配置Jackson允许单个值转数组

如果你的项目里有很多类似的List字段,都需要处理单个元素转List的情况,可以全局开启Jackson的ACCEPT_SINGLE_VALUE_AS_ARRAY特性,这样所有List类型的字段都会自动把单个值当成数组处理。

示例代码:

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

public class XmlDeserializeDemo {
    public static void main(String[] args) throws Exception {
        XmlMapper xmlMapper = new XmlMapper();
        // 开启单个值转数组的特性
        xmlMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);

        // 测试单个bar的XML
        String singleBarXml = "<foo><bar>hello</bar></foo>";
        Foo foo = xmlMapper.readValue(singleBarXml, Foo.class);
        System.out.println(foo.getBarList()); // 输出 [hello]

        // 测试多个bar的XML
        String multiBarXml = "<foo><bar>hello</bar><bar>world</bar></foo>";
        Foo foo2 = xmlMapper.readValue(multiBarXml, Foo.class);
        System.out.println(foo2.getBarList()); // 输出 [hello, world]
    }
}

注意:这个是全局生效,如果你有某些List字段不需要这种处理,就别用这个方法,还是方法1更灵活。

方法3:自定义反序列化器(复杂场景用)

如果上面两种方法都满足不了你的需求(比如XML结构特别复杂,有嵌套或者特殊格式),可以写自定义的反序列化器,手动处理单个值和数组的情况。

示例代码:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@JacksonXmlRootElement(localName = "foo")
public class Foo {
    // 指定用自定义反序列化器处理这个字段
    @JsonDeserialize(using = SingleOrListDeserializer.class)
    private List<String> barList;

    // getter和setter
    public List<String> getBarList() {
        return barList;
    }

    public void setBarList(List<String> barList) {
        this.barList = barList;
    }
}

// 自定义反序列化器,处理单个值转List的逻辑
class SingleOrListDeserializer extends JsonDeserializer<List<String>> {
    @Override
    public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        List<String> resultList = new ArrayList<>();
        
        // 如果当前是单个标量值(比如字符串),直接添加到列表
        if (p.getCurrentToken().isScalarValue()) {
            resultList.add(p.getText());
        } 
        // 如果是数组,遍历所有元素添加到列表
        else if (p.getCurrentToken().isStartArray()) {
            while (p.nextToken() != null && !p.getCurrentToken().isEndArray()) {
                resultList.add(p.getText());
            }
        }
        
        return resultList;
    }
}

这种方式灵活性最高,但代码量也大,适合特殊场景下使用。

内容的提问来源于stack exchange,提问作者Damien-Amen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:01:36