CXF generated client HandlerTubeFactory does not implement TubeFactory

4.1k views Asked by At

I use wsdl2java to generate a client. When I run this client I get

java.lang.RuntimeException: MASM0015: Class [ com.sun.xml.ws.assembler.jaxws.HandlerTubeFactory ] does not implement [ com.sun.xml.internal.ws.assembler.dev.TubeFactory ] interface
at com.sun.xml.internal.ws.assembler.TubeCreator.<init>(TubeCreator.java:63)
at com.sun.xml.internal.ws.assembler.TubelineAssemblyController.initializeTubeCreators(TubelineAssemblyController.java:116)
at com.sun.xml.internal.ws.assembler.TubelineAssemblyController.getTubeCreators(TubelineAssemblyController.java:79)
at com.sun.xml.internal.ws.assembler.MetroTubelineAssembler.createClient(MetroTubelineAssembler.java:103)
at com.sun.xml.internal.ws.client.Stub.createPipeline(Stub.java:328)
at com.sun.xml.internal.ws.client.Stub.<init>(Stub.java:295)
at com.sun.xml.internal.ws.client.Stub.<init>(Stub.java:228)
at com.sun.xml.internal.ws.client.Stub.<init>(Stub.java:243)
at com.sun.xml.internal.ws.client.sei.SEIStub.<init>(SEIStub.java:84)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getStubHandler(WSServiceDelegate.java:814)
at com.sun.xml.internal.ws.client.WSServiceDelegate.createEndpointIFBaseProxy(WSServiceDelegate.java:803)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:436)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:404)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:386)
at javax.xml.ws.Service.getPort(Service.java:119)
at com.equifax.eid.soap.schema.ukidentityfraudservice.v1.wsdl.UkIdentityFraudService.getUkIdentityFraudServiceHttpPort(UkIdentityFraudService.java:72)

My pom.xml includes the following relevant dependencies (not showing all as too many)

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>3.1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>3.1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.wss4j</groupId>
        <artifactId>wss4j-ws-security-common</artifactId>
        <version>2.1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-ws-security</artifactId>
        <version>3.1.7</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-bindings-soap</artifactId>
        <version>3.1.7</version>
    </dependency>

Here is my client code:

URL eapURL = UkIdentityFraudService.WSDL_LOCATION;
UkIdentityFraudService ss = new UkIdentityFraudService(eapURL, EPA_SERVICE_NAME);
epaPort = ss.getUkIdentityFraudServiceHttpPort();
Map<String, Object> epaOutProps = new HashMap<String, Object>();
Client client = org.apache.cxf.frontend.ClientProxy.getClient(epaPort);
Endpoint epaCxfEndpoint = client.getEndpoint();
epaOutProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
epaOutProps.put(WSHandlerConstants.USER, epauser);
epaOutProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
epaOutProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, EpaPasswordCallback.class.getName());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(epaOutProps);
epaCxfEndpoint.getOutInterceptors().add(wssOut);
epaCxfEndpoint.getInInterceptors().add(new LoggingInInterceptor());
epaCxfEndpoint.getOutInterceptors().add(new LoggingOutInterceptor());

Here is the top part of the generated Service code:

import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.Service;

/**
 * This class was generated by Apache CXF 3.1.7
 * 2017-01-04T10:48:02.103Z
 * Generated source version: 3.1.7
 * 
 */ 

Thank you to pedrofb. I could only get it to work by explicitly overriding the ServiceDelegate, adding this to my code, inside a big try catch block.

    Field delegateField = Service.class.getDeclaredField("delegate"); //ALLOW CXF SPECIFIC SERVICE DELEGATE ONLY!
    delegateField.setAccessible(true);
    ServiceDelegate previousDelegate = (ServiceDelegate) delegateField.get(ss);
    if (!previousDelegate.getClass().getName().contains("cxf")) {
        ServiceDelegate serviceDelegate = ((Provider) Class.forName("org.apache.cxf.jaxws.spi.ProviderImpl").newInstance())
            .createServiceDelegate(epaLoc, EPA_SERVICE_NAME, ss.getClass());
        logger.info("The " + getClass().getSimpleName() + " delegate is changed from " + "[" + previousDelegate + "] to [" +
            serviceDelegate +
            "]");
        delegateField.set(ss, serviceDelegate);
    }
1

There are 1 answers

2
pedrofb On BEST ANSWER

The error stacktrace shows that the client is using JRE JAX-WS built-in classes com.sun.xml.internal.ws.* instead of CXF classes.

JVM selects the JAX-WS implementation scanning classpath looking for javax.xml.ws.spi.Provider. The CXF provider is located in cxf-rt-frontend-jaxws-*.jar, so the most probable reason for the issue is that jar is not correctly deployed and is not present in classpath.

Ensure CXF dependencies are really deployed in your server and found at execution time