簡體   English   中英

在Java 1.6中為JAX-WS提供不同版本的JAXB

[英]Supplying a different version of JAXB for JAX-WS in Java 1.6

我有一個第三方jar,它附帶一個jaxb-impl.jar並將其包含在其manifest類路徑中。 問題是,似乎提供自己的JAXB版本(無論它是哪個版本)似乎打破了JAX-WS中的SoapFaultBuilder。

根據非官方的JAXB指南 ,似乎Sun在將JAXB折疊到JDK中時故意更改了包名稱,以避免與獨立版本沖突。 但是,隨JDK一起提供的SoapFaultBuilder(我相信JAX-WS的一部分)明確依賴於新的內部包名。 如果您添加了一個獨立的JAXB jar(即使它與JAXB的版本相同),這會在構建錯誤消息時導致失敗。

這是我的小測試案例:我制作一個簡單的Web服務:

package wstest;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

//Service Endpoint Interface
@WebService
@SOAPBinding(style = Style.RPC)
public interface HelloWorld{

    @WebMethod String getHelloWorldAsString(String name);

}

一個簡單拋出異常的實現。 (因為問題只出現在SOAPFaultBuilder中):

package wstest;

import javax.jws.WebService;

//Service Implementation
@WebService(endpointInterface = "wstest.HelloWorld")
public class HelloWorldImpl implements HelloWorld{

    @Override
    public String getHelloWorldAsString(String name) {
        //return "Hello World JAX-WS " + name;
        throw new RuntimeException("Exception for: " + name);
    }

}

還有一個發布Web服務的類:

package wstest;

import javax.xml.ws.Endpoint;

//Endpoint publisher
public class HelloWorldPublisher{

    public static void main(String[] args) {
       Endpoint.publish("http://localhost:9999/ws/hello", new HelloWorldImpl());
    }

}

我運行HelloWorldPublisher,然后針對它運行此客戶端:

package wstest;

import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;

public class HelloWorldClient{

    public static void main(String[] args) throws Exception {

    URL url = new URL("http://localhost:9999/ws/hello?wsdl");

        //1st argument service URI, refer to wsdl document above
    //2nd argument is service name, refer to wsdl document above
        QName qname = new QName("http://wstest/", "HelloWorldImplService");

        Service service = Service.create(url, qname);

        HelloWorld hello = service.getPort(HelloWorld.class);

        System.out.println(hello.getHelloWorldAsString("Matt"));

    }

}

這正確地吐出了Web服務引發的異常。 但是,當我添加任何版本的jaxb-impl.jar時,無論是在類路徑還是在支持的lib中,我都會得到這個堆棧跟蹤:

Exception in thread "main" java.lang.ExceptionInInitializerError
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:107)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
    at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
    at $Proxy19.getHelloWorldAsString(Unknown Source)
    at wstest.HelloWorldClient.main(HelloWorldClient.java:21)
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.<clinit>(SOAPFaultBuilder.java:533)
    ... 5 more

發生異常的原因是我的jaxb-impl中的com.sun.xml.bind.v2.runtime.JAXBContextImpl擴展了com.sun.xml.bind.api.JAXBRIContext而不是com.sun.xml.internal.bind.api.JAXBRIContext(請注意包層次結構中缺少的“內部”子包。

另外根據非官方JAXB指南 ,他們說你需要使用支持的lib才能正確覆蓋JAXB的版本。 事實證明,SOAPFaultBuilder使用JAXBContext.newInstance()在類路徑中搜索名為/META-INF/services/javax.xml.bind.JAXBContext的文件,然后根據類手動加載(並反復創建)JAXBContext文件中指定的名稱。 因此無關緊要 - classpath或endorsed lib為您提供相同的行為。

一種解決方法是將-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory添加到命令行,這會導致JAXBContext.newInstance()忽略/META-INF/services/javax.xml.bind.JAXBContext類路徑上的/META-INF/services/javax.xml.bind.JAXBContext文件,並手動指定JAXB的內置版本。 另一種解決方法是簡單地不指定您自己的JAXB並使用JDK中內置的版本,但是從非官方JAXB指南中可以看出,Sun設計此系統是為了能夠處理提供您自己的JAXB實現。 有沒有人能夠成功提供JAXB版本並仍然能夠成功捕獲故障消息? (只要沒有Web服務生成的錯誤,一切都運行正常)。

我被困在這個問題但是能夠通過設置系統屬性來使用此 論壇 問答中列出的“解決方法”:

System.setProperty("javax.xml.bind.JAXBContext", 
                   "com.sun.xml.internal.bind.v2.ContextFactory"); 

這個問題的關鍵是JAXB API發生了變化,您嘗試使用的運行時實現與JDK捆綁的JAXB API版本不匹配。

為了使用不同的版本,您應該將相應版本的jaxb-api.jarjaxws-api.jar復制到一個支持的lib(例如%JAVA_HOME%\\lib\\endorsed )。

完整的選項列表在非官方JAXB指南的7.1.2節中給出

將實現jar(例如jaxb-impl.jar)復制到endorsed lib中是錯誤的,這些應該只是在你的類路徑上。

另請注意,如果您嘗試使用較新版本的jaxb而不包含兼容版本的jaxws,則可能會遇到麻煩。 這是因為舊的jaxws試圖引用舊的jaxb,所以如果你要更改一個,請確保你同時執行這兩個操作。 com.sun.xml.internal.ws包中的堆棧跟蹤暗示了一個舊的jax-ws實現。即使最新版本的Java仍然附帶舊版本1 jaxb和jaxws apis)。

API文檔中描述了另一種可能的解決方案,無需修改系統屬性

https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/api/javax/xml/bind/JAXBContext.html

您可以將jaxb.properties文件放在模型類的包中。

javax.xml.bind.context.factory=com.sun.xml.internal.bind.v2.ContextFactory

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM