WebSphere 9中SOAP客户端首调成功后续失败的UnmarshalException问题
问题:WebSphere 9.0.5.13中SOAP客户端首次调用正常,后续调用反序列化失败
现象与异常信息
首次调用WebService服务正常,但后续所有调用均抛出反序列化异常:
[javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.mycompany.com", local:"MyOCRFileRequestRs"). Expected elements are (none)]
当前环境配置
- 应用类加载器设置为parent last(父类最后)
- 已添加JVM参数:
-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory - 尝试添加JVM自定义属性
com.ibm.xml.xlxp.jaxb.opti.level=0,问题仍未解决
核心调用代码
private MyOCRFileRequestRsType callMyOCRService(MyOCRFileRequestRqType MyOCRRequest) throws Exception { String headerValue = "Bearer "+MyTokenClient.getToken(); MyOCRFileRequest port= esbOcrSerice.getMyOCRFileRequestSOAP11(); Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext(); requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,ConfigManager.getMyOCRRequestUrl().split("[?]")[0]); requestContext.put("javax.xml.ws.http.request.headers", Collections.singletonMap("Authorization", Collections.singletonList(headerValue))); try { return port.MyOCRFileRequest(MyOCRRequest); } catch (Exception e) { throw e; } }
相关接口定义
@WebService(name = "MyOCRFileRequest", targetNamespace = "http://www.mycompany.com") @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE) @XmlSeeAlso({ ObjectFactory.class }) public interface MyOCRFileRequest { /** * * @param MyOCRFileRequestRq * @return * returns com.mycompany.idrak.MyOCRFileRequestRsType */ @WebMethod(operationName = "MyOCRFileRequest", action = "MyOCRFileRequest") @WebResult(name = "MyOCRFileRequestRs", targetNamespace = "http://www.mycompany.com", partName = "MyOCRFileRequestRs") public MyOCRFileRequestRsType MyOCRFileRequest( @WebParam(name = "MyOCRFileRequestRq", targetNamespace = "http://www.mycompany.com", partName = "MyOCRFileRequestRq") MyOCRFileRequestRqType MyOCRFileRequestRq); }
相关实体类定义
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "MyOCRFileRequestRs_Type", propOrder = { "msgRsHdr", "body" }) public class MyOCRFileRequestRsType { @XmlElement(name = "MsgRsHdr", required = true) protected MsgRsHdrType msgRsHdr; @XmlElement(name = "Body") protected MyOCRFileRequestRsBodyType body; public MsgRsHdrType getMsgRsHdr() { return msgRsHdr; } public void setMsgRsHdr(MsgRsHdrType value) { this.msgRsHdr = value; } public MyOCRFileRequestRsBodyType getBody() { return body; } public void setBody(MyOCRFileRequestRsBodyType value) { this.body = value; } }
解决方案:调整WebSphere配置及代码优化
1. 修正JAXB上下文类加载器隔离
在WebSphere控制台中进入应用的类加载器设置页面:
- 开启**"为应用使用隔离类加载器"**(对应英文:Use an isolated class loader for this application)
- 确保应用自身的JAXB实现类(com.sun.xml.bind.*)优先加载,避免与WebSphere内置JAXB组件冲突
2. 调整JVM参数,指定正确的JAXB上下文工厂
替换原有的JAXBContext参数为:
-Djavax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory
注:原参数javax.xml.bind.JAXBContext为旧版配置,WebSphere对javax.xml.bind.JAXBContextFactory的识别更准确。
3. 禁用WebSphere的JAXB上下文缓存
保留com.ibm.xml.xlxp.jaxb.opti.level=0的同时,添加以下JVM参数:
-Dcom.ibm.ws.jaxb.cache.context=false
该参数会阻止WebSphere复用错误的JAXB上下文实例,避免后续调用时出现反序列化匹配问题。
4. 代码优化:复用Port实例并重置上下文
当前代码每次调用创建新Port实例,可能引发类加载上下文混乱。可将Port实例缓存为线程安全的单例,并在每次调用时重置请求上下文:
// 线程安全的单例Port缓存 private static volatile MyOCRFileRequest cachedPort; private MyOCRFileRequestRsType callMyOCRService(MyOCRFileRequestRqType MyOCRRequest) throws Exception { String headerValue = "Bearer "+MyTokenClient.getToken(); MyOCRFileRequest port; // 双重检查锁定创建单例Port if (cachedPort == null) { synchronized (this.getClass()) { if (cachedPort == null) { port = esbOcrSerice.getMyOCRFileRequestSOAP11(); cachedPort = port; } else { port = cachedPort; } } } else { port = cachedPort; } Map<String, Object> requestContext = ((BindingProvider) port).getRequestContext(); // 重置请求地址和头部,避免复用旧数据 requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, ConfigManager.getMyOCRRequestUrl().split("[?]")[0]); requestContext.put("javax.xml.ws.http.request.headers", Collections.singletonMap("Authorization", Collections.singletonList(headerValue))); try { return port.MyOCRFileRequest(MyOCRRequest); } catch (Exception e) { throw e; } }
5. 验证ObjectFactory的元素映射
确保wsimport生成的ObjectFactory类包含MyOCRFileRequestRs元素的正确映射,示例如下:
@XmlElementDecl(namespace = "http://www.mycompany.com", name = "MyOCRFileRequestRs") public JAXBElement<MyOCRFileRequestRsType> createMyOCRFileRequestRs(MyOCRFileRequestRsType value) { return new JAXBElement<MyOCRFileRequestRsType>(_MyOCRFileRequestRs_QNAME, MyOCRFileRequestRsType.class, null, value); }
若缺少该映射,需重新生成客户端代码,确保WSDL的命名空间和元素名称与实体类注解完全匹配。
内容的提问来源于stack exchange,提问作者Mahmoud Saleh
相关产品推荐
相关产品推荐

