This article provides a specific example, with code, of using Jersey and JAXB to implement a REST service suitable for consumption by an iPhone application. It follows an earlier article (https://www.captechconsulting.com/blogs/components-enterprise-iphone-restful-applications) in which I surveyed the components that can be used to create an iPhone application that consumes a REST service.

Components

Jersey

Jersey is an open source reference implementation of the JSR-311 (JAX-RS) specification provided by Sun. In my client work with Jersey, it has proven to be a reliable and lightweight framework for providing REST endpoints and it integrates well with Spring, which will be shown later.

Jersey is available from Sun at https://jersey.dev.java.net

JAXB

JAXB is a framework that provides mapping between XML and Java objects. In this example, I describe XML documents using XML schema (XSD) files and compile them into Java objects for use within REST resource classes.

More information on JAXB can be found at: http://java.sun.com/developer/technicalArticles/WebServices/jaxb

JAXB provides methods to easily marshal data between XML and Java objects while providing for schema validation on incoming objects. Using JAXB for inbound data allows you to specify validation rules in the XSD and allows for reuse of those XSD in other applications that may be consumers of this service. JAXB's marshalling of Java to XML simplifies the generation of outbound XML while enhancing the maintainability of your service code by eliminating hand-coded XML.

REST Resource Example

The following code snippet shows the sub-resource methods of a JSR-311 REST resource class.

<span class="kw1">package</span> <span class="co2">com.captechventures.rest</span><span class="sy0">;</span>
 
<span class="co1">// imports</span>
 
@Path<span class="br0">(</span><span class="st0">"/v1"</span><span class="br0">)</span>
<span class="kw1">public</span> <span class="kw1">class</span> LookupService <span class="br0">{</span>
 
 <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string"><span class="kw3">String</span></a> welcome<span class="sy0">;</span>
 <span class="kw1">protected</span> UserManager userManager<span class="sy0">;</span>
 
 <span class="kw1">private</span> JAXBContext jaxbContext <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span>
 <span class="kw1">private</span> Marshaller marshaller <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span>
 <span class="kw1">private</span> Unmarshaller unmarshaller <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span>
 <span class="kw1">private</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string"><span class="kw3">String</span></a> jaxbPath <span class="sy0">=</span> <span class="st0">"com.captechventures.schema"</span><span class="sy0">;</span>
 
 <span class="co3">/**
 * Tell the Jersey-spring integration which bean to inject into this bean
 */</span>
 @Inject<span class="br0">(</span><span class="st0">"LookupService"</span><span class="br0">)</span>
 <span class="kw1">public</span> LookupService<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span>
 <span class="kw1">super</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span>
 <span class="br0">}</span>
 
 @GET
 @Path<span class="br0">(</span><span class="st0">"/{userId}"</span><span class="br0">)</span>
 @Produces<span class="br0">(</span><span class="st0">"text/xml"</span><span class="br0">)</span>
 <span class="kw1">public</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string"><span class="kw3">String</span></a> lookup<span class="br0">(</span>@PathParam<span class="br0">(</span><span class="st0">"userId"</span><span class="br0">)</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+integer"><span class="kw3">Integer</span></a> userId,
 @<a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+context"><span class="kw3">Context</span></a> HttpServletRequest req,
 @<a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+context"><span class="kw3">Context</span></a> SecurityContext sc<span class="br0">)</span> <span class="kw1">throws</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+exception"><span class="kw3">Exception</span></a> <span class="br0">{</span>
 <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+system"><span class="kw3">System</span></a>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">(</span><span class="st0">"getting username for userId="</span> <span class="sy0">+</span> userId<span class="br0">)</span><span class="sy0">;</span>
 
 User User <span class="sy0">=</span> userManager.<span class="me1">lookupUser</span><span class="br0">(</span>userId<span class="br0">)</span><span class="sy0">;</span>
 <span class="kw1">if</span> <span class="br0">(</span>User <span class="sy0">==</span> <span class="kw2">null</span><span class="br0">)</span> <span class="br0">{</span>
 <span class="kw1">throw</span> <span class="kw1">new</span> WebApplicationException<span class="br0">(</span>HttpServletResponse.<span class="me1">SC_NOT_FOUND</span><span class="br0">)</span><span class="sy0">;</span>
 <span class="br0">}</span>
 
 <span class="kw1">return</span> marshalObject<span class="br0">(</span>User<span class="br0">)</span><span class="sy0">;</span>
 <span class="br0">}</span>
 
 @POST
 @Path<span class="br0">(</span><span class="st0">"/add"</span><span class="br0">)</span>
 @Produces<span class="br0">(</span><span class="st0">"text/xml"</span><span class="br0">)</span>
 <span class="kw1">public</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string"><span class="kw3">String</span></a> add<span class="br0">(</span>@<a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+context"><span class="kw3">Context</span></a> HttpServletRequest req,
 @<a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+context"><span class="kw3">Context</span></a> SecurityContext sc<span class="br0">)</span> <span class="kw1">throws</span> <a href="http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+exception"><span class="kw3">Exception</span></a> <span class="br0">{</span>
 User request <span class="sy0">=</span> <span class="br0">(</span>User<span class="br0">)</span> unmarshallRequest<span class="br0">(</span>req<span class="br0">)</span><span class="sy0">;</span>
 
 userManager.<span class="me1">addUser</span><span class="br0">(</span>request<span class="br0">)</span><span class="sy0">;</span>
 
 <span class="kw1">return</span> marshalObject<span class="br0">(</span>request<span class="br0">)</span><span class="sy0">;</span>
 <span class="br0">}</span>
<span class="br0">}</span>

The code above is a REST resource class. The resource class implements two endpoints, one to lookup a username and the other to add a username. The annotations in the class define the characteristics of the endpoints.

The initial @Path annotation, on line X, declares the base URL path for the all the other endpoints within the resource. In this case all of the following endpoint paths will be prefixed with /v1. The contents of the URL path prior to /v1 are defined in the web.xml of the enclosing .war file, and the server.xml of the tomcat server. The two service endpoints have the URL paths of /v1/{userId} and /v1/add.

The /v1/{userId} path maps to the lookup() method. The @GET annotation indicates that this method only responds to HTTP GET requests. The {userId} nomenclature in the @Path annotation specifies that this part of the path will be provided to the method as a parameter. There must be a matching @PathParam annotated parameter to the method.

The /v1/add path maps to the add() method. The @POST annotation specifies that this method only responds on HTTP Posts. The body of the POST will be in the HttpServletRequest object.

On both methods the @Produces annotation specifies the content-type emitted by the method.

Notice that I've included on both methods the HttpServletRequest and SecurityContext as @Context variables. I've found that putting these into methods as a default setting makes the interface more consistent and provides more ready access to the request metadata. Having access to these context variables provides the data necessary to audit specific user activities and provide for session management.

The reason that I've prefixed the path with /v1 is to provide a version number for the interface. A subsequent revision to the interface can extend this resource class with an annotated path of /v2 and either override the v1 methods or add new methods for endpoints. If a method is not overridden it will be visible in the new resource class with the new path prefix. The resulting resource would have endpoints of /v2/{userId} and /v2/add if the lookup and add methods are not overridden. Any new method with a @Path annotation would be visible to the v2 endpoint but not to the v1 endpoint. Additionally, the v1 endpoint will still be accessible. Versioning your interfaces improves the user experience for the iPhone users since they will not have to update their app immediately. In the associated example project, there is a /v2 LookupService class that implements a DELETE method with the which uses the same URL path as the GET method used for lookups.

One small thing to note from the XML used in the example, if you have control over the XML emitted by the REST service that will be consumed by the iPhone then you can make the development easier on the phone by insuring that all the element names in the XML are unique. If the names are unique then you will not have to track state in the NSXMLParser delegate class.

JAXB Example

In the example code, JAXB is used to serialize the response object to XML and to deserialize the post body from XML to a Java object.

The schema of the exchanged XML document is described in the project file Lookup.xsd. For the example, the XML document is extremely simple, just two elements enclosed within a root level user object.

At project compile time the XSD is compiled into classes representing the structures within the XML schema. The attached example project uses ant to compile the XSD into Java classes. The code snippet below is the germane portion of the build.xml file that compiles the XSD into Java code.

<span class="sc3"><span class="re1"><></span> <span class="re0">name</span>=<span class="st0">"xjc"</span> <span class="re0">classname</span>=<span class="st0">"com.sun.tools.xjc.XJCTask"</span><span class="re2">></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><></span> <span class="re0">dir</span>=<span class="st0">"WebContent/WEB-INF/lib"</span> <span class="re0">includes</span>=<span class="st0">"*.jar"</span> <span class="re2">/></span></span>
 <span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><></span> <span class="re0">name</span>=<span class="st0">"xjc"</span><span class="re2">></span></span>
 <span class="sc3"><span class="re1"><></span> <span class="re0">destdir</span>=<span class="st0">"gensrc"</span> <span class="re0">removeOldOutput</span>=<span class="st0">"yes"</span> <span class="re2">></span></span>
 <span class="sc3"><span class="re1"><></span> <span class="re0">dir</span>=<span class="st0">"src"</span> <span class="re0">includes</span>=<span class="st0">"*.xsd"</span><span class="re2">/></span></span>
 <span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>

For simplicity sake the build file adds all of the jar files, on line 3, in the WEB-INF/lib into the classpath for the xjc compiler. Only the jaxb-xjc.jar file in the WEB-INF/lib file is not required at runtime.

Lines 7-9 execute the compilation task. It instructs the compiler to include all of the XSD files in the source directory in the compilation process and to place the output into a separate source directory called gensrc. It's best to compile all the project XSDs with one compile step so that all dependencies within the XSDs are available to the compiler.

Once the XSD is compiled it can be used in the REST resource classes. In the associated example project, the XSD generated files are passed between the REST resource and the faux user manager class. The REST resource is solely responsible for serialization/de-serialization of the XML document.

The code snippet below, found in the intializeJAXB() method of the LookupService class:

jaxbContext <span class="sy0">=</span> JAXBContext.<span class="me1">newInstance</span><span class="br0">(</span>jaxbPath<span class="br0">)</span><span class="sy0">;</span>
marshaller <span class="sy0">=</span> jc.<span class="me1">createMarshaller</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span>
unmarshaller <span class="sy0">=</span> jc.<span class="me1">createUnmarshaller</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span>

The jaxbPath variable is a colon separated lists of packages containing the generated JAXB classes. Without this list of packages, JAXB could not efficiently find the XSD derived objects from which de-serialization is driven.

The marshaller and unmashaller objects are used when serializing Java objects to XML documents and visa versa.

The marshalObject() and unmarshalObject() methods in the LookupService class do the grunt work of transforming data between XML and Java.

Spring Configuration

The Spring configuration for this example application is very straightforward:

<span class="sc3"><span class="re1"><></span> <span class="re0">id</span>=<span class="st0">"LookupService"</span> <span class="re0">class</span>=<span class="st0">"com.captechventures.rest.LookupService"</span><span class="re2">></span></span>
 <span class="sc3"><span class="re1"><></span> <span class="re0">name</span>=<span class="st0">"welcome"</span> <span class="re0">value</span>=<span class="st0">"bar"</span><span class="re2">></span><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><></span> <span class="re0">name</span>=<span class="st0">"userManager"</span> <span class="re0">ref</span>=<span class="st0">"UserManager"</span><span class="re2">></span><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 
<span class="sc3"><span class="re1"><></span> <span class="re0">id</span>=<span class="st0">"UserManager"</span> <span class="re0">class</span>=<span class="st0">"com.captechventures.rest.UserManager"</span><span class="re2">></span><span class="re1"><span class="re2">></span></span></span>

Lines 1 through 4 define the REST resource, configuration in the web.xml, described later, will trigger the injection of the bean's dependencies upon instantiation of the bean.

Line 6 is just an example bean that could represent a data access object or business logic object injected into a REST resource bean.

WEB.XML Configuration

The web.xml configuration is a bit more substantial, but still straightforward:

<span class="sc3"><span class="re1"><><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>org.springframework.web.context.ContextLoaderListener<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>contextConfigLocation<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>/WEB-INF/applicationContext.xml<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>Jersey-Spring<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>Jersey-Spring<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>com.sun.jersey.spi.spring.container.servlet.SpringServlet<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>REST resource package<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>com.sun.jersey.config.property.packages<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>com.captechventures.rest<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>Jersey-Spring<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
 <span class="sc3"><span class="re1"><><span class="re2">></span></span></span>/*<span class="sc3"><span class="re1"><span class="re2">></span></span></span>
<span class="sc3"><span class="re1"><span class="re2">></span></span></span>

Lines 1-7 specify the Spring context loader and it's associated configuration file. For this example, the information included in the applicationContext.xml will be used later by the com.sun.jersey.spi.spring.container.servlet.SpringServlet.

Lines 8-17 define the Jersey Spring servlet. The Jersey Spring servlet provides the REST functionality as well as triggering the injection of Spring defined attributes into the REST resources. The standard Jersey servlet just provides the REST functionality without the Spring integration. Lines 12-16 define the Java packages that are scanned for REST resource classes. Since the LookupService class defined earlier is in the com.captechventures.rest package and has a @Path annotation, the Jersey Servlet will find the class and map that class to the endpoints specified by the @Path annotations within the class. The remaining lines in the web.xml snippet map the Jersey-Spring servlet to the URL pattern of /*.

Service Operation

On system startup the Spring container takes the following actions:

  1. Instantiate an instance of each bean defined in the applicationContext.xml file.
  2. Injects dependencies as appropriate.

When a request arrives that is mapped to the URL of the Jersey servlet, Jersey does the following things:

  1. Find the class that has a method that maps to the request URI.
  2. Queries Spring for an object instance of the class of the required type.
  3. Using the object returned by Spring, calls the matching sub-resource method on the Object using parameter values harvested from the URI or HTTP request.
  4. Takes the returned object from the method call and builds an HTTP response and uses the returned object as the response body.

Dependencies

The example project provided with this article has the following dependencies:

Example Project

Attached to this article is an example Eclipse project containing all the code and dependencies used for this article. In Eclipse, create a new project using the attached .zip file. The project type is a dynamic web project. Once installed, associate the project with a Tomcat server resource.