Contract First SOAP Service with Spring and Maven
1. Introduction
In this tutorial, we will learn to implement a contract-first SOAP service application using JAX-WS, Spring and Maven. This is more of a design decision whether to use contract-first or code-first approach.
The most notable benefit of using applying contract-first approach in developing a SOAP based web service application, is that the contract can be shared with the consumers/clients immediately after the needed changes are done to it, so the client application and web service operation implementation can be done independently by different teams at the same time, thus saving a lot of time.
2. Implementation
Something like above would be the scenario, where the client/consumer application will be interacting with our sample SOAP based JAX-WS web service through a service endpoint.
To start with the implementation, first create a Maven Project in Eclipse and make sure we proceed with the directory structure close to what has been shown below.
First is to look at our pom dependencies, which should look like:
pom.xml
<dependencies> <!-- Spring dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.2.1.RELEASE</version> </dependency> <!-- JAX-WS dependencies --> <dependency> <groupId>org.jvnet.jax-ws-commons.spring</groupId> <artifactId>jaxws-spring</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.2.8</version> </dependency> </dependencies> <build> <finalName>SOAPWebServiceExample</finalName> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>1.12</version> <configuration> <wsdlDirectory>${basedir}/src/main/resources/wsdl</wsdlDirectory> <packageName>com.jcombat.ws</packageName> <keep>true</keep> <sourceDestDir>${basedir}/target/generated/src/main/java</sourceDestDir> </configuration> <executions> <execution> <id>wsdl_import</id> <goals> <goal>wsimport</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Note the wsimport tool that we will be using, to generate the stub files later from the WSDL file.
Let’s now check out the web.xml file.
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>SOAPWebServiceExample</display-name> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>customer</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>customer</servlet-name> <url-pattern>/customer</url-pattern> </servlet-mapping> </web-app>
Next we create a schema file for our web service. Name it as customerService.xsd, which will basically define the building blocks for the WSDL file or web service contract, we will be creating.
customerService.xsd
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ws.jcombat.com/" xmlns:tns="http://ws.jcombat.com/" elementFormDefault="qualified"> <element name="CustomerServiceRequest" type="tns:CustomerServiceRequestType"> </element> <complexType name="CustomerServiceRequestType"> <sequence> <element name="customerId" type="int"></element> </sequence> </complexType> <complexType name="CustomerServiceResponseType"> <sequence> <element name="customer" type="tns:Customer" maxOccurs="unbounded" minOccurs="0"></element> </sequence> </complexType> <element name="CustomerServiceResponse" type="tns:CustomerServiceResponseType"> </element> <complexType name="Customer"> <sequence> <element name="id" type="int" maxOccurs="1" minOccurs="1"></element> <element name="name" type="string" maxOccurs="1" minOccurs="1"></element> </sequence> </complexType> </schema>
Create a valid WSDL file using the XML schema we just created.
customerService.wsdl
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://ws.jcombat.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://ws.jcombat.com/" name="customerService"> <wsdl:types> <xsd:schema targetNamespace="http://ws.jcombat.com/"> <xsd:import namespace="http://ws.jcombat.com/" schemaLocation="../schema/customerService.xsd" /> </xsd:schema> </wsdl:types> <wsdl:message name="CustomerServiceRequest"> <wsdl:part name="CustomerServiceRequest" element="tns:CustomerServiceRequest" /> </wsdl:message> <wsdl:message name="CustomerServiceResponse"> <wsdl:part name="CustomerServiceResponse" element="tns:CustomerServiceResponse" /> </wsdl:message> <wsdl:portType name="CustomerServicePortType"> <wsdl:operation name="getCustomer"> <wsdl:input name="CustomerServiceRequest" message="tns:CustomerServiceRequest" /> <wsdl:output name="CustomerServiceResponse" message="tns:CustomerServiceResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="CustomerEndpointPortBinding" type="tns:CustomerServicePortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="getCustomer"> <soap:operation style="document" soapAction="getCustomer" /> <wsdl:input name="CustomerServiceRequest"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="CustomerServiceResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="customerService"> <wsdl:port name="CustomerEndpointPort" binding="tns:CustomerEndpointPortBinding"> <soap:address location="http://localhost:8080/SOAPWebServiceExample/customer" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
Next is to generate the stub files from the WSDL file. To do that, run the below command in your system’s command prompt.
mvn clean install
Check out for the generated stub files in the /target directory.
Let’s now create the implementation of the generated service interface CustomerServicePortType in a class named CustomerServiceImpl.
CustomerServiceImpl.java
package com.jcombat.service; import javax.jws.WebService; import com.jcombat.ws.Customer; import com.jcombat.ws.CustomerServicePortType; import com.jcombat.ws.CustomerServiceRequestType; import com.jcombat.ws.CustomerServiceResponseType; @WebService(endpointInterface="com.jcombat.ws.CustomerServicePortType") public class CustomerServiceImpl implements CustomerServicePortType { public CustomerServiceResponseType getCustomer( CustomerServiceRequestType customerServiceRequest) { final CustomerServiceResponseType response = new CustomerServiceResponseType(); Customer customer = new Customer(); customer.setId(123); customer.setName("Ramesh"); response.getCustomer().add(customer); return response; } }
@WebService annotation must be applied to the endpoint interface implementation class to mark it as the web service endpoint. The @WebService annotation tells the server runtime environment to expose all the public methods of that class as web service methods.
We are all done with the application. Final check is if we can see the WSDL content displayed when the below endpoint URI is hit, whose location we have specified towards the bottom of the WSDL file.
- http://localhost:8080/SOAPWebServiceExample/customer?wsdl
Below is what we see in the browser when we hit it.
So yes, we did it, successfully.
3. Running the application
Setup the SOAP project in SOAP UI with the WSDL URI (http://localhost:8080/SOAPWebServiceExample/customer?wsdl).
Below is what we see when we actually hit the service in SOAP UI.
4. Download the source code
Reference: | Contract First SOAP Service with Spring and Maven from our JCG partner Abhimanyu Prasad at the jCombat blog. |
http://localhost:8080/SOAPWebServiceExample/customer?wsdl is incorrect.
It should be http://localhost:8080/SOAPCFWebServiceExample/customer since we have SOAPCFWebServiceExample in pom.xml