JAX-WS = Когда установлен Apache CXF, он «крадет» реализацию JDK JAX-WS по умолчанию, как решить? - PullRequest
32 голосов
/ 16 июня 2011

У меня странная проблема.

  1. Используя wsimport, я сгенерировал код JAX-WS als из WSDL (в выделенном Java-проекте Eclipse). Это прекрасно работает в JDK6 без каких-либо внешних зависимостей (работает в Eclipse)

  2. У меня есть второй проект, где я когда-то использовал Apache CXF. Если я скопирую код, описанный в пункте 1), в этот проект, то вдруг JDK не выполнит JAX-WS (файлы, которые я сгенерировал), а Apache CXF.

Как я могу запретить Apache CXF "запускать" JAX-WS? (Проблема в том, что CXF не запускает код ...). Я также совершенно не понимаю, как Apache CXF обнаруживает эти классы. Я их не регистрировал?

Большое спасибо! Markus

Ответы [ 5 ]

59 голосов
/ 16 июня 2011

Apache CXF (точнее, cxf-rt-frontend-jaxws-*.jar) регистрируется как поставщик JAX-WS в JVM.Внутри вышеупомянутого JAR есть файл с именем: /META-INF/services/javax.xml.ws.spi.Provider со следующим содержимым:

org.apache.cxf.jaxws.spi.ProviderImpl

Если вы теперь посмотрите на метод javax.xml.ws.spi.FactoryFinder#find, вы обнаружите, что JDK ищет CLASSPATH на наличие javax.xml.ws.spi.Provider файл и возвращается к стандартной реализации Sun, если она недоступна.Таким образом, у вас есть два варианта принудительного отката:

  • либо удалить cxf-rt-frontend-jaxws-*.jar из CLASSPATH

  • , либо переопределить javax.xml.ws.spi.Provider файл, предоставленный CXF дляуказать на запасное местоположение

Второй вариант на самом деле немного проще.Просто создайте:

/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider

файл (при условии, что вы используете Maven) со следующим содержимым:

org.apache.cxf.jaxws.spi.ProviderImpl

Вот и все, протестировано с javax.xml.ws.Endpoint#publish.

16 голосов
/ 30 июля 2013

Для реализации по умолчанию введите:

com.sun.xml.internal.ws.spi.ProviderImpl

внутри /src/main/resources/META-INF/services/javax.xml.ws.spi.Provider

7 голосов
/ 08 августа 2015

Я попробовал другой, и я просто не мог заставить его работать вообще, поэтому, чтобы установить CXF, если он не был установлен в CXF, я просто переопределяю делегат внутри службы.

 try {
        loc = this.getClass().getResource(wsdlResource); 
        QName qName = new QName( wsTargetNamespace, wsName );
        service = new YourWS(loc, qName);
        Field delegateField = Service.class.getDeclaredField("delegate"); //ALLOW CXF SPECIFIC SERVICE DELEGATE ONLY!
        delegateField.setAccessible(true);
        ServiceDelegate previousDelegate = (ServiceDelegate) delegateField.get(service);
        if (!previousDelegate.getClass().getName().contains("cxf")) {
            ServiceDelegate serviceDelegate = ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance())
                .createServiceDelegate(loc, qName, service.getClass());
            log.info("The " + getClass().getSimpleName() + " delegate is changed from " + "[" + previousDelegate + "] to [" +
                serviceDelegate +
                "]");
            delegateField.set(service, serviceDelegate);
        }
        port = service.getYourWSSoap();
2 голосов
/ 31 августа 2016

Стандартные механизмы поиска не работают в OSGi (*).

Есть два способа заставить сервис выбрать реализацию CXF javax.xml.ws.spi.Provider:

  • подход установки delegate отражением, данный в ответе EpicPandaForce на этот вопрос (https://stackoverflow.com/a/31892305/109079)

  • вызов нижнего уровня JaxWsProxyFactoryBean; это, кажется, позволяет избежать всех вызовов javax.xml.ws.spi.FactoryFinder, включенных в Java, что является корнем проблемы

Вот пример последнего, для менее отважных программистов, которые предпочитают не менять рефлексию приватных полей:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getClientFactoryBean().getServiceFactory().setWsdlURL(WinRmService.WSDL_LOCATION);
factory.setServiceName(WinRmService.SERVICE);
factory.setEndpointName(WinRmService.WinRmPort);
// factory.setFeatures(...);  // if required

Service winrm = factory.create(WinRm.class);        

Client client = ClientProxy.getClient(winrm);

Пара заметок:

  • Передача URL, как указано выше, вместо простого factory.setWsdlURL(String) может потребоваться, если WSDL является ресурсом на пути к классам (избегайте неразрешимых bundle://... URL-адресов для элементов пути к классам)

  • Вам могут потребоваться дополнительные пакеты для функций (например, адресация)


(*) Что касается того, почему механизмы поиска не работают в большинстве контейнеров OSGi, ознакомьтесь с этой небольшой неприятностью в Oracle Java FactoryFinder:

private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "com.sun.org.glassfish.hk2.osgiresourcelocator.ServiceLoader";

private static boolean isOsgi() {
    try {
        Class.forName(OSGI_SERVICE_LOADER_CLASS_NAME);
        return true;
    } catch (ClassNotFoundException ignored) {
    }
    return false;
}

OSGi = Glassfish? Действительно рыбный!

1 голос
/ 13 декабря 2017

У меня была похожая проблема.В моем случае мне пришлось использовать org.apache.cxf.jaxws.spi.ProviderImpl для JAX-WS (создание конечных точек веб-службы и т. Д.) И com.sun.xml.internal.ws.spi.ProviderImpl для публикации конечных точек на com.sun.net.httpserver.HttpsServer.

Мне удалось решить эту проблему, создав собственного провайдера, который расширяет javax.xml.ws.spi.Provider, и использовать его вместо стандартного.

package provider;

import java.net.URL;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.ws.Endpoint;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.spi.Provider;
import javax.xml.ws.spi.ServiceDelegate;
import javax.xml.ws.wsaddressing.W3CEndpointReference;

import org.w3c.dom.Element;

public class MyProvider extends Provider
{

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public ServiceDelegate createServiceDelegate(URL wsdlDocumentLocation, QName serviceName, Class serviceClass)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createServiceDelegate(wsdlDocumentLocation, serviceName, serviceClass.getClass());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public Endpoint createEndpoint(String bindingId, Object implementor)
{
    try {
        return ((Provider) Class.forName("com.sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createEndpoint(bindingId, implementor);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public Endpoint createAndPublishEndpoint(String address, Object implementor)
{
    try {
        return ((Provider) Class.forName("com.sun.xml.internal.ws.spi.ProviderImpl").newInstance()).createAndPublishEndpoint(address, implementor);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public EndpointReference readEndpointReference(Source eprInfoset)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).readEndpointReference(eprInfoset);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public <T> T getPort(EndpointReference endpointReference, Class<T> serviceEndpointInterface, WebServiceFeature... features)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).getPort(endpointReference, serviceEndpointInterface, features);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

@Override
public W3CEndpointReference createW3CEndpointReference(String address, QName serviceName, QName portName, List<Element> metadata, String wsdlDocumentLocation, List<Element> referenceParameters)
{
    try {
        return ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance()).createW3CEndpointReference(address, serviceName, portName, metadata, wsdlDocumentLocation,
                referenceParameters);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

}

Затем просто создайте:

/src/main/resources/META-INF/services/javax.xml.ws.spi.Provider

файл (при условии, что вы используете Maven) со следующим содержимым:

package.MyProvider
...