Spring Web Services 2. Made easy!

We’ll see how to develop Spring Webservices 2, along with validation on the base of xml schema. We’ll use spring-ws 2, maven, jaxb for making this sample project spring-ws2-exemplary. 

Source Code!

You don’t need to copy paste the code, it’s available for download at the bottom of the page. The project may give some errors while building due to non-conformance of Maven 3, so for that I’ve enhanced the POM and you can download the new project from here.

We’ll see the whole process in easy steps, making no big dragon of this!

1. I presume you are probably aware of maven. Setting it up is easy. If you’re not a maven-compatriot, don’t worry, google it, and you’ll have it up and running in a matter of mins.

So all said and done, lets start the development rightaway.

2. Open command prompt and navigate to your workspace location, or wherever you need to make the project.

3. Type in the following command, all in one line.

mvn archetype:create -DarchetypeGroupId=org.springframework.ws -DarchetypeArtifactId=spring-ws-archetype -DarchetypeVersion=2.0.1.RELEASE -DgroupId=ankeet.spring.ws2 -DartifactId=spring-ws2-exemplary

So there you have the basic skeleton of the project ready for you, including the spring config files, pom.xml and the requisite folder structure. Go have look ;)

4. Now you have the basic structure with you, but it still doesn’t qualifies to be imported as a project in eclipse or SpringsourceToolSuite (STS), as it lacks the .classpath and .project files.

To overcome, go to the project folder spring-ws2-exemplary in this case and run the following command:-

mvn eclipse:eclipse

Now you can import this as Existing Projects into Workspace

5. Creating the xml request and response messages. We’ll create a service SquareService, which will give the square of the input number.

So our request will be

        <SquareServiceRequest>
	   <Input>3</Input>
	</SquareServiceRequest>

and response will be

       <SquareServiceResponse>
	  <Output>9</Output>
       </SquareServiceResponse>

6. Since, you now have the request and response messages combine it into one xml file and generate the xsd.

Combining the request and response in a file spring-ws2-square.xml

<?xml version="1.0" encoding="UTF-8"?>
<SquareService xmlns="http://ankeetmaini.wordpress.com/spring-ws2-square">

	<SquareServiceRequest>
		<Input>3</Input>
	</SquareServiceRequest>

	<SquareServiceResponse>
		<Output>9</Output>
	</SquareServiceResponse>

</SquareService>

7. To generate the xsd, you can use trang.jar if you don’t have anything else. Its an open source product.

Download the latest version and unzip it on your system. Open command prompt and navigate to the unzipped folder.

To create the XSD run the following command:

java -jar trang.java <Path-of-XML-file> <Path-where-xsd-is-to-be-generated>

I copied my xml to the trang direcotory only, and generated my corresponding xsd there too, and then copied it to WEB-INF. Simple.

So you have the xsd generated in the current directory. Before putting it into use, we need to tweak it a little bit to suit our purposes.

Original spring-ws2-square.xsd


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://ankeetmaini.wordpress.com/spring-ws2-square" xmlns:s="http://ankeetmaini.wordpress.com/spring-ws2-square">
  <xs:element name="SquareService">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="s:SquareServiceRequest"/>
        <xs:element ref="s:SquareServiceResponse"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="SquareServiceRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="s:Input"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Input" type="xs:integer"/>
  <xs:element name="SquareServiceResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="s:Output"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="Output" type="xs:integer"/>
</xs:schema></pre>

Editing it, we get the final xsd. Please note the finer details yourself, and try to comprehend. You’ll be able to figure out the need to edit it most of the times for the sake of more conciseness, and removal of extraneous elements, if you know what I mean ;)

Final spring-ws2-square.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://ankeetmaini.wordpress.com/spring-ws2-square" xmlns:s="http://ankeetmaini.wordpress.com/spring-ws2-square">

  <xs:element name="SquareServiceRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Input" type="xs:integer"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:element name="SquareServiceResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Output" type="xs:integer"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

Now copy this to the src/main/webapp/WEB-INF folder, so that it’ll be detected at classpath.

