JAXB执行Unmarshalling解析SOAP XML返回重复空字段问题求助
问题根因分析
你遇到的反序列化全空的核心原因是命名空间不匹配,JAXB对XML节点的匹配是「节点名+命名空间」联合匹配,只要有一项对应不上就会忽略节点赋值,具体问题点如下:
- Envelope类内的Header、Body字段都属于
http://schemas.xmlsoap.org/soap/envelope/命名空间,未在字段上指定namespace属性,无法匹配带soapenv前缀的节点 - Header类内的tMLHeader属于
http://tml.t1m1.org/tML.Transport.xsd命名空间,未指定namespace无法匹配带ns1前缀的节点 - Body类内的processSyncRequestResponse属于
java:lsr.webservice.wisor.com命名空间,未指定namespace无法匹配节点 - SendTimestamp字段是带时区的ISO日期格式,JAXB默认无法直接转换为Date类型,需要自定义适配器
- 输出的JSON出现4个字段是因为JSON序列化框架同时序列化了public字段和getter方法:大写是字段名,小写是getter方法转换后生成的属性
修复代码
1. 日期格式适配器
先自定义日期适配类处理XML日期转换:
import javax.xml.bind.annotation.adapters.XmlAdapter; import java.text.SimpleDateFormat; import java.util.Date; public class XmlAdapterDate extends XmlAdapter<String, Date> { private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); @Override public Date unmarshal(String v) throws Exception { return sdf.parse(v); } @Override public String marshal(Date v) throws Exception { return sdf.format(v); } }
2. 实体类修正
Envelope类
@XmlRootElement(name="Envelope",namespace = "http://schemas.xmlsoap.org/soap/envelope/") @XmlAccessorType(XmlAccessType.FIELD) public class Envelope { @XmlElement(name = "Header", namespace = "http://schemas.xmlsoap.org/soap/envelope/") public Header Header; @XmlElement(name = "Body", namespace = "http://schemas.xmlsoap.org/soap/envelope/") public Body Body; // 原有getter/setter保留 }
Header类
@XmlAccessorType(XmlAccessType.FIELD) public class Header { @XmlElement(name = "tMLHeader", namespace = "http://tml.t1m1.org/tML.Transport.xsd") public tMLHeader tMLHeader; // 原有getter/setter保留 }
tMLHeader类
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public class tMLHeader { @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public String TransportID; @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public String ApplicationType; @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public double ApplicationVersion; @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public String From; @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public String To; @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") @XmlJavaTypeAdapter(value = XmlAdapterDate.class) public Date SendTimestamp; @XmlElement(namespace = "http://tml.t1m1.org/tML.Transport.xsd") public int RetryCount; // 原有getter/setter保留 }
Body类
@XmlAccessorType(XmlAccessType.FIELD) public class Body { @XmlElement(name = "processSyncRequestResponse", namespace = "java:lsr.webservice.wisor.com") public ProcessSyncRequestResponse processSyncRequestResponse; // 原有getter/setter保留 }
ProcessSyncRequestResponse类
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(namespace = "java:lsr.webservice.wisor.com") public class ProcessSyncRequestResponse { @XmlElement(name = "response") public String response; // 原有getter/setter保留 }
3. 反序列化代码优化
保险起见把所有关联类都传入JAXBContext,避免扫描遗漏:
File xml = new File("test.xml"); return (Envelope)JAXBContext .newInstance(Envelope.class, Header.class, Body.class, tMLHeader.class, ProcessSyncRequestResponse.class) .createUnmarshaller() .unmarshal(xml);
重复字段优化
如果要去掉JSON里小写的header/body重复字段,给Envelope类加上Jackson注解(其他序列化框架对应调整配置即可):
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE) public class Envelope { // 原有内容不变 }
内容的提问来源于stack exchange,提问作者FoxsTail
相关产品推荐
相关产品推荐

