JAXB反序列化XML为POJO时upsert字段始终为null问题
问题根因
这个问题是XML默认命名空间继承规则+JAXB严格命名空间匹配逻辑共同导致的:
- 你提供的待反序列化XML中,根节点
<MarginCall>声明了默认命名空间xmlns="http://my-name-space"。按照XML规范,所有未显式指定命名空间前缀、也未重写默认命名空间的子元素,会自动继承父级的默认命名空间,也就是说XML里的<upsert>、<AccountId>节点实际所属命名空间都是http://my-name-space,并非空命名空间。 - 你当前的POJO注解配置中,
upsert字段、Upsert类、accountId字段都没有显式绑定http://my-name-space命名空间,默认按空命名空间匹配节点,和XML实际节点的命名空间不匹配。 - JAXB反序列化时如果找不到命名空间+节点名完全匹配的元素,不会抛出异常,会静默将对应字段赋值为null,这就是你看到upsert始终为null的直接原因。
- 你之前测试序列化输出的XML结构看着和输入一致,本质是因为序列化时根节点用了
ns2显式前缀,子元素未绑定默认命名空间,JAXB按空命名空间生成子节点,和你原有注解配置匹配;但待反序列化的XML是根节点绑定默认命名空间,子节点自动继承命名空间,二者的节点命名空间实际不相同,只是肉眼看结构相似。 - 你之前尝试修改/移除Upsert类上的namespace配置未生效,是因为没有同步修改
MarginCall类中upsert字段、Upsert类中accountId字段的命名空间配置,匹配规则始终不对。
修复方案
由于你不能修改现有XML结构,只需要调整POJO的JAXB注解,让字段绑定的命名空间和XML实际节点的命名空间完全匹配即可:
- 给
MarginCall类中upsert字段的@XmlElement注解,显式指定命名空间为http://my-name-space - 把
Upsert类上的@XmlType注解的namespace值改为http://my-name-space,移除空命名空间配置 - 给
Upsert类中accountId字段的@XmlElement注解,也显式指定相同的命名空间
修正后的代码示例:
MarginCall类
@XmlRootElement(name="MarginCall", namespace="http://my-name-space") @XmlAccessorType(XmlAccessType.FIELD) public class MarginCall { @XmlAttribute private String type; // 显式指定upsert元素匹配的命名空间 @XmlElement(namespace = "http://my-name-space") protected Upsert upsert; // 省略getter、setter、toString方法 }
Upsert类
// 类级别绑定的命名空间和根节点保持一致 @XmlType(name = "upsert", namespace="http://my-name-space") @XmlAccessorType(XmlAccessType.FIELD) public class Upsert { // 内部子元素也需要指定匹配的命名空间 @XmlElement(name="AccountId", namespace = "http://my-name-space") private String accountId; // 省略getter、setter、toString方法 }
修改完成后再执行反序列化,即可正常解析出upsert对象及其中的accountId值。如果需要序列化输出时去掉自动生成的ns2前缀、和原始XML结构完全一致,可以在包路径下添加package-info.java配置默认命名空间前缀,该调整不影响反序列化逻辑。
内容的提问来源于stack exchange,提问作者Sandrew Cheru
相关产品推荐
相关产品推荐

