Simple Spring Web Services using JAXB for Marshalling

David Winterfeldt

2008


A very simple example of using Spring Web Services 1.5.x with JAXB for marshalling and unmarshalling requests. A JAXB plugin for Maven is used to generate the JAXB beans from and XSD and the XSD is reused to generate a WSDL. The response from the server sends a person list, but could easily be modified to retrieve person based on an ID.

1. Server Configuration

Web Configuration

The MessageDispatcherServlet needs to be defined and the URL patterns it will handle. The contextConfigLocation is specified instead of allowing the default (/WEB-INF/spring-ws-servlet.xml) because this location makes the configuration easier to share with the unit test.

/WEB-INF/web.xml
                    
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
         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">
 
    <servlet>
        <servlet-name>spring-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:/spring-ws-context.xml</param-value>
		</init-param>
    </servlet>

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

</web-app>
                        
                

Spring Configuration

The PersonEndpoint is defined as a bean and will automatically be registered with Spring Web Services since the class is identified as an endpoint by the @Endpoint annotation. This configuration uses the person.xsd that was used to generated the JAXB beans to generate the WSDL. The locationUri matches the URL pattern specified in the web.xml.

The JAXB marshaller/unmarshaller is configured using Spring OXM and also set on the MarshallingMethodEndpointAdapter bean.

/src/main/resources/spring-ws-context.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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.springbyexample.ws.service" />

    <bean id="person" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition"
          p:portTypeName="Person"
          p:locationUri="/personService/"
          p:targetNamespace="http://www.springbyexample.org/person/schema/beans">
        <property name="schema">
            <bean class="org.springframework.xml.xsd.SimpleXsdSchema">
                <property name="xsd" value="classpath:/person.xsd"/>
            </bean>
        </property>        
    </bean>

    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
        <description>An endpoint mapping strategy that looks for @Endpoint and @PayloadRoot annotations.</description>
    </bean>

    <bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
        <description>Enables the MessageDispatchServlet to invoke methods requiring OXM marshalling.</description>
        <constructor-arg ref="marshaller"/>
    </bean>

    <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
          p:contextPath="org.springbyexample.person.schema.beans" />

</beans>
                    
                

XML Schema Descriptor

A very simple XSD defining an element to indicate an incoming request to get all persons (name element isn't used) and a person response element that contains a list of person elements.

person.xsd
                    
<xsd:schema xmlns="http://www.springbyexample.org/person/schema/beans"
            targetNamespace="http://www.springbyexample.org/person/schema/beans"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:element name="get-persons-request">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="name" type="xsd:string" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    
    <xsd:element name="person-response">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="person" type="person"
                             minOccurs="0" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:complexType name="person">
        <xsd:sequence>
            <xsd:element name="id" type="xsd:int" />
            <xsd:element name="first-name" type="xsd:string" />
            <xsd:element name="last-name" type="xsd:string" />
        </xsd:sequence>
    </xsd:complexType>

</xsd:schema>
                   
                

Code Example

Example 1. MarshallingPersonService

Interface for getting persons using the JAXB generated beans ('get-persons-request' element --> GetPersonsRequst? , 'person-response' element --> PersonResponse? ). It also has constants for the namespace (matches XSD) and a request constant.

                    
public interface MarshallingPersonService {
    
    public final static String NAMESPACE = "http://www.springbyexample.org/person/schema/beans";
    public final static String GET_PERSONS_REQUEST = "get-persons-request";

    /**
     * Gets person list.
     */
    public PersonResponse getPersons(GetPersonsRequest request);

}
                    
                

Example 2. PersonEndpoint

It is indicated as an endpoint by the @Endpoint annotation and implements MarshallingPersonService. The getPersons method is indicated to handle a specific namespace and incoming request element.

The endpoint just prepares a static response, but this could very easily have a DAO injected into it and information retrieved from a database that is then mapped into the JAXB beans. The PersonResponse is created using the JAXB Fluent API which is less verbose than the standard JAXB API.

                    
@Endpoint
public class PersonEndpoint implements MarshallingPersonService {
    
    /**
     * Gets person list.
     */
    @PayloadRoot(localPart=GET_PERSONS_REQUEST, namespace=NAMESPACE)
    public PersonResponse getPersons(GetPersonsRequest request) {
        return new PersonResponse().withPerson(
                   new Person().withId(1).withFirstName("Joe").withLastName("Smith"),
                   new Person().withId(2).withFirstName("John").withLastName("Jackson"));        
    }

}