Spring Web Service’s with JAXB, Maven & Eclipse

Acknowledgements

Technorati Profile

Before I get started I wish to acknowledge the work of others that greatly assisted me in my understanding of Spring Web Services. I encourage readers to reach out to these sources as well.

Contract Last vs Contract First

There are two development styles for developing web services using Java. With contract-last you start with your Java code and from that you generate the web service contract (WSDL – web service definition language). When using the contract first you start with the WSDL or contract and use Java to implement a service to meet this contract.

Spring-WS only supports contract-first development style.
For more information on contract-first ; much of the information paraphrased here is explored in greater detail.

Problems with Contract Last

From experience and for me the most important difficulties with Contract Last are:

  • Language specific (proprietary) types can become exposed in a XSD and are not portable to other languages.
    • Example Java TreeMap type would not be understood correctly by .NET or Python and would result in a different data type instantiated with differing semantics.
  • Code == Contract. Increased Fragility since the WSDL contract is directly generated from the Java code thereby resulting in a change in WSDL contract with any change in the Java code. This is not desirable.
    • Contracts should be as stable as long as possible
  • Performance resulting from XML generated from Java code.
  • XSD reuse is difficult if not impossible.

Benefits of Contract-First

  • By focusing on the contract and in particular the XSD that defines the contract you implement a more robust WSDL contract that can support changes in the Java code that implements the contract. That is the WSDL contract and Java contract are loosely coupled.
    • The contract is stable over a longer period of time
  • By focusing on what is needed in the XML to support the WSDL contract a much better performing XML message is implemented.
  • XSD components are reusable across other WSDL contracts therefore increasing the re-usability of the SOA artifacts.
    • This of course is dependent upon the XML design pattern chosen to implement the XSD. For an extensive and well thought exploration of this topic refer to Roger L. Costello’s discussion of Schemas

Tools Used

For our example a number of tools are used. Briefly I mention them here.

Spring Web Services

  • The contract is defined by the XML schema (XSD) of the services’ messages
  • The Service contract (i.e., WSDL) will be generated from the XSD
  • Each Spring-WS has an end point which handles the incoming XML documents and manages the outgoing XML response documents
  • Each end point will require a business service to operate
    • This business service is defined as an interface
    • The business service interface_ is implemented by a business service class
  • These dependencies are injected by Springs IoC with metadata defined in the spring-ws-servlet.xml
    • All the components are wired together by the configurations specified in spring-ws-servlet.xml context.

Sample: Magic 8 Ball

The following example is based on the old toy Magic 8-ball which allows as question to be asked and magically 1 of 20 possible answers return as a response to the query. Our sample web service using Spring WS with JAXB will do just this.

The Contract

We focus on the data contract between our client and service and define this with in an XML Schema; our XSD.   Using a simple Russian Doll design pattern we have two elements; a request and a response.  The request involves a question and the reponse an answer.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://acompany.com/it/enterprise/DEPT/EightBall/v1" xmlns:tns="http://acompany.com/it/enterprise/DEPT/EightBall/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified">
	<xs:element name="eightBallRequest">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Question" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="eightBallResponse">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Answer" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Marshalling/Unmarshalling:JAXB

Not only does our XSD define our data contract between the client and service it is used by JAXB to generate the marshalling and unmarshalling code that our service uses to handle the XML messages.

  1. With your XSD in the bin directory of you JAXB installation run the xjc tool to generate the JAVA class for marshalling and unmarshalling.
  2. You can us the -p switch and specify a simple package name for your JAXB JAVA code. In our example jaxb.eightball. The default package name is the XSD target namespace

C:\jaxb-ri-20070122\bin>xjc.bat -p jaxb.eightball eightball.xsd
parsing a schema…
compiling a schema…
jaxb\eightball\EightBallRequest.java
jaxb\eightball\EightBallResponse.java
jaxb\eightball\ObjectFactory.java
jaxb\eightball\package-info.java

