webservice:com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.a
阿新 • • 發佈:2019-02-15
用原生jdk開發好webservice服務端介面後,和客戶端聯調的過程中調不通,服務端報錯:
java.lang.ExceptionInInitializerError at com.sun.xml.internal.ws.wsdl.PayloadQNameBasedOperationFinder.getWSDLOperationQName(PayloadQNameBasedOperationFinder.java:140) at com.sun.xml.internal.ws.wsdl.OperationDispatcher.getWSDLOperationQName(OperationDispatcher.java:76) at com.sun.xml.internal.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:84) at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:626) at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:585) at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:570) at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:467) at com.sun.xml.internal.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:299) at com.sun.xml.internal.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:593) at com.sun.xml.internal.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244) at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handleExchange(WSHttpHandler.java:95) at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handle(WSHttpHandler.java:80) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:80) at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:677) at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:649) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.ClassCastException: com.sun.xml.bind.v2.runtime.JAXBContextImpl cannot be cast to com.sun.xml.internal.bind.api.JAXBRIContext at com.sun.xml.internal.ws.fault.SOAPFaultBuilder$1.run(SOAPFaultBuilder.java:570) at com.sun.xml.internal.ws.fault.SOAPFaultBuilder$1.run(SOAPFaultBuilder.java:566) at java.security.AccessController.doPrivileged(Native Method) at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createJAXBContext(SOAPFaultBuilder.java:565) at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.<clinit>(SOAPFaultBuilder.java:555) ... 21 more 17:44:05.222 [schedulerFactoryBean_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
網上查了好久,大部分都說是因為jaxb-api.jar和Jaxb-impl,jar衝突導致的,大致有以下幾種解決方式:
1.刪掉lib目錄下的jaxb-api.jar和Jaxb-impl.jar;
2.把jdk升級到1.6以上版本;
3.在工程(我用的maven建的工程)的pom.xml中增加
以上方式我都嘗試了但都無效,我用的maven搭建的工程,為此還折騰了各種版本的引用包均無效。<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <systemPropertyVariables> <com.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize>true</com.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize> </systemPropertyVariables> </configuration> </plugin>
最後,嘗試直接在webservice釋出時就設定:
System.setProperty("javax.xml.bind.JAXBContext", "com.sun.xml.internal.bind.v2.ContextFactory");
webservice伺服器端倒是不報錯了,但是客戶端依然調不通,報錯說找不到匹配的方法。
然後,又是一番折騰,基本上都說是webservice內部jar版本與現在所用的jdk的jar有衝突,問題依然沒有解決。
後來發現如果客戶端呼叫的時候設定了QNAME的namespace就可以繞過此錯誤,附上客戶端呼叫的關鍵程式碼:
Call call = null;
try {
call = (Call)service.createCall();
call.setTargetEndpointAddress(new URL("http://localhost:8081/UserService?wsdl"));
call.setProperty("axis.connection.timeout", new Integer(3600000));
call.setTimeout(new Integer(3600000));
call.setOperationName(new javax.xml.namespace.QName("http://webservice.web.demo.com/", "queryUsers")); //用這句可以正常呼叫
//call.setOperationName("queryUsers");//用這句就報錯說找不到匹配的方法
Object res=call.invoke(new Object[]{});
PrintWriter out = response.getWriter();
out.println(res);
}catch (Exception e) {
e.printStackTrace();
}
如果不想改客戶端的呼叫程式碼,也可新增攔截器攔截webservice請求,攔截後判斷namespace是否存在不存在則加上,方法如下:
在classpath下建handler-chain.xml配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<!-- 攔截器類的包名和類名路徑 -->
<javaee:handler-class>com.xxx.xxx.web.service.WebservicePhaseInterceptor</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
在webservice的實現類上加HandlerChain配置:
@HandlerChain(file="handler-chain.xml")
public class UserWebServiceImpl implements UserWebService {
/**
程式碼省略
**/
}
SOAPHandler實現攔截請求並加namespace的類:
package com.xxx.xxx.web.service;
import java.util.Iterator;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.apache.commons.lang3.StringUtils;
public class WebservicePhaseInterceptor implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
try {
SOAPMessage msg = context.getMessage();
SOAPBody body = msg.getSOAPBody();
Iterator<?> iter = body.getChildElements();
while (iter.hasNext()) {
Object next = iter.next();
if (next instanceof SOAPElement) {
SOAPElement se = (SOAPElement) next;
String uri = se.getNamespaceURI();
if (StringUtils.isBlank(uri)) {
QName name = se.getElementQName();
QName qName = new QName("你的namespaceURI,在wsdl檔案中可以看到", name.getLocalPart());
se.setElementQName(qName);
}
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
// TODO Auto-generated method stub
return false;
}
@Override
public void close(MessageContext context) {
// TODO Auto-generated method stub
}
@Override
public Set<QName> getHeaders() {
// TODO Auto-generated method stub
return null;
}
}
攔截器的實現,參考了http://blog.csdn.net/accountwcx/article/details/46986943,感謝。
目的雖然達到了,問題也繞過去了,客戶端呼叫成功,但是問題依然沒有從根本上解決。我實在想不到好的解決方式了,如果有解決方法還請不吝留言告知哦,感激不盡。