JAX-WS = When Apache CXF is installed it “steals” default JDK JAX-WS implementation, how to solve?

后端 未结 5 1215
轮回少年
轮回少年 2020-11-28 03:15

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

相关标签:
5条回答
  • 2020-11-28 03:39

    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.

    0 讨论(0)
  • 2020-11-28 03:44

    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();
    
    0 讨论(0)
  • 2020-11-28 03:44

    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!

    0 讨论(0)
  • 2020-11-28 03:55

    For the default implementation put:

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

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

    0 讨论(0)
  • 2020-11-28 04:00

    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
    
    0 讨论(0)
提交回复
热议问题