Eclipse Project using Maven 2

  1. In Eclispe use File/New/Project…/Maven Project
  2. Select Default workspace
  3. Select spring-ws-archtype
  4. Enter eightballdemo for Group Id
  5. Enter eightballdemo for Artifact Id
  6. Select Finish
  7. Selecting the POM.XML under the dependencies tab add the log4j POM dependencies in the Tools Used section above
    • Add spring-oxm-tiger dependency
    • Add spring-ws-core-tiger dependency
  8. POM Dependencies

Exposing the Contract

  • Import eightball.xsd in src/main/webapp/WEB-INF
  • Edit spring-ws-servlet.xml and add the following for Spring to generate the WSDL at runtime from the XSD file:
  •    <!-- Add automatic WSDL generation support -->
        <bean id="eightball" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
    <property name="schema" ref="schema" />
    <property name="portTypeName" value="eightball" />
    <property name="locationUri" value="http://localhost:8080/eightball/" />
    <property name="targetNamespace" value="http://acompany.com/it/enterprise/DEPT/EightBall/v1" />
        </bean>  
    
        <bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
    <property name="xsd" value="/WEB-INF/eightball.xsd" />
        </bean>
    

Preparing for Code

  1. Add a Source Folder to your project: src/main/java
  2. Add the following packages to this Source Folder
    • ws – web service end point
    • jaxb.eightballJAXB marshalling and unmarshalling classes
    • service – interface for class that contains service logic
    • service.impl – class that implements service logic
  3. Import the JAXB Java files generated under the jaxb.eightball package.
  4. JAXB for Eightball

EndPoint

First Part

  • In spring-ws-servlet.xml define the web service endpoint using annotations along with the service interface and implementation.
  • <!-- Register PayloadRootAnnotationMethodEndpointMapping -->  
        <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />  
      
        <!-- Register Endpoint -->  
        <bean id="eightBallEndpoint" class="ws.EightBallEndpoint">
        <description>
                This endpoint handles requests.
            </description>
            <property name="eightBallService" ref="eightBallService"/>
        </bean>  
        
         <bean id="eightBallService" class="service.impl.EightBallServiceImpl">
            <description>
                This bean is our "business" service.
            </description>
        </bean>
        
    
  • Now create the end point class EightBallEndPoint in the ws package
  • package ws;
    import service.EightBallService;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.ws.server.endpoint.annotation.Endpoint;
    import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
    
    import jaxb.eightball.EightBallRequest;
    import jaxb.eightball.EightBallResponse;
    
    @Endpoint
    public class EightBallEndpoint {
    	
    	private EightBallService eightBallService;
    	protected final Log logger = LogFactory.getLog(getClass());
    	
    	/**
    	 * Sets the "business service" to delegate to.
    	 */
    	public void setEightBallService(EightBallService eightBallService) {
    		this.eightBallService = eightBallService;
    	}....
    

Service: EightBallService

  • Define the interface EightBallService in the package service
  • package service;
    
    public interface EightBallService {
    
    	String question (String s);
    }
    

Wire In the JAXB

  • In spring-ws-servlet.xml add the following wiring for the JAXB marshalling and unmarshalling.
  •      <!-- Configure XML Marshaller -->  
        <bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">  
            <constructor-arg ref="marshaller" />  
        </bean>  
      
        <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">  
            <property name="classesToBeBound">  
                <list>  
                    <value>jaxb.eightball.EightBallRequest</value>  
                    <value>jaxb.eightball.EightBallResponse</value> 
                </list>  
            </property>  
        </bean> 
    
  • In EightBallEndPoint add the following annotation based section for marshalling and unmarshalling.
  • 
    	@PayloadRoot(localPart= "eightBallRequest", namespace="http://acompany.com/it/enterprise/DEPT/EightBall/v1")
    	public EightBallResponse doit(EightBallRequest request){
    
    		String question = request.getQuestion();
    		System.out.println("The question is " + question);
    		logger.info("The question is " + question);
    		String answer = eightBallService.question(question);
    		logger.info("The answer is " + answer);
    		EightBallResponse response = new EightBallResponse();
    		response.setAnswer(answer);
    		return response;
    	}
    }
    

