调用WebService时JAXBElement无法转为ShowPendingFilesResponse异常
问题:WebService空响应编组失败,抛出JAXBElement类型转换异常
调用WebService后返回200 OK,响应XML是无待下载文件的正确空结构,但Spring的marshalSendAndReceive方法无法正确编组响应,抛出javax.xml.bind.JAXBElement cannot be cast to download.iris.models.ShowPendingFilesResponse异常。
相关代码及响应信息
请求代码
JAXBElement<ShowPendingFiles> jAXBElement = new ObjectFactory().createShowPendingFiles(showPendingFilesRequest); CustomEnvelopeDetails customEnvelopeDetails = new CustomEnvelopeDetails( CcrConstants.ACTION_PENDING_FILES, new SecurityHeader(isSecurityEnabled, username, password) ); final Object marshalled = (ShowPendingFilesResponse) createServiceTemplate(jaxb2Marshaller) //return (ShowPendingFilesResponse) createServiceTemplate(jaxb2Marshaller) .marshalSendAndReceive(soapServer, jAXBElement, new SoapRequestHeaderModifier(customEnvelopeDetails)); return (ShowPendingFilesResponse) marshalled;
响应XML
<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <ns2:showPendingFilesResponse xmlns:ns2="http://iris.somewhere.com/web_services/external/downloadFile" xmlns:ns3="http://iris.somewhere.gr/web_services/external/uploadFile"/> </soapenv:Body> </soapenv:Envelope>
WSDL自动生成的ShowPendingFilesResponse类
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "showPendingFilesResponse", propOrder = { "showPendingFilesResult" }) public class ShowPendingFilesResponse { @XmlElement(nillable = true) protected List<TransferableFile> showPendingFilesResult; public List<TransferableFile> getShowPendingFilesResult() { if (showPendingFilesResult == null) { showPendingFilesResult = new ArrayList<TransferableFile>(); } return this.showPendingFilesResult; } }
原因分析
- 当响应XML中的根元素(
showPendingFilesResponse)没有子元素时,JAXB会将其封装为JAXBElement<ShowPendingFilesResponse>实例,而非直接返回ShowPendingFilesResponse对象 - 自动生成的
ShowPendingFilesResponse类缺少@XmlRootElement注解,导致JAXB无法直接将空元素映射为实体类实例,只能通过JAXBElement进行包装
解决方案
方案1:直接处理返回的JAXBElement
修改代码,先判断返回对象的类型,再提取内部的实体实例:
final Object marshalled = createServiceTemplate(jaxb2Marshaller) .marshalSendAndReceive(soapServer, jAXBElement, new SoapRequestHeaderModifier(customEnvelopeDetails)); if (marshalled instanceof JAXBElement) { return ((JAXBElement<ShowPendingFilesResponse>) marshalled).getValue(); } else { return (ShowPendingFilesResponse) marshalled; }
方案2:给实体类添加@XmlRootElement注解
如果允许修改自动生成的实体类,添加@XmlRootElement注解,注意命名空间要和响应XML中的ns2一致:
@XmlRootElement(name = "showPendingFilesResponse", namespace = "http://iris.somewhere.com/web_services/external/downloadFile") @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "showPendingFilesResponse", propOrder = { "showPendingFilesResult" }) public class ShowPendingFilesResponse { // 原有代码保持不变 }
方案3:配置Jaxb2Marshaller支持JAXBElement
在创建Jaxb2Marshaller实例时,设置supportJaxbElementClass属性为true,让Marshaller自动处理JAXBElement包装:
Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setSupportJaxbElementClass(true); marshaller.setContextPath("download.iris.models"); // 替换为你的实体类上下文路径 // 其他必要配置
内容的提问来源于stack exchange,提问作者Grafana Next
相关产品推荐
相关产品推荐

