37 Stimmen

JAX-WS = Wenn Apache CXF installiert wird, "stiehlt" es die standardmäßige JDK JAX-WS-Implementierung, wie kann man das lösen?

Ich habe ein seltsames Problem.

  1. Mit wsimport habe ich auch JAX-WS Code aus einer WSDL generiert (in einem eigenen eclipse java Projekt). Dies funktioniert gut in JDK6 ohne externe Abhängigkeiten (in Eclipse ausgeführt)

  2. Ich habe ein zweites Projekt, bei dem ich einmal Apache CXF verwendet habe. Wenn ich den unter 1.) beschriebenen Code in dieses Projekt kopiere, führt plötzlich nicht das JDK die JAX-WS-Sachen aus (Dateien, die ich generiert habe), sondern Apache CXF.

Wie kann ich verhindern, dass Apache CXF die JAX-WS-Sachen "ausführt". (Das Problem ist, dass CXF den Code nicht ausführen kann...). Ich verstehe auch überhaupt nicht, wie Apache CXF diese Klassen entdeckt. Ich habe sie nirgendwo registriert?

Herzlichen Dank! Markus

73voto

Tomasz Nurkiewicz Punkte 322861

Apache CXF ( cxf-rt-frontend-jaxws-*.jar um genau zu sein) registriert sich selbst als JAX-WS-Anbieter in der JVM. Innerhalb des oben erwähnten JAR gibt es eine Datei namens: /META-INF/services/javax.xml.ws.spi.Provider mit folgendem Inhalt:

org.apache.cxf.jaxws.spi.ProviderImpl

Wenn Sie sich nun ansehen javax.xml.ws.spi.FactoryFinder#find Methode werden Sie feststellen, dass JDK den CLASSPATH nach dem Vorhandensein von javax.xml.ws.spi.Provider Datei und greift auf die Standardimplementierung von Sun zurück, wenn diese nicht verfügbar ist. Sie haben also zwei Möglichkeiten, den Fallback zu erzwingen:

  • entweder entfernen cxf-rt-frontend-jaxws-*.jar von CLASSPATH

  • oder außer Kraft setzen javax.xml.ws.spi.Provider Datei, die von CXF bereitgestellt wird, um auf den Ausweichort zu verweisen

Die zweite Möglichkeit ist eigentlich etwas einfacher. Einfach erstellen:

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

Datei (vorausgesetzt, Sie verwenden Maven) mit folgendem Inhalt:

org.apache.cxf.jaxws.spi.ProviderImpl

Das war's, getestet mit javax.xml.ws.Endpoint#publish .

17voto

Ken Larson Punkte 171

Für die Standardimplementierung setzen:

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

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

7voto

EpicPandaForce Punkte 75417

Ich habe versucht, die andere und ich konnte einfach nicht machen es überhaupt funktionieren, so CXF zu setzen, wenn es nicht auf CXF gesetzt wurde, ich einfach überschreiben den Delegaten innerhalb des Dienstes.

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

6voto

Partly Cloudy Punkte 5708

Die Standard-Findungsmechanismen scheinen in OSGi nicht gut zu funktionieren (*).

Es gibt zwei Möglichkeiten, wie ich den Dienst zwingen kann, die CXF-Implementierung von javax.xml.ws.spi.Provider :

  • der Ansatz der Einstellung delegate durch Überlegungen in der Antwort von EpicPandaForce auf diese Frage ( https://stackoverflow.com/a/31892305/109079 )

  • Aufruf der untergeordneten Ebene JaxWsProxyFactoryBean ; dies scheint alle Aufrufe der javax.xml.ws.spi.FactoryFinder die in Java enthalten ist und die Ursache des Problems ist

Hier ist ein Beispiel für letzteres, für weniger unerschrockene Programmierer, die es vorziehen, private Felder nicht reflektierend zu ändern:

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

Ein paar Anmerkungen:

  • Übergabe einer URL wie oben, statt der einfacheren factory.setWsdlURL(String) kann erforderlich sein, wenn die WSDL eine Ressource im Klassenpfad ist (Vermeidung unauflösbarer bundle://... URLs für Klassenpfadelemente)

  • Für bestimmte Funktionen (z. B. Adressierung) benötigen Sie möglicherweise zusätzliche Pakete.


(*) Warum die Suchmechanismen in den meisten OSGi-Containern nicht funktionieren, kann man in den Oracle Java's 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? In der Tat fischig!

1voto

Monika Bozhinova Punkte 284

Ich hatte ein ähnliches Problem. In meinem Fall musste ich Folgendes verwenden org.apache.cxf.jaxws.spi.ProviderImpl für JAX-WS-Sachen (Erstellen von Webservice-Endpunkten usw.) und com.sun.xml.internal.ws.spi.ProviderImpl für die Veröffentlichung von Endpunkten auf com.sun.net.httpserver.HttpsServer .

Ich konnte dieses Problem lösen, indem ich meinen eigenen Anbieter erstellt habe, der die javax.xml.ws.spi.Provider und diese anstelle der Standardeinstellung zu verwenden.

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

}

Dann erstellen Sie einfach:

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

Datei (vorausgesetzt, Sie verwenden Maven) mit folgendem Inhalt:

package.MyProvider

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X