JAX-WS = When Apache CXF is installed it "steals" default JDK JAX-WS implementation, how to solve?
Asked Answered
B

5

37

I have a strange problem.

  1. Using wsimport I generated als JAX-WS Code from a WSDL (in a dedicated eclipse java project). This works fine in JDK6 without any external dependencies (running in Eclipse)

  2. I have second project where I once used Apache CXF. If I copy the Code described in 1.) into this project, suddenly not the JDK executes the JAX-WS stuff (files I generated), but rather Apache CXF.

How can I prevent Apache CXF "running" the JAX-WS stuff. (Problem is, CXF Fails to run the code...). I also completely do not understand how Apache CXF discovers these classes. I did not register them anywere?

Thank you very much! Markus

Bursary answered 15/6, 2011 at 21:3 Comment(1)
Honestly, I'd be most interested in why CXF fails to run the code. CXF is completely JAX-WS compliant so it should be a drop in replacement for the in-jdk jax-ws implementation. Bug report?Para
T
73

Apache CXF (cxf-rt-frontend-jaxws-*.jar to be precise) registers itself as a JAX-WS provider in the JVM. Inside the aforementioned JAR there is a file named: /META-INF/services/javax.xml.ws.spi.Provider with the following contents:

org.apache.cxf.jaxws.spi.ProviderImpl

If you now look at javax.xml.ws.spi.FactoryFinder#find method you will discover that JDK searches the CLASSPATH for the presence of javax.xml.ws.spi.Provider file and falls back to default Sun implementation if not available. So you have two options to force fallback:

  • either remove cxf-rt-frontend-jaxws-*.jar from CLASSPATH

  • or override javax.xml.ws.spi.Provider file provided by CXF to point to fallback location

The second option is actually a bit easier. Simply create:

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

file (assuming you are using Maven) with the following contents:

org.apache.cxf.jaxws.spi.ProviderImpl

That's it, tested with javax.xml.ws.Endpoint#publish.

Testudinal answered 15/6, 2011 at 21:33 Comment(6)
Hello Tomasz, thank you very much for your geneours and valuable help. It is very much appreciated!!! (Just in case you know this: Is it correct that I can either use JDK OR CXF? So there is no option to tell CXF to leave some of my classes/packages untouched and in the and use both somewho in parallel...) Thanks.Bursary
Your second option tells you how to configure JAX-WS to use CXF, what if I want JAX-WS to NOT use CXF? Neither the META-INF/javax.xml.ws.spi.Provider file nor the cxf-rt-frontend-jaxws jar are on my classpath, so I can't figure out how to prevent CXF from becoming the JAX-WS providerUndue
I was trying to make CXF run on WebLogic 11g 10.3.6 for a couple of days already - this was the key. It seems that the Provider file in META-INF (in EAR module) made the trick. I'm on the verge of tears. Thank you :-)Frogfish
See also: docs.oracle.com/javaee/5/api/javax/xml/ws/spi/…Horal
Overriding META-INF/services/javax.xml.ws.spi.Provider doesn't always work for all servers like for Websphere where it forces it's own implementation on you.Anisotropic
This seems like a genuine classpath problem and seems to be working by simply placing the cxf-rt-frontend-jaxws-*.jar higher on the classpath (than the jar containing javax.xml.... ). Then the javax.xml.ws.spi.Provider cxf one will surely get picked up. No ?Hahnemann
S
17

For the default implementation put:

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

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

Swamper answered 30/7, 2013 at 9:15 Comment(0)
C
7

I tried the other and I just couldn't make it work at all, so to set CXF if it was not set to CXF, I just override the delegate inside the service.

 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();
Cottier answered 8/8, 2015 at 10:50 Comment(3)
I tried all the answers but for my application this is the only way the solved my problem , Thanks :)Nurseryman
(relevant question with same answer: https://mcmap.net/q/298356/-cxf-classcastexception-seistub-clientproxy )Cottier
The Service.class is javax.xml.ws.Service.Cottier
M
6

The standard finding mechanisms don't seem to work nicely in OSGi (*).

There are two ways I've gotten to work forcing the service to pick up the CXF implementation of javax.xml.ws.spi.Provider:

Here is an example of the latter, for less intrepid coders who prefer not reflectively changing private fields:

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

A couple of notes:

  • Passing a URL as above, rather than the simpler factory.setWsdlURL(String) may be needed if the WSDL is a resource on the classpath (avoid unresolvable bundle://... URLs for classpath items)

  • You may need additional bundles for features (such as addressing)


(*) As for why the finding mechanisms don't work in most OSGi containers, check out this little bit of nasty in 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? Fishy indeed!

Maitund answered 31/8, 2016 at 14:0 Comment(0)
B
1

I had a similar problem. In my case I had to use org.apache.cxf.jaxws.spi.ProviderImpl for JAX-WS stuff (creating webservice endpoints etc.) and com.sun.xml.internal.ws.spi.ProviderImpl for publishing endpoints on com.sun.net.httpserver.HttpsServer.

I managed to solve this by creating my own provider which extends javax.xml.ws.spi.Provider and using it instead of the default one.

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

}

Then simply create:

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

file (assuming you are using Maven) with the following contents:

package.MyProvider
Birdbath answered 13/12, 2017 at 13:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.