Подтвердить что ты не робот

Поставка другой версии JAXB для JAX-WS в Java 1.6

У меня есть сторонняя банка, которая поставляется с jaxb-impl.jar и включает ее в свой явный путь к классам. Проблема в том, что, по-видимому, поставка вашей собственной версии JAXB (независимо от того, какая версия она может быть), по-видимому, разбивает SoapFaultBuilder в JAX-WS.

В соответствии с Неофициальным руководством JAXB кажется, что Sun намеренно изменило имя пакета, когда оно сместило JAXB в JDK, чтобы избежать конфликты с автономной версией. Однако SoapFaultBuilder (часть JAX-WS, я считаю), который поставляется с JDK, явно зависит от нового внутреннего имени пакета. Это приводит к сбою при создании сообщения о неисправности, если вы добавили автономную банку 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);

}

И реализация, которая просто выдает исключение. (Так как проблема возникает только в 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);
    }

}

И класс для публикации веб-службы:

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

    }

}

Это правильно вычеркивает исключение, которое было вызвано веб-службой. Однако, когда я добавляю любую версию 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.runtime.JAXBContextImpl из моего jaxb-impl расширяет com.sun.xml.bind.api.JAXBRIContext вместо com.sun.xml.internal.bind.api.JAXBRIContext(обратите внимание на отсутствующий "внутренний" подпакет в иерархии пакетов).

Также в соответствии с Неофициальным руководством JAXB, они говорят, что вам нужно использовать одобренную lib, чтобы правильно переопределить версию JAXB. Как оказалось, SOAPFaultBuilder использует JAXBContext.newInstance() для поиска пути к классу для файла с именем /META-INF/services/javax.xml.bind.JAXBContext, затем вручную загружает (и рефлексивно) создает JAXBContext на основе имени класса, указанного в файле. Так что это не имеет значения - classpath или одобренная lib дает вам такое же поведение.

Обходным путем является добавление -Djavax.xml.bind.JAXBContext=com.sun.xml.internal.bind.v2.ContextFactory в командную строку, что приводит к тому, что JAXBContext.newInstance() игнорирует файл /META-INF/services/javax.xml.bind.JAXBContext в пути к классам и вручную указывает встроенную версию JAXB. Другим обходным решением является просто не указывать ваш собственный JAXB и использовать версию, встроенную в JDK, но, как видно из Неофициального руководства JAXB, Sun разработала эту систему, чтобы иметь возможность обрабатывать вашу собственную реализацию JAXB. Кто-нибудь смог успешно предоставить версию JAXB и все еще иметь возможность успешно записывать сообщения об ошибках? (Все работает отлично для меня, пока нет ошибок, сгенерированных веб-службой).

4b9b3361

Ответ 1

Я застрял в этой проблеме, но смог использовать "работу вокруг", указанную в этом форуме Q & A, установив системное свойство следующим образом:

System.setProperty("javax.xml.bind.JAXBContext", 
                   "com.sun.xml.internal.bind.v2.ContextFactory"); 

Ответ 2

Суть этой проблемы заключается в изменении JAXB API, используемая реализация выполнения, которую вы пытаетесь использовать, не соответствует версии API JAXB в комплекте с JDK.

Чтобы использовать другую версию, вы должны скопировать соответствующие версии jaxb-api.jar и jaxws-api.jar в одобренную библиотеку lib (например, %JAVA_HOME%\lib\endorsed).

Полный список параметров приведен в разделе 7.1.2 Неофициального руководства JAXB

Ошибочно копировать баннеры реализации (например, jaxb-impl.jar) в одобренную библиотеку lib, они должны быть просто в вашем пути к классам.

Также обратите внимание, что вы можете столкнуться с проблемами, если попытаетесь использовать более новую версию jaxb, не включая совместимую версию jaxws. Это связано с тем, что старые jaxws пытаются ссылаться на старый jaxb, поэтому, если вы меняете, убедитесь, что вы оба. (Stack-trace в пакете com.sun.xml.internal.ws подразумевает старую реализацию jax-ws. Даже последняя версия Java по-прежнему поставляется со старой версией jaxb и jaxws apis).