2013-01-04 13 views
30

私は、jaxb-impl.jarに付属しているサードパーティのjarをマニフェストのクラスパスに含めています。問題は、JAXBの独自のバージョンを提供しているかのように(どのバージョンであろうと)、JAX-WSのSoapFaultBuilderを壊しているようです。Java 1.6でJAX-WS用のJAXBの別のバージョンを提供

Unofficial JAXB Guideによれば、スタンドアロンバージョンとの競合を避けるために、SunがJAXBをJDKに折り畳んだときにSunが故意にパッケージ名を変更したようです。しかし、JDKに同梱されているSoapFaultBuilder(JAX-WSの一部)は、新しい内部パッケージ名に明示的に依存しています。これにより、スタンドアロンのJAXB jarを追加した場合(JAXBの番号のJAXBと同じバージョンであっても)、障害メッセージを作成するときにエラーが発生します。

は、ここに私の小さなテストケースである:

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); 

} 

そして、単に例外をスロー実装:私は些細なWebサービスを作ります。 (問題のみ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 

例外があるためcom.sun.xml.bind.v2を発生します私のjaxb-implの.runtime.JAXBContextImplは、com.sun.xml.internal.bind.api.JAXBRIContextの代わりにcom.sun.xml.bind.api.JAXBRIContextを拡張します(パッケージ階層内の '内部'サブパッケージがないことに注意してください)。 )。

また、Unofficial JAXB Guideによれば、JAXBのバージョンを正しく上書きするには、承認されたライブラリを使用する必要があると言われています。しかし、SOAPFaultBuilderはJAXBContext.newInstance()を使用してクラスパスを検索して/META-INF/services/javax.xml.bind.JAXBContextという名前のファイルを探し、ファイルで指定されたクラス名に基づいて手動でJAXBContextをロードします(反射的に作成します)。つまり、classpathやendorsed libは同じ動作をします。

回避策の1つはコマンドラインに追加することです。これにより、JAXBContext.newInstance()はクラスパス上の/META-INF/services/javax.xml.bind.JAXBContextファイルを無視し、手動でJAXBの組み込みバージョンを指定します。もう1つの回避策は、独自のJAXBを指定せずにJDKに組み込まれたバージョンを使用することですが、Unofficial JAXB Guideから、Sunが独自のJAXB実装の提供を処理できるようにこのシステムを設計したようです。誰でもJAXBのバージョンを正常に提供でき、しかも障害メッセージを正常に取得できるようになっていますか? (Webサービスによって生成された障害がない限り、すべてがうまく動作します)。

答えて

4

JAXB APIに変更があり、使用しようとしている実行時の実装が、JDKにバンドルされているJAXB APIのバージョンと一致しません。

異なるバージョンを使用するには、対応するバージョンjaxb-api.jarjaxws-api.jarを承認済みのlib(たとえば%JAVA_HOME%\lib\endorsed)にコピーする必要があります。

オプションの完全なリストは、承認のlibに(例えばJAXB-impl.jarの)実装のjarファイルをコピーするのは間違いですセクション7.1.2 of the Unofficial JAXB Guide

で与えられ、これらは単にあなたのクラスパス上になければなりません。

互換性のあるバージョンのjaxwsも含めずに新しいバージョンのjaxbを使用しようとすると、問題が発生する可能性があります。これは、古いjaxwsが古いjaxbを参照しようとするためです。変更する場合は、両方を行うことを確認してください。 (パッケージ内のスタックトレースcom.sun.xml.internal.wsには、古いjax-ws実装が関係しています。最新バージョンのJavaでも、古いバージョン1のjaxbとjaxws apisが付属しています)。

+0

ご回答ありがとうございます。それはいくつかの良い情報を持っていますが、私はそれが完全に正しいとは思わない。 JAXBとJAX-WSの両方をオーバーライドする必要があるようです。しかし、JDKが提供するバージョンと一致する独自のJAXB jarを提供しようとしても(この質問で述べたように)、バージョンの競合とは関係がないようです。 'internal'パッケージ名は古いものではありません。ユーザー提供のJAXBとの競合を避けるため、Sunによって導入されました。 (JAXB非公式ガイドの第2回目の紹介を参照してください。)Java 1.7 u17にはまだこの内部パッケージ名があります。 –

+1

{{com.sun.xml.internal.ws}}は古いJAXWSバージョンであり、最新のJavaリリースでも更新されていません。 – gb96

+0

あなたの問題から正常に問題を再現し、jaxwsの最新バージョン(lib/endorsedにjaxws-api.jarを追加したもの)を使用するだけで解決しました。わかりやすく答えを更新しました。それでも問題がある場合は教えてください.GitWorksなどでEclipseワークスペースを共有できます。 – gb96

37

私はこの問題に引っかかっが、そのようにシステムプロパティを設定することで、この フォーラム Q & Aに記載されている「回避」を使用することができた。

System.setProperty("javax.xml.bind.JAXBContext", 
        "com.sun.xml.internal.bind.v2.ContextFactory"); 
関連する問題