JAX-RS with Apache Wink

December 2, 2009

JAX-RS is a specification addressing the implementation of providers and consumers of REST services in Java. Apache Wink is an Open Source implementation of that specification. To give an idea of what is possible: you can annotate a Java Class like this

    @Path(“/books”)
    public class LibraryResource {

    @GET
    @Produces( MediaType.APPLICATION_JSON)
    public BookCollection getBooks() {
          // implementation here

    }

and deploy this class along with the Wink framework to an Application Server and you have immediately implemented a RESTful service with a URI

    http://myhost/rest/books

In this posting I will explain in detail how to use Apache Wink to implement a service like this. I will be creating RESTful services for a simplified, fictional Lending library. First, a reminder of the problems addressed by JAX-RS. I’ve described the service providers responsibilities in more detail in this posting but in summary we first need to do some up-front design work:

  • Identify some resources, in our case these could be Books, Editions, Authors, Categories and Borrowers
  • Decide on the URIs that identify these resources, both individual resources and collections of resources.
  • Design the services, giving appropriate meanings to methods such as GET, PUT, POST and DELETE

Then we write code and exploit JAX-RS (and JAXB) to address these implementation problems:

  1. Transform between the State of a Resource and its Transfer Representation. That is, manage the conversion between a Java Object and an XML or JSON representation of its attributes.
  2. Interpret the URI of a service request and direct the request to the appropriate Resource Manager, which we have developed in Java.
  3. Map the HTTP method (GET, PUT …) to appropriate methods of the Resource Manager.
  4. Enable the resource manager to use the details of the URI to identify particular resources. for example

    http://myhost/rest/borrowers/12345

    would identify a borrower with id 12345

  5. Give access to qualifying parameters such as search criteria

Preparation

I am using Rational Application Developer 7.5  (RAD) and the WebSphere Application Server 7.0 (WAS) test environment provided by RAD. I downloaded Apache WINK and then added WINK jar files to my dynamic web project.

Download Wink

Apache WINK can be downloaded from Wink Download. I downloaded

apache-wink-1.0-incubating.zip

This contains directories

  • dist – the core of Wink
  • lib –  wink supporting libraries
  • ext/wink-json-provider – JSON formatting and parsing

There is also documentation and examples.

Creating and Populating Web Project

In RAD create an Application (EAR) project and Dynamic Web Project, then add the Wink JAR files, define the Wink servlet and create packages for the Java Classes we will write shortly. The next sections describe these steps in more detail.

Wink JAR files

Copy the following jar files from the Wink distribution to the WEB-INF lib directory of the dynamic web project.

From dist

wink-server-1.0-incubating.jar
wink-common-1.0-incubating.jar

From lib:

jsr311-api-1.0.jar
slf4j-api-1.5.8.jar
slf4j-simple-1.5.8.jar

(note that instead of slf4j-simple-1.5.8.jar you may prefer to use a different slf4j implementation such as slf4j-jdk14-1.5.8.jar, you can download that from here.

From ext/wink-json-provider

lib/json-20080701.jar
wink-json-provider-1.0-incubating.jar

So my LibraryEar and LibraryWink projects now look like this

ProjectJar 

Wink Servlet

Edit WEB-INF/web.xml, add the servlet definition.

  <servlet>
        <servlet-name>restSdkService</servlet-name>
        <servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
        <init-param>
            <param-name>applicationConfigLocation</param-name>
            <param-value>/WEB-INF/application</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>restSdkService</servlet-name>
        <url-pattern>/library/*</url-pattern>
    </servlet-mapping>

This has the effect of mapping all URLs begging with “library” to the Wink REST servlet.

The Web project now shows a servlet:

Servlet

We will create our own resource manager classes with JAX-RS annotation that will implement the service function and hook that servlet to call our implementation: note that the servlet has an initialisation parameter applicationConfigLocation which refers to a file

    /WEB-INF/application

the purpose of this file is to register our resource manager code with the Wink servlet. We’ll create that file once we have written the code.            

Creating Packages

I created two packages to differentiate two kinds of Class used in the service implementation:

  • org.djna.library.service: the resource manager classes, these being the classes that offer the service interfaces themselves
  • org.djna.library.resources: the resource state classes, which hold the data passed to and from the service methods, these classes will be serialised to and from JSON and XML

Packages

In the next section I’ll describe how to implement the state and resource manager classes

Information using JAXB

I  first create classes to hold the state of the various resources in our system. In this example they will be simple Java Beans with with minimal  business logic, effectively just Data Transfer Objects that will be serialised to and from JSON or XML. Something I want to study in the future is the relationship between these resource objects and JPA Entities.

Book Edition

We’ll start with a simple class representing an Edition of a Book. In this simple example the class has few attributes:

          package org.djna.library.resources;

     import java.util.Date;

public class BookEdition {
    private String title;
    private String author;
    private String isbn;
    private Date publicationDate;

The isbn uniquely identifies the book edition.

I generated getters and setters for every field, for example

    public String getTitle() {
        return title; 
  } 
  public void setTitle(String title) {
        this.title = title; 
  }

I also created a two constructors, one takes no arguments and one allowing a fully populated BookEdition to be created.

    public BookEdition() {
        title = null;
        author = null;
        isbn = null;
        publicationDate = null;
    }
       public BookEdition(String nTitle,
            String nAuthor,
            String nIsbn,
            Date nPublicationDate){
        title = nTitle;
        author = nAuthor;
        isbn = nIsbn;
        publicationDate = nPublicationDate;
    }

The zero argument constructor is required by JAXB.

Annotating for Serialization

The BookEdition class will be passed to and from the REST service and so must be serializable. This is quickly accomplished by adding annotations to the class.

@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "Edition") 
public class BookEdition {

These two annotations are sufficient to enable BookEdition to be transformed to and from XML and JSON.

  • The XmlAccessorType, with parameter  XmlAccessType.PROPERTY specifies that the attributes to be serialised will be deduced from the presence of Getters and Setters in the class. This a very simple use of JAXB. JAXB has many other capabilities, for example by using other XmlAccessTypes you can expose attributes directly. Also, if necessary you can get finer control over which fields are to be serialised and their serialized representations by applying other annotations to individual attributes.
  • XmlRootElement specifies the root element of the XML or JSON payload.

Resources using JAX-RS

Next I create a Resource Manager which will offer services to manipulate BookEditions and specify a base URI for the services. I then create the individual service methods which act on particular resources and collections of resources. In order to enable testing of the services I create a Mock Data Store for Book Editions which simply works with a few hard-coded examples.

This assumes that I have already made decisions about the URIs I intend to use to access my resources.  For this simple case, with only a single kind of resource the following URIs (I show only the significant portion of the URI, prepend http://myhost/rest to all these) will be sufficient:

  • /editions : all book editions
  • /editions?query=XXX : editions matching query
  • /editions/0858835544 : a particular edition specified by its ISBN

In the remainder of this posting I’ll focus on implementing that final operation, the retrieval of an Editions’s state specified by its ISBN.

Resource Manager Class

JAX-RS has a rich set of capabilities for mapping REST URIs to methods of resoruce manager classes. I’ implemented a very simple case: a single resource manager with methods for each particular operation I wanted to expose.

Resource Manager Class and Path

The resource manager class is an an arbitrary class, no special requirements for inheritance or interface implementation. It is annotated  to specify the URIs that will be dispatched to this class

    package org.djna.library.service;

    import javax.ws.rs.Path;

    @Path("/editions")
     public class BookEditionResources {

The context root for the Web Application is LibraryWink and the servlet is mapped to library hence the base URI for the REST services exposed by this resource manager is

   http://myhost/LibraryWink/library/editions

Next I prepared some example, hard-coded data items.

Example Data

The EditionStore class is included in the project ZIP file (TBD).

Retrieve One Item – GET

The first method I implemented retrieved a single edition, specified by its ISBN. That is, we implement a GET method for the URI

   http://myhost/LibraryWink/library/editions/0858835544

The method in the resource manager looks like this

   @Path("{isbn}")
    @GET
    @Produces( MediaType.APPLICATION_JSON)
    public BookEdition getEditionByIsbn(@PathParam("isbn") String isbn) {
        return EditionStore.getInstance().getEdition(isbn);
    }

The JAX-RS runtime has a flexible algorithm for matching the request to the service method, this considers the matching of the request URI to the @PATH annotations for class and method, the HTTP method types (GET, POST …) and also the requested Media Types.  In the general case the algorithm  needs to deal with the possibilities of there being many resource managers each with many methods. There is an explanation of the algorithm here.

In this getEditionByIsbn() example we see that the method is annotated with @GET to indicate that it deals with HTPP GET requests, and with @Produces( MediaType.APPLICATION_JSON) to specify that the response is in JSON format. It is possible to specify more than one Media type (for example both XML and JSON) in which case the client may specify its preference.

The @Path("{isbn}") annotation is a little more complex. Two things are happening here. First, this Path is used in conjunction with the overall ResouceManager class Path annotation so that the request URI that will be serviced by this method will look like this

     http://myhost/LibraryWink/library/editions/XXXXX

where XXXX will be a specific ISBN. The second thing that is being specified is that the isbn portion of the URI is to be accessible as a parameter, the parameter having the name isbn.

This now gives a context for the final annotation: @PathParam("isbn") the method declaration

    getEditionByIsbn(@PathParam("isbn") String isbn)

specifies that the Java method takes a single String parameter, and the annotation of that parameter tells JAX-RS to populate that parameter from the URI path.

Application Configuration

You may remember that we need to configure the Wink REST servlet to use our application code. We do this by creating a simple text file in the location specified by the servlet’s applicationConfigLocation parameter, that is a text fille: WEB_INF/application

The contents of the file is a simple list of resource manager classes, in our case just

    org.djna.library.service.BookEditionResources

Execute

I can now deploy the code to the WAS test environment and using a browser issue the GET request

  http://myhost/LibraryWink/library/editions/1900924323

The response is a simple JSON string containing the details of the Edition with ISBN 1900924323

   { "Edition": {
     "author": "Brian Hinton, Geoff Wall",
     "isbn": "1900924323",
     "publicationDate": "2002-03-27T14:45:43.437+00:00",
     "title": "The Guvnor"
   }  }

Conclusion 

The experience of coding a RESTful service using the Apache Wink implementation of JAX-RS is pretty good, I wrote very little code and achieved a working implementation very quickly. There’s a few directions for further study:

  • The relationship between our resource classes and JPA entities. Can we (and should we) annotate a class with both JPA and JAXB annotations?
  • How easy will it be to implement PUT, POST and DELETE?
  • How easily can we implement queries across collections?
  • JAX-RS has various techniques for allowing to refactor resource manager logic, with flexible URI path specifications. Are there obvious patterns for using these capabilities?
  • JAX-RS enables various life-cycle models for resource managers. How easy are they to use?
About these ads

4 Responses to “JAX-RS with Apache Wink”

  1. Tim said

    Hi Dave,
    I have been reading all of you REST entries, thank you for the excellent work.
    I have two questions:
    1. regarding “…Something I want to study in the future is the relationship between these resource objects and JPA Entities.” Have you had a chance to look into this? I’ve been wondering how JPA/DAO/Hibernate fit into to this cleanly.
    2. You mentioned the availability of source code download, but I can’t find any link in the entries.

    Thanks

    • djna said

      Hi Tim, thanks for the feedback.

      Concerning JPA: no I still haven’t done enough experimentation or study to have anything useful to say about this. In simple cases it seems obvious that resource objects can be JPA objects. I speculate that for larger scale projects DAOs re-emerge as a useful pattern, and DAOs may well be the resource objects.

      Concerning the source: I’ve sprinkled bits of it around the articles, I think almost everything is there. I really should attach the complete source, but this week and next I’m frantically busy simply won’t have time to make sure that I have a clean version. Apologies for the delay.

  2. Douglas said

    Congratulations for the tutorial, it was very helpfull to me!

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: