A very simple example of using Spring Web Services 2.1.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.
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.
<?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>
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.
<?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:requestSuffix="-request" p:responseSuffix="-response"> <property name="schema"> <bean class="org.springframework.xml.xsd.SimpleXsdSchema" p:xsd="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>
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.
<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>
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")); } }