Bereitstellen einer anderen Version von JAXB für JAX-WS in Java 1.6

Ich habe ein Drittanbieter-Jar, das mit einem jaxb-impl.jar ausgeliefert wird und dieses in seinen Klassenpfad einfügt. Das Problem ist, dass es den Anschein hat, als würde die Bereitstellung Ihrer eigenen Version von JAXB (unabhängig von der Version) den SoapFaultBuilder in JAX-WS beschädigen.

LautInoffizieller JAXB GuideEs scheint, als ob Sun den Paketnamen absichtlich geändert hat, als JAXB in das JDK integriert wurde, um Konflikte mit der Standalone-Version zu vermeiden. Der SoapFaultBuilder (Teil von JAX-WS, glaube ich), der mit dem JDK geliefert wird, ist jedoch explizit vom neuen internen Paketnamen abhängig. Dies führt dazu, dass es beim Erstellen einer Fehlermeldung fehlschlägt, wenn Sie eine eigenständige JAXB-JAR hinzugefügt haben (auch wenn es sich um dieselbe Version handelt)Nummer von JAXB).

Hier ist mein kleiner Testfall: Ich mache einen trivialen Web Service:

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

}

Und eine Implementierung, die einfach eine Ausnahme auslöst. (Da das Problem nur im SOAPFaultBuilder auftritt):

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

}

Und eine Klasse, um den Webdienst zu veröffentlichen:

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

}

Ich starte den HelloWorldPublisher und starte dann diesen Client dagegen:

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

    }

}

Dadurch wird die vom Webdienst ausgelöste Ausnahme korrekt ausgespuckt. Wenn ich jedoch eine Version von jaxb-impl.jar hinzufüge, sei es im Klassenpfad oder in der indossierten Bibliothek, erhalte ich diesen Stack-Trace:

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

Die Ausnahme tritt auf, weil com.sun.xml.bind.v2.runtime.JAXBContextImpl von meinem jaxb-impl com.sun.xml.bind.api.JAXBRIContext anstelle von com.sun.xml.internal.bind.api.JAXBRIContext (erweitert. Beachten Sie das fehlende 'interne' Unterpaket in der Pakethierarchie.

Auch nach demInoffizieller JAXB Guide, heißt es, dass Sie die indossierte Bibliothek verwenden müssen, um die Version von JAXB korrekt zu überschreiben. Wie sich herausstellt, verwendet SOAPFaultBuilder JAXBContext.newInstance (), um den Klassenpfad nach einer Datei mit dem Namen zu durchsuchen/META-INF/services/javax.xml.bind.JAXBContextLaden Sie anschließend manuell einen JAXBContext (und erstellen Sie ihn reflexiv) auf der Grundlage des in der Datei angegebenen Klassennamens. Es spielt also keine Rolle - classpath oder endorsed lib verhalten sich genauso.

Eine Problemumgehung ist das Hinzufügen-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory in die Befehlszeile, wodurch JAXBContext.newInstance () das ignoriert/META-INF/services/javax.xml.bind.JAXBContext Datei im Klassenpfad und gibt die integrierte Version von JAXB manuell an. Die andere Problemumgehung besteht darin, einfach kein eigenes JAXB anzugeben und die in das JDK integrierte Version zu verwenden. Aus dem inoffiziellen JAXB-Handbuch geht jedoch hervor, dass Sun dieses System so konzipiert hat, dass es in der Lage ist, Ihre eigene JAXB-Implementierung bereitzustellen. War jemand in der Lage, eine Version von JAXB erfolgreich bereitzustellen und weiterhin Fehlermeldungen erfolgreich zu erfassen? (Alles läuft gut für mich, solange es keine Fehler gibt, die vom Web-Service erzeugt werden).

Antworten auf die Frage(3)

Ihre Antwort auf die Frage