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

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Markus
  • 4,062
  • 4
  • 39
  • 42
  • 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? – Daniel Kulp Aug 04 '11 at 14:15

5 Answers5

71

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.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • 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. – Markus Jun 15 '11 at 22:48
  • 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 provider – adam Jul 21 '11 at 21:05
  • 1
    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 :-) – virgo47 Apr 25 '13 at 20:06
  • 1
    See also: http://docs.oracle.com/javaee/5/api/javax/xml/ws/spi/Provider.html#provider() – Matt R Oct 23 '13 at 10:12
  • 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. – rveach Aug 03 '17 at 13:49
  • 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 ? – theo Nov 07 '20 at 13:24
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

shonky linux user
  • 6,131
  • 4
  • 46
  • 73
Ken Larson
  • 171
  • 1
  • 2
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();
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
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:

  • the approach of setting delegate by reflection given in EpicPandaForce's answer to this question (https://stackoverflow.com/a/31892305/109079)

  • calling the lower-level JaxWsProxyFactoryBean; this seems to avoid all calls to the javax.xml.ws.spi.FactoryFinder included with Java which is the root of the problem

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!

Community
  • 1
  • 1
Partly Cloudy
  • 6,508
  • 3
  • 27
  • 16
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
Monika Bozhinova
  • 294
  • 3
  • 16