This blog post aims to cover generating Java classes from WSDLs using Maven and it also covers a problem with web annotations when deploying to an app server.
There are many different ways to generate Java classes for a given wsdl file (and associated xsds). One of those ways is to use the JAX-WS wsimport tool. Amongst the classes that the tool can generate are the service endpoint interface and the service class.
When using Maven, you can use the jaxws-maven-plugin and the wsimport goal. The plugin will read a WSDL file (from the /src/wsdl directory unless otherwise specified via the wsdlLocation tag) and generate the Java classes. The plugins sections from a pom.xml is shown below:
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlFiles>
<wsdlFile>Customer.wsdl</wsdlFile>
</wsdlFiles>
<staleFile>
${project.build.directory}/jaxws/stale/Customer.stale
</staleFile>
</configuration>
<id>wsimport-generate-Customer</id>
<phase>generate-sources</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>webservices-api</artifactId>
<version>${javax.xml.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>${jaxb-xjc.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>${jaxws-rt.version}</version>
</dependency>
</dependencies>
<configuration>
<sourceDestDir>
${project.build.directory}/generated-sources/jaxws-wsimport
</sourceDestDir>
<xnocompile>true</xnocompile>
<verbose>true</verbose>
<extension>true</extension>
<catalog>
${basedir}/src/jax-ws-catalog.xml
</catalog>
</configuration>
</plugin>
</plugins>
The generated web service class will look like the class below:
@WebService(
name = "Customer",
targetNamespace = "http://<package>/Customer")
@SOAPBinding(
parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface Customer {
/**
*
* @param body
*/
@WebMethod(
operationName = "AddCustomer",
action = "http://<package>/Customer/AddCustomer")
public void addCustomer(
@WebParam(name = "AddCustomer",
targetNamespace = "http://<package>/Customer",
partName = "body") AddCustomer body);
}
Given the above interface, a class can be written to implement the above generated interface as shown below:
@WebService(name = Customer.NAME,
targetNamespace = Customer.TARGET_NAMESPACE,
portName = Customer.PORT_NAME,
serviceName = Customer.SERVICE_NAME,
wsdlLocation = Customer.WSDL_LOCATION_URL)
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@BindingType(value = Customer.SOAP12_OVER_HTTP)
@SchemaValidation()
public class CustomerWebService implements Customer {
static final String NAME = "Customer";
static final String TARGET_NAMESPACE
= TARGET_NAMESPACE_URL + NAME;
static final String PORT_NAME = NAME + "SOAP";
static final String SERVICE_NAME = NAME;
static final String WSDL_LOCATION_URL
= WSDL_LOCATION_PATH + NAME + ".wsdl";
static final String SOAP12_OVER_HTTP
= "http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/";
@Override
@WebMethod(operationName = "AddCustomer")
public void addCustomer(
@WebParam(name = "AddCustomer",
targetNamespace = "http://<package>/Customer",
partName = "body") AddCustomer body) {
// do something
}
}
Having built an ear file containing the web service, you can then deploy it. To deploy to eg Glassfish v3.0.1, you can use the following command:
asadmin --host <server> --port <port> --interactive=false --echo=true --terse=true deploy
--name customer-ear --force=false --precompilejsp=false --verify=false --enabled=true --generatermistubs=false --availabilityenabled=false
--keepreposdir=false --keepfailedstubs=false --logReportedErrors=true --help=false ./customer-ear.ear
One point to note is that the below implementation of the addCustomer method would compile...
@Override
public void addCustomer(AddCustomer body) {
// do something
}
... but it would not inherit the Web annotations and would result in the below error when deploying the ear:
com.sun.enterprise.admin.cli.CommandException: remote failure: Exception while loading the app : java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: javax.servlet.ServletException
Exception while invoking class com.sun.enterprise.web.WebApplication start method : java.lang.Exception: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: javax.servlet.ServletException
The Web annotations need to be explicitly replicated in the concrete class.
Thank you for the info. It sounds pretty user friendly. I guess I’ll pick one up for fun. thank u
ReplyDeleteWeb Services Chennai
Thanks, right to the point!
ReplyDelete