Dostarczenie innej wersji JAXB dla JAX-WS w Javie 1.6

Mam słoik innej firmy, który jest dostarczany z jaxb-impl.jar i dołącza go do manifestu ścieżki klas. Problem polega na tym, że wydaje się, że dostarczenie własnej wersji JAXB (niezależnie od wersji, w jakiej może być) wydaje się łamać SoapFaultBuilder w JAX-WS.

WedługNieoficjalny przewodnik JAXBwygląda na to, że Sun celowo zmienił nazwę pakietu, gdy złożył JAXB w JDK, aby uniknąć konfliktów z wersją autonomiczną. Jednak SoapFaultBuilder (część JAX-WS, którą uważam) dostarczana z JDK jest wyraźnie zależna od nowej, wewnętrznej nazwy pakietu. Powoduje to niepowodzenie podczas tworzenia komunikatu o błędzie, jeśli dodano autonomiczny jar JAXB (nawet jeśli jest to ta sama wersjanumer JAXB).

Oto mój mały przypadek testowy: robię banalną usługę internetową:

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

}

I implementacja, która po prostu zgłasza wyjątek. (Ponieważ problem występuje tylko w 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);
    }

}

I klasa do opublikowania usługi internetowej:

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

}

Uruchamiam HelloWorldPublisher, a następnie uruchamiam tego klienta przeciwko temu:

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

    }

}

To poprawnie wypowiada wyjątek, który został zgłoszony przez usługę sieci Web. Jednak gdy dodam dowolną wersję jaxb-impl.jar, czy to w ścieżce klasy, czy w zatwierdzonej bibliotece, otrzymuję ten ślad stosu:

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

Wyjątek występuje, ponieważ com.sun.xml.bind.v2.runtime.JAXBContextImpl z mojego jaxb-impl rozszerza com.sun.xml.bind.api.JAXBRIContext zamiast com.sun.xml.internal.bind.api.JAXBRIContext ( zanotuj brakujący „pakiet wewnętrzny” w hierarchii pakietów).

Również wedługNieoficjalny przewodnik JAXB, twierdzą, że musisz użyć zatwierdzonej biblioteki, aby poprawnie zastąpić wersję JAXB. Jak się jednak okazuje, SOAPFaultBuilder używa JAXBContext.newInstance () do przeszukiwania ścieżki klas w poszukiwaniu pliku o nazwie/META-INF/services/javax.xml.bind.JAXBContext, następnie ręcznie załaduj (i odruchowo utwórz) tekst JAXBContext na podstawie nazwy klasy podanej w pliku. Więc to nie ma znaczenia - ścieżka classpath lub lib zatwierdzona daje to samo zachowanie.

Jednym obejściem jest dodanie-Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory do linii poleceń, która powoduje, że JAXBContext.newInstance () ignoruje/META-INF/services/javax.xml.bind.JAXBContext plik w ścieżce klasy i ręcznie określa wbudowaną wersję JAXB. Innym obejściem jest po prostu nie określenie własnego JAXB i użycie wersji wbudowanej w JDK, ale wydaje się, że z Nieoficjalnego Przewodnika JAXB, Sun zaprojektował ten system, aby móc obsłużyć dostarczanie własnej implementacji JAXB. Czy ktoś był w stanie z powodzeniem dostarczyć wersję JAXB i nadal być w stanie skutecznie przechwytywać komunikaty o błędach? (Wszystko działa dobrze dla mnie, dopóki usługa sieci Web nie generuje błędów).

questionAnswers(3)

yourAnswerToTheQuestion