
本文详解如何在 Jackson XML 反序列化中正确解析含重复子元素(如 多次出现)的 XML 结构,解决 ObjectNode 无法保留数组语义导致列表被覆盖的问题,并提供基于类型安全与动态兼容的两种推荐方案。
本文详解如何在 jackson xml 反序列化中正确解析含重复子元素(如 `
在使用 Jackson 的 XmlMapper 解析 XML 时,若 XML 中存在多个同名子节点(例如
✅ 正确做法:用 @JacksonXmlElementWrapper 显式声明列表结构
Jackson XML 模块提供了专用注解 @JacksonXmlElementWrapper 配合 @JacksonXmlProperty 来准确建模嵌套列表。关键规则如下:
- @JacksonXmlProperty(localName = "COMPANY") 标记每个列表项的元素名;
- @JacksonXmlElementWrapper(useWrapping = false) 表示该列表无包装器标签(即直接以
为项,而非 中的... 作为 wrapper); - 若 XML 中
直接位于 内(如示例),则 COMPANYS 应作为容器类,而非 wrapper 标签本身。
对应示例 XML 结构,推荐定义如下 Java 类型:
@Data
@JacksonXmlRootElement(localName = "TX")
public class ServiceBusReq {
@JacksonXmlProperty(localName = "TX_HEADER")
private ServiceBusHeaderReq txHeader;
@JacksonXmlProperty(localName = "TX_EMB")
private String txEmb;
@JacksonXmlProperty(localName = "ENTITY")
private Entity entity;
}
@Data
public class Entity {
@JacksonXmlProperty(localName = "USER_NAME")
private String userName;
@JacksonXmlProperty(localName = "COMPANYS")
private Companies companys;
}
@Data
public class Companies {
@JacksonXmlProperty(localName = "COMPANY")
@JacksonXmlElementWrapper(useWrapping = false) // ⚠️ 关键:告知 Jackson COMPANY 是重复项,非单值
private List<Company> companyList;
}
@Data
public class Company {
@JacksonXmlProperty(localName = "COMPANYNAME")
private String companyName;
}使用时无需修改 XmlMapper 配置,直接反序列化即可:
XmlMapper xmlMapper = XmlMapper.xmlBuilder().build(); ServiceBusReq req = xmlMapper.readValue(xml, ServiceBusReq.class); // 此时 req.getEntity().getCompanys().getCompanyList() 将包含 2 个 Company 对象
? 替代方案:保持动态性 —— 使用 JsonNode + 手动提取数组
若业务确实无法预定义结构(如
XmlMapper xmlMapper = XmlMapper.xmlBuilder().build();
// 先解析为 JsonNode 树(保留 XML 结构语义)
JsonNode rootNode = xmlMapper.readTree(xml);
JsonNode entityNode = rootNode.path("ENTITY");
// 手动提取 COMPANYS 下的所有 COMPANY 节点(自动转为数组)
JsonNode companiesArray = entityNode.path("COMPANYS").path("COMPANY"); // 自动聚合为 ArrayNode
System.out.println("Company count: " + companiesArray.size()); // 输出 2
companiesArray.forEach(company -> {
String name = company.path("COMPANYNAME").asText();
System.out.println("Company: " + name);
});✅ 优势:完全动态,无需提前建模;
⚠️ 注意:需确保 XML 结构中确实是 的直接子节点,且无命名空间干扰。
? 总结与建议
| 场景 | 推荐方式 | 说明 |
|---|---|---|
|
结构相对稳定(如 |
定义 POJO + @JacksonXmlElementWrapper | 类型安全、IDE 支持好、性能优、可序列化回 XML |
|
结构高度动态(如 |
XmlMapper.readTree() → JsonNode → 路径遍历 | 灵活但需手动处理逻辑,丢失编译期检查 |
切勿依赖 ObjectNode 自动识别 XML 数组——这是常见误区。Jackson XML 的数组语义必须由注解显式驱动,或交由 JsonNode 树模型按需解析。合理选择方案,即可兼顾灵活性与健壮性。

