EightBallServiceImpl

  • Create the Class EightBallServiceImpl implementing the interface EightBallService
  • package service.impl;
    
    import java.util.ArrayList;
    import java.util.Random;
    
    import service.EightBallService;
    
    public class EightBallServiceImpl implements EightBallService {
    
    	public String question (String s) {
    		Random rand = new Random();
    		ArrayList<String> answers = new ArrayList<String>(20);
    		answers.add(0, "As I see it, yes");
    		answers.add(1, "It is certain");
    		answers.add(2,"It is decidedly so" );
    		answers.add(3,"Most likely");
    		answers.add(4,"Outlook good");
    		answers.add(5, "Signs point to yes");
    		answers.add(6, "Without a doubt");
    		answers.add(7, "Yes");
    		answers.add(8, "Yes - definitely");
    		answers.add(9, "You may rely on it");
    		answers.add(10,"Reply hazy, try again");
    		answers.add(11,"Better not tell you now");
    		answers.add(12,"Cannot predict now");
    		answers.add(13,"Concentrate and ask again");
    		answers.add(14,"Don't count on it");
    		answers.add(15,"My reply is no");
    		answers.add(16,"My sources say no");
    		answers.add(17,"Outlook not so good");
    		answers.add(18,"Very doubtful");
    		answers.add(19, "Ask again later");
    
    		int iNum = rand.nextInt(20);
    		return answers.get(iNum).toString();
    	}
    }
    
    
    

Package and Test

We are now done should be ready to compile, package and test our service. I strongly recommended using SoapUI for testing your web service.

  • On the project eightballdemo right mouse-button
    • Select Run As
    • Select Maven package
  • You can deploy your eightball.war to your Tomcat servlet container
  • From SoapUI you can create a project and import the WSDL from your Tomcat Instance
  • http://localhost:8080/eightball/eightball.wsdl

  • Test and have fun

Project Code

You can download Eclipse Project Zip file

About these ads

Tags: , , , , ,

6 Responses to “Spring Web Service’s with JAXB, Maven & Eclipse”

  1. Raj Says:

    Hi James,

    Nice article to get an idea on Spring Ws and binding framework interactions.

    What would be the changes to make this application use JibX instead of JaxB as binding framework?

    One of the changes would be to change the “marshaller” to use JibX one.

    Regards
    Raj

    • cyclocrossboy Says:

      Raj,

      Strange you should make that suggestion, it was a toss up between JAXB and JibX as the X/O. I’ll take your suggestion to heart and build this out using JibX. Thanks for commenting.

  2. Atmaram Says:

    Hey,
    Thanks for htis article. The eclipse project link is not working. Please update.

    Thank You

    • cyclocrossboy Says:

      atmaram.m

      Sorry about that … free storage; forgot to do my monthly logon. Its restored and good to go.

      Thanks.

  3. Peeyush Says:

    Thanks for a very nice tutorial,
    I was able to follow the instructions easily without any prior experience with spring at all. But I have two question and I would be grateful if you answer them..
    the following tag specifies the endpoint location uri

    The value tag does not get updated with the actual server ip and port when the wsdl is requested from the app server(tomcat in my case).
    This looks like a kind of hardcoding which should be avoided. Is there any workaround for this, or do I need to change this manually after deployment?

    Secondly, is it possible to debug this webservice in eclipse with tomcat, I cant find a direct way to do that(as it is really easy to do the same in a dynamic web project)

    • cyclocrossboy Says:

      Peeyush81

      I’m glad you find this of some value.

      Re: the locationUri … yes my example is hardcode as you noted. I’m assuming you have a tomcat instanced installed and running on your local host … an old habit of mine. Yes you can make this a relative reference for example:

      For more information on this check out the spring ws reference section 3.7 for more information on this.

      As for debugging you can write unit test’s for your components that make up your web service. Also a great web service testing tool is Soap UI but this runs outside of eclipse.

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


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: