Which is the best maven's plugin to generate a Web Service Client?

I have to generate a WS Client and I can't decide wich plugin to use. Until now my options are: jaxb2-maven-plugin, axistools-maven-plugin and jaxws-maven-plugin.

First, the jaxb2-maven-plugin is not really intended to generate WS clients. ELIMINATED.

Second, personally I wouldn't use Axis even for client development only so I won't recommend using the axistools-maven-plugin. ELIMINATED.

This leaves us with the JAX-WS RI and the Apache CXF stacks, and their respective Maven plugins: the JAX-WS Maven Plugin (instructions to use the JAX-WS Maven Plugin can be found on the Usage page) and the cxf-codegen-plugin.

Regarding the pros and cons, I would summarize them like this:

  • JAX-WS RI is included in Java 6, but the documentation is more "rough" (although you'll find plenty of tutorials about JAX-WS RI too).
  • Apache CXF is better documentated and provide more flexibility if you want to go beyond the spec.

At the end, both choices are decent so I suggest to browse the links a bit and to make your own opinion.


I use jaxws-maven-plugin. In my opinion, JAX-WS is the de-facto standard implementation for WS. It has much better generated code than AXIS, and easier to config and implement. It has Maven and Spring support.

Generating client-side code from wsdl file, in pom.xml:

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxws-maven-plugin</artifactId>
            <executions>
                <execution>
                    <id>generate-reports-ws-code</id>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>wsimport</goal>
                    </goals>
                    <configuration>

<!-- This property is used to support having multiple <execution> elements. The plugin has, from some reason, only one timestamp file per the all executions, thus if you have two executions, it doesn't know exactly when to recompile the code. Here we tell it explicitly to have one timestamp file per each execution -->                            <staleFile>${project.build.directory}/jaxws/stale/.staleFlag.reports</staleFile>
                        <packageName>com.acme.reports.ws.api</packageName>
                        <wsdlDirectory>${project.build.directory}/wsdl</wsdlDirectory>
                        <wsdlFiles>
                            <wsdlFile>InternalReportsAPIService.wsdl</wsdlFile>
                        </wsdlFiles>
                        <verbose>true</verbose>
                        <sourceDestDir>${wsdl.generated.source.files.dir}</sourceDestDir>
                    </configuration>
                </execution>
            </executions>
        </plugin>

An interface to create the client service bean (this is not auto generated):

public interface InternalReportsAPIServiceFactory {

    public InternalReportsAPIService createInternalReportsAPIService();

}

Its Bean implementation:

public class InternalReportsAPIServiceFactoryBean implements InternalReportsAPIServiceFactory {

    private URL acmeReportsWsdlURL;

    private final static QName V1_QNAME = new QName("http://internal.reports.api.acme.net/v1","InternalReportsAPIService");

    @Override
    public InternalReportsAPIService createInternalReportsAPIService() {
        return new InternalReportsAPIService(acmeReportsWsdlURL, V1_QNAME);
    }

    public void setAcmeReportsWsdlUrl(String acmeReportsWsdlUrl) {
        try {
            this.acmeReportsWsdlURL = new URL(acmeReportsWsdlUrl);
        } catch (MalformedURLException ex) {
            throw new RuntimeException("Acme Reports WSDL URL is bad: "+ex.getMessage(), ex);
        }
    }
}

The idea in this bean (used as Spring bean) is to have a singleton for generating a client service code. It requires two inputs: The WSDL url - that is, the actual URL of the server which implements the WSDL. The client service code, upon construction, send a get request for the WSDL at the supplied URL. It then creates the WSDL based on the annotations residing in the auto generated code, and it compares it. I believe this is done to make sure you're running against the correct server version. So, I've placed the url in a property file accessible to my application, thus I initialize in my Spring application context file.

Here's an example of using the factory to generate a service and then using it:

InternalReportsAPIService internalReportsAPIService = acmeReportsWSFactory.createInternalReportsAPIService();
InternalReportsAPI port = internalReportsAPIService.getInternalReportsAPIPort();

From here, just use the port variable to call any operation available on the wsdl.

Tags:

Java

Jax Ws

Axis