JAX - WS = po zainstalowaniu Apache CXF "kradnie" domyślną implementację JDK JAX-WS, jak rozwiązać?

Mam dziwny problem.

  1. Za pomocą wsimportu wygenerowałem Kod als JAX-WS z WSDL (w dedykowanym projekcie eclipse java). To działa dobrze w JDK6 bez żadnych zewnętrznych zależności (działa w Eclipse)

  2. Mam drugi projekt, w którym kiedyś korzystałem z Apache CXF. Jeśli skopiuję Kod opisany w 1.) do tego projektu, nagle nie JDK wykonuje rzeczy JAX-WS (pliki, które wygenerowałem), ale raczej Apache CXF.

Jak mogę zapobiec Apache CXF "uruchamianiu" rzeczy JAX-WS. (Problem w tym, że CXF nie uruchamia kodu...). Zupełnie też nie rozumiem, w jaki sposób Apache CXF odkrywa te klasy. Ja ich nie zarejestrowałem?

Dziękuję bardzo! Markus

Author: Donal Fellows, 2011-06-15

5 answers

Apache CXF (cxf-rt-frontend-jaxws-*.jar aby być precyzyjnym) rejestruje się jako dostawca JAX-WS w JVM. Wewnątrz wspomnianego słoika znajduje się plik o nazwie: /META-INF/services/javax.xml.ws.spi.Provider o następującej treści:

org.apache.cxf.jaxws.spi.ProviderImpl

Jeśli teraz przyjrzysz się metodzie javax.xml.ws.spi.FactoryFinder#find odkryjesz, że JDK przeszukuje ścieżkę klasową pod kątem obecności pliku javax.xml.ws.spi.Provider i wraca do domyślnej implementacji Sun, jeśli nie jest dostępna. Więc masz dwie opcje, aby wymusić odwrót:

  • Albo usunąć cxf-rt-frontend-jaxws-*.jar z CLASSPATH

  • Lub nadpisać javax.xml.ws.spi.Provider plik dostarczony przez CXF, aby wskazać lokalizację awaryjną

Druga opcja jest właściwie nieco łatwiejsza. Po prostu utwórz:

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

Plik (zakładając, że używasz Mavena) o następującej treści:

org.apache.cxf.jaxws.spi.ProviderImpl

To jest to, przetestowane z javax.xml.ws.Endpoint#publish.

 64
Author: Tomasz Nurkiewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-15 21:33:32

Dla domyślnej implementacji wpisz:

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

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

 17
Author: Ken Larson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-28 03:07:23

Próbowałem drugiego i nie mogłem go w ogóle uruchomić, więc aby ustawić CXF, jeśli nie był ustawiony na CXF, po prostu nadpisuję delegata wewnątrz usługi.

 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();
 7
Author: EpicPandaForce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-08 10:50:31

Standardowe mechanizmy wyszukiwania nie działają dobrze w OSGi (*).

Są dwa sposoby na to, aby zmusić serwis do odebrania implementacji CXF javax.xml.ws.spi.Provider:

  • Podejście ustawienia delegate przez refleksję podaną w odpowiedzi EpicPandaForce na to pytanie ( https://stackoverflow.com/a/31892305/109079)

  • Wywołanie niższego poziomu JaxWsProxyFactoryBean; wydaje się to unikać wszystkich wywołań do javax.xml.ws.spi.FactoryFinder dołączonych do Javy, która jest źródło problemu

Oto przykład tego ostatniego, dla mniej nieustraszonych programistów, którzy wolą nie zmieniać ponownie pól prywatnych:

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

Kilka uwag:

  • Jeśli WSDL jest zasobem na classpath (unikaj nierozwiązywalnych adresów URL bundle://... dla pozycji classpath)

  • Możesz potrzebować dodatkowych pakietów dla funkcji (takich jak adresowanie)


(*) jeśli chodzi o to, dlaczego mechanizmy wyszukiwania nie działają w większości kontenerów OSGi, sprawdź to trochę paskudne w 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? W rzeczy samej!

 6
Author: Partly Cloudy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:13

Miałem podobny problem. W moim przypadku musiałem użyć org.apache.cxf.jaxws.spi.ProviderImpl do rzeczy JAX-WS (tworzenie punktów końcowych webservice itp.) i com.sun.xml.internal.ws.spi.ProviderImpl do publikacji punktów końcowych na com.sun.net.httpserver.HttpsServer.

Udało mi się to rozwiązać, tworząc własny provider, który rozszerza javax.xml.ws.spi.Provider i używając go zamiast domyślnego.

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

}

Następnie wystarczy utworzyć:

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

Plik (zakładając, że używasz Mavena) o następującej treści:

package.MyProvider
 1
Author: Monika Bozhinova,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-13 13:21:57