Enterprise Java

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

Untitled-Diagram

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.

ProjectStructure

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.

stub

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.

wsdl-1

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.

SOAP-1

4. Download the source code

Reference: Contract First SOAP Service with Spring and Maven from our JCG partner Abhimanyu Prasad at the jCombat blog.

Abhimanyu Prasad

Abhimanyu is a passionate tech blogger and senior programmer, who has an extensive end-to-end development experience with wide range of technologies. He is the founder and administrator at jCombat.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Dmitriy
Dmitriy
5 years ago

http://localhost:8080/SOAPWebServiceExample/customer?wsdl is incorrect.
It should be http://localhost:8080/SOAPCFWebServiceExample/customer since we have SOAPCFWebServiceExample in pom.xml

Back to top button