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