8. Open web.xml located in WEB-INF folder and change the name of the servlet to spring-ws2 (This is not required but I do, to remove the ambiguity, if at all it arises). Don’t forget to change in the <servlet-maping> also.

Add an init param

<init-param>
			<param-name>transformWsdlLocations</param-name>
			<param-value>true</param-value>
		</init-param>

Verify your web.xml looks like this:-

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">

    <display-name>Archetype Created Web Application</display-name>

 	<servlet>
		<servlet-name>spring-ws2</servlet-name>
		<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet
		</servlet-class>
		<init-param>
			<param-name>transformWsdlLocations</param-name>
			<param-value>true</param-value>
		</init-param>
	</servlet>

    <servlet-mapping>
        <servlet-name>spring-ws2</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

9. Now, since you changed the servlet’s name, you need to change the Spring’s configuration file too, because the container will look for <servlet-name>-servlet.xml

Rename (or better Refactor) it to spring-ws2-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:sws="http://www.springframework.org/schema/web-services"
       xsi:schemaLocation="http://www.springframework.org/schema/beans	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context


http://www.springframework.org/schema/context/spring-context.xsd

       http://www.springframework.org/schema/web-services                      	http://www.springframework.org/schema/web-services/web-services-2.0.xsd">

    <!-- To detect @Endpoint -->
<sws:annotation-driven/>

<!-- To detect @Service, @Component etc -->
<context:component-scan base-package="ankeet.spring" />

    <!-- To generate dynamic wsdl -->
	<sws:dynamic-wsdl
		id="getSquare"
		portTypeName="SquareService"
		locationUri="/squareService"
		targetNamespace="http://ankeetmaini.wordpress.com/spring-ws2-square">
		<sws:xsd location="/WEB-INF/spring-ws2-square.xsd"/>
	</sws:dynamic-wsdl>

    <!-- For validating your request and response -->
    <!-- So that you don't send a string instead of an integer -->

	 <sws:interceptors>
<bean id="validatingInterceptor"
        class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
    <property name="schema" value="/WEB-INF/spring-ws2-square.xsd"/>
    <property name="validateRequest" value="true"/>
    <property name="validateResponse" value="true"/>
</bean>
  </sws:interceptors>

</beans>

10. In Eclipse/STS right click your project and and then new, and select a new source folder and name it as src/main/java

Create three packages : ankeet.spring.ws2.endpoint, ankeet.spring.ws2.service, ankeet.spring.ws2.generated

11. Since we’re using jaxb for converting xml <—> object, we need to make changes to the pom.xml to add its dependencies and plugins, so that the Java Classes are generated at compile time from the XSD given.

Add the following piece of code to the pom in the <plugins> section

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxb2-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
	<goal>xjc</goal>
      </goals>
     </execution>
   </executions>
  <configuration>
    <schemaDirectory>src/main/webapp/WEB-INF/</schemaDirectory>
  </configuration>
</plugin>

Similarly add the dependencies in the <dependencies> section of POM.

<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.0</version>
</dependency>
<dependency>
  <groupId>com.sun.xml.bind</groupId>
  <artifactId>jaxb-impl</artifactId>
  <version>2.0.3</version>
</dependency>
<dependency>
  <groupId>org.apache.xmlbeans</groupId>
  <artifactId>xmlbeans</artifactId>
  <version>2.4.0</version>
</dependency>
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.8.1</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <scope>compile</scope>
  <version>1.2.16</version>
</dependency>

11. Write the endpoint class as follows:-

SquareWSEndpoint.java

/**
 *
 */
package ankeet.spring.ws2.endpoint;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import ankeet.spring.ws2.generated.*;
import ankeet.spring.ws2.generated.SquareServiceResponse;
import ankeet.spring.ws2.service.SquareService;

/**
 * @author Ankeet Maini
 *
 */
@Endpoint
public class SquareWSEndpoint {
	//To calculate square of the input.
	@Autowired
	private SquareService squareService;
	//This is like @RequestMapping of Spring MVC
	@PayloadRoot(localPart="SquareServiceRequest", namespace="http://ankeetmaini.wordpress.com/spring-ws2-square")
	@ResponsePayload
	public SquareServiceResponse getSquare(@RequestPayload SquareServiceRequest request) {
		SquareServiceResponse response = new ObjectFactory().createSquareServiceResponse();
		response.setOutput(squareService.square(request.getInput()));
		return response;
	}
}

12. Now write the service classes which will actually do the squaring.

SquareService.java

package ankeet.spring.ws2.service;

import java.math.BigInteger;

public interface SquareService {
	public BigInteger square(BigInteger bigInteger);

}

And it’s implementation class SquareServiceImpl.java

package ankeet.spring.ws2.service;

import java.math.BigInteger;

import org.springframework.stereotype.Service;

@Service
public class SquareServiceImpl implements SquareService {

	public BigInteger square(BigInteger bigInteger) {
		return (bigInteger.multiply(bigInteger));
	}

}

13. Now when you clean your project JAXB will create the classes from the XSD present on the classpath, in our case spring-ws2-square.xsd located in WEB-INF. The code generated will be in the target folder, so you’ll have to copy the files and put into the ankeet.spring.ws2.generated package, and correct the inconsistencies arising in the package names by shifting. Also, make src/main/webapp a source folder(By navigating to webapp and then right clicking and in Configure Buildpath, make it a source folder).

14. After this your project structure should prcisely look like this.

15. To run the project you can create a war and deploy on the server, or use maven. Go the project directory and type the following command to run the project on tomcat server:

mvn tomcat:run

16. Open your web browser and enter the following url

http://localhost:8080/spring-ws2-exemplary/getSquare.wsdl to see the WSDL file generated.

17. To test the application, you can build a client or use Soap UI. To test with soap UI, open it, create an new project and give it the above url of WSDL.

Press Ok.

Click on Request1 and on the left side an interface will appear asking your request. Enter any integer and press the green button to send it to the server. If you enter anything other than an integer, a Validation error will be reported on the other side.

and if you do enter any thing else than integer, say a string, the Validation will fail and you’ll get the following error.

Just in case if you wish to know, the above Response is

<pre><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <SOAP-ENV:Body>
      <SOAP-ENV:Fault>
         <faultcode>SOAP-ENV:Client</faultcode>
         <faultstring xml:lang="en">Validation error</faultstring>
         <detail>
            <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-datatype-valid.1.2.1: 'a' is not a valid value for 'integer'.</spring-ws:ValidationError>
            <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-type.3.1.3: The value 'a' of element 'spr:Input' is not valid.</spring-ws:ValidationError>
         </detail>
      </SOAP-ENV:Fault>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The code is hosted on Google Codes, to download the project click here.

To run it, just unzip the file, open command prompt, navigate to the directory and type : mvn tomcat:run, and voila you’re done!

While creating this project I read a lot, and found these blogs extremely helpful,

1. Jamesbnuzzo

2. Ice09

3. krams

That’s all for this one. Enjoy building and running it. :)

22 thoughts on “Spring Web Services 2. Made easy!”

    1. Hi Gita,

      Apologies for the late reply, as I’ve been extremely busy these days. But as far as your problem is concerned, it should run fine as the wsdl is getting generated.

      You can check if the request and response messages are going correctly, and also make sure you copy paste the wsdl from browser directly, and when you send the request from SOAP client, is there any console log printed in the server. Try putting some sysouts to see if it’s reaching there or not.

      All the best!

      On Thu, Jul 11, 2013 at 1:40 PM, Ankeet Maini wrote:

      > New comment on your post “Spring Web Services 2. Made easy!” > Author : gita (IP: 128.221.224.58 , 128.221.224.58) > E-mail : gitanjali.nandi@hcl.com > URL : > Whois : http://whois.arin.net/rest/ip/128.221.224.58 > Comment: > Hi Ankeet. > I am getting the wsdl when i am putting url > http://localhost:8080/webservice_project/getSquare.wsdl in browser.But > in SoapUI i am not getting the response.it is gving error HTTP/1.1 404 > Not Found > Server: Apache-Coyote/1.1 > Content-Length: 0

      Like

  1. Thanks for the tutorial. A couple of improvements (might not have existed back in 2011).

    m2e:

    Rather than running eclipse:eclipse, nowadays you can use m2e, the maven integration for eclipse, to import a maven project. The advantage of doing this is it keeps the eclipse project settings up to date when the maven pom changes.

    generated sources:

    You shouldn’t copy the generated source into src/main/java. The xsd is the true ‘source’ and the generated java code is compiler output, just like .class files are compiler output from the .java
    The problem with copying them to the source folder is:

    1) You have duplicate classes on the build path. When you build from maven, the java in the target/generated folder will get compiled as well as the copies you made.

    2) When you change the xsd, the files you copied will be out of date. This is creating unnecessary work to manually copy the files to the source folder. Undoubtedly you will forget one day and you will have two different conflicting versions of the classes on the build path.

    Instead you should add target/generated-sources/xjc as a source folder. Does this manually if using eclipse:eclipse, or if using m2e, just right click on the project and go maven -> update project. It should detect there is a generated source added to the build maven build path and then add it to the eclipse build path.

    Like

  2. Great tutorial. I’ve spent about three days researching a way to do Spring WS contract first and this has been the easiest way to get it done. Thanks.

    Like

  3. Search engines read this as the top basis on what you want to improve in google.

    Keep a twitter feed that is updating daily, facebook and google+
    too! How To Optimize A Blogger Template For Search Engine Optimization
    pay per click versus Social Media Marketing in an
    effective online marketing strategy. The high page rank can pass on some link juice to flow to your sites
    niche or theme. There are many online resources, but it’s a LOW fee.

    Like

  4. I was looking all over the web for a working source code. None of the tutorials were of any use and gave so many exceptions. Was able to run your code in under 5 mins. Great post.

    Like

  5. Great tutorial, I have tested it in tomcat and It works but I have 3 question:
    1) I need to add this dependency into the pom.xml to avoid tomcat throws exception:

    org.apache.axis2
    axis2-saaj
    1.5.1

    The first question is: Why is Axis jar necessary ? Is not Jaxb alone sufficient ?
    2) I also tested it with soapUI and I have this resonse:

    25

    I miss the tag ?? Why ?
    3) I am now trying to make WSDL static, write by hand and not generated by Spring, Are You interested to share this approach ?

    Like

    1. Hi Massimiliano,

      Thanks a lot for liking the post.

      As far as your questions go, I didn’t require any axis jar to be added as a dependency. It might be asking for you if your development environment is using Java 1.4 and Tomcat Versions 4.x. Try using newer versions. The SOAP UI response would also be certainly because of aforementioned things.

      And I haven’t yet written the WSDL by hand, so can’t say much on that. If you’ve already done it, feel free to share the approach. Since you pointed that out I’ll also have a look and if I find anything worthwhile I’ll keep you posted.

      Cheers!

      Like

  6. Hi, first I need to say it is great tutorial, understandable and actually exactly what I need. But I have some problems running it so I would like to ask for help. My project don’t generate the sources after clean. I have STS 3.0 and that’s probably the problem. Problems start right after importing the project into STS. There are some different things in 3.0 for example I need to convert the project into Faceted form and select Facets (I select Dynamic web project and Java) to have option to at least run it on the server (in STS). And lots of things are diffeerent som I am a little bit confused. So I am going step by step in your tutorial but it isnt working anyway and I don’t know what is wrong, what should I do. Can you (or someone here) look at it in STS 3.0 and help me? Thanks to everybody who will look at this

    Like

    1. Thanks for liking the post. As far as your problem goes. Download the project, and import it as *Existing Maven Projects*. I don’t think the STS version has anything to do with that, as the .project files would be created automatically once you import the project.

      Hope this would be of some help.

      Like

  7. Amazing! Thanks for the very detailed explanation. web-services were never this easy and fun to play with.Waiting eagerly for the client part!

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s