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

Jackson解析含同名属性与子标签的XML时遇类型转换异常

XML解析异常原因解析

问题场景

需要解析包含child节点的XML:该节点同时存在名为subject的String类型属性,以及未包装的Subject类型集合。通过setSubject(Object value)方法根据传入值的类型,将其映射到对应的String或Subject字段。但第二次调用XmlMapper.convertValue(Object from, Class<T> to)时抛出类型转换异常,错误信息显示node元素被识别为LinkedHashMap而非预期的ArrayList。

错误信息

com.fasterxml.jackson.databind.JsonMappingException: Cannot deserialize value of type java.util.ArrayList[com.example.MyTest$Node] from Object value (token JsonToken.START_OBJECT)
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.example.MyTest$Root["child"]->com.example.MyTest$Child["subject"])

测试代码与实体类

@Test
void syntheticTest() throws JsonMappingException, JsonProcessingException {

    String xml;
    Root root;

    // #1 多个node元素,解析成功
    xml = """
            <root>
                <child subject="first subject">
                    <subject>
                        <node param="value1" />
                        <node param="value2" />
                    </subject>
                </child>
            </root>
            """;
    root = mapper.readValue(xml, Root.class);
    assertEquals(2, root.getChild().getSubjectObj().getNodes().size());

    // #2 单个node元素,抛出异常
    xml = """
            <root>
                <child subject="second subject">
                    <subject>
                        <node param="value1" />
                    </subject>
                </child>
            </root>
            """;
    root = mapper.readValue(xml, Root.class);
    assertEquals(1, root.getChild().getSubjectObj().getNodes().size());
}

@Getter
@Setter
public static class Root {
    private Child child;
}

@Getter
public static class Child {
    private String subjectStr;
    private Subject subjectObj;

    public void setSubject(Object value) {
        if (value instanceof String str) {
            subjectStr = str;
        } else {
            subjectObj = mapper.convertValue(value, Subject.class); // <- 此处抛出异常
        }
    }
}

@Getter
@Setter
public static class Subject {
    @JsonProperty("node")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Node> nodes;
}

@Getter
@Setter
public static class Node {
    private String param;
}

核心原因

Jackson XML解析器的默认行为导致了这个问题:

  • 当XML节点下存在多个同名子元素时,解析器会自动将它们封装为ArrayList集合;
  • 当XML节点下只有一个同名子元素时,解析器会直接将其解析为单个对象(这里对应LinkedHashMap,因为Jackson先把XML节点转成通用的Map结构)。

而Subject类中nodes字段声明为List<Node>,调用convertValue时,Jackson尝试将单个LinkedHashMap对象转换成ArrayList<Node>,类型不匹配直接触发JsonMappingException。第一次调用成功是因为多个node元素被解析为ArrayList,与目标类型匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:53:10