私は、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サービスによって生成された障害がない限り、すべてがうまく動作します)。
ご回答ありがとうございます。それはいくつかの良い情報を持っていますが、私はそれが完全に正しいとは思わない。 JAXBとJAX-WSの両方をオーバーライドする必要があるようです。しかし、JDKが提供するバージョンと一致する独自のJAXB jarを提供しようとしても(この質問で述べたように)、バージョンの競合とは関係がないようです。 'internal'パッケージ名は古いものではありません。ユーザー提供のJAXBとの競合を避けるため、Sunによって導入されました。 (JAXB非公式ガイドの第2回目の紹介を参照してください。)Java 1.7 u17にはまだこの内部パッケージ名があります。 –
{{com.sun.xml.internal.ws}}は古いJAXWSバージョンであり、最新のJavaリリースでも更新されていません。 – gb96
あなたの問題から正常に問題を再現し、jaxwsの最新バージョン(lib/endorsedにjaxws-api.jarを追加したもの)を使用するだけで解決しました。わかりやすく答えを更新しました。それでも問題がある場合は教えてください.GitWorksなどでEclipseワークスペースを共有できます。 – gb96