JAXB反序列化SOAP XML绑定POJO时字段全为null问题求助
JAXB反序列化SOAP报文全字段为null修复方案
核心问题是命名空间配置缺失+注解映射错误+代码笔误三类问题叠加,逐个修正即可:
- 所有业务节点都属于默认命名空间
urn:soap.origin.com,但除根类外其余实体、字段都未指定该命名空间,JAXB默认按空命名空间匹配节点,就算name写对也找不到对应值 - 注解存在大量语法错误、映射值错误:部分@XmlElement的name属性漏写前引号、Json注解名写错、字段名和XML标签不匹配、漏写报文里存在的字段
- 解析方法存在变量名笔误,编译都无法通过
修复步骤
1. 统一配置命名空间(最省事方案)
在所有JAXB实体类所在的包下新建package-info.java文件,统一指定包下所有类的默认命名空间,不用每个注解单独写namespace属性:
@XmlSchema( namespace = "urn:soap.origin.com", elementFormDefault = XmlNsForm.QUALIFIED ) // 下面替换成你自己的实体类实际包路径 package com.your.project.entity; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema;
如果不想加包级配置,就给每个实体类、每个@XmlElement注解都加上namespace = "urn:soap.origin.com"属性,效果一致但写法繁琐
2. 修正EventResponse类
补全注解漏写的引号,修正result字段的错误映射:
@Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "eventResponse", namespace = "urn:soap.origin.com") public class EventResponse{ // 原代码name写的是LoginResult,和实际XML标签result完全不匹配 @XmlElement(name = "result") private Result result; }
3. 修正Result类
修正写错的Json注解,补全报文中存在的boolean1字段,修正userInfo字段的映射值:
@Getter @Setter // 原代码多写了一层Json前缀,注解名写错 @JsonInclude(JsonInclude.Include.NON_NULL) @XmlAccessorType(XmlAccessType.FIELD) public class Result{ @XmlElement(name="field1", nillable="true") private String field1; // 原代码漏写该字段,错把属于userInfo的boolean2写到了这 @XmlElement(name="boolean1") private Boolean boolean1; @XmlElement(name="userId", nillable="true") private String userId; // 原代码name写的是类型名GetUserInfo,要和实际XML标签名一致,你提供的报文里是全小写userinfo @XmlElement(name="userinfo") private UserInfo userInfo; }
如果实际返回报文里该节点是驼峰userInfo,把上面的name值改成对应值即可,永远以实际返回的XML标签名为准
4. 修正UserInfo类
修正写错的Json注解,保证字段和XML标签一一对应:
@Getter @Setter // 原代码多写了一层Json前缀,注解名写错 @JsonInclude(JsonInclude.Include.NON_NULL) @XmlAccessorType(XmlAccessType.FIELD) public class UserInfo{ @XmlElement(name="boolean2") private Boolean boolean2; @XmlElement(name="field2", nillable="true") private String field2; @XmlElement(name="orgId") private String orgId; @XmlElement(name="userCode", nillable=true) private String userCode; }
5. 修正解析方法的笔误
统一变量名,指定报文编码避免乱码:
private EventResponse parseXmlResult(String xmlToParse) throws Exception { JAXBContext jaxbContext = JAXBContext.newInstance(EventResponse.class); // 原代码变量定义为msg,后面调用时写成了message,属于低级笔误;指定UTF-8编码避免乱码 SOAPMessage msg = MessageFactory.newInstance().createMessage(null, new ByteArrayInputStream(xmlToParse.getBytes(StandardCharsets.UTF_8))); Unmarshaller um = jaxbContext.createUnmarshaller(); EventResponse response = (EventResponse) um.unmarshall(msg.getSOAPBody().extractAsDocument()); return response; }
额外排查点
你提供的示例XML里SOAP Envelope标签前缀写的是soap:env,但实际声明的命名空间前缀是soapenv,前缀不匹配会导致SOAPMessage解析直接报错,如果是你写示例时的手误可以忽略,实际运行时要保证报文前缀和声明的命名空间前缀一致。
内容的提问来源于stack exchange,提问作者Panda
相关产品推荐
相关产品推荐

