Friday, April 20, 2012

REST: Play Framework vs Java EE 6

Here, I will very briefly, present a simple example on making a REST service using the Play Framework (1.2.4) vs making a REST service using JAX-RS in java EE 6.

The goal is to enable us to compare the complexity and the amount of code to be written (to implement a REST service) in respectively Play and in Java EE 6. In both Play and Java EE 6, there are several ways to implement a REST service, so this presentation will (rather arbitrarily) choose one approach from each platform and present that.

In our example, we are creating a Library service exposing books of a library database as resources via REST.

We will represent a book resource with the following (directory structure like) URI:


http://mylibrary.com/library/books/{isbn}

The part {isbn} above is the book's International Standard Book Number, and represents a dynamic part, replaced by the books isbn number.

An example request is: http://mylibrary.com/library/books/0596529260 which in our example should return a JSON representation of the book as shown below (The JSON representation is deliberately made simple for legibility reasons.):


{
	"isbn":"0596529260",
	"title":"Restful Web Services",
	"authors":[
			{"firstName":"Leonard","lastName":"Richardson"},
			{"firstName":"Sam","lastName":"Ruby"}]
}

How can we implement this in Play?

To make things work in Play we need to implement a Play controller (extending play.mvc.Controller) and then configure URLs mappings to the functions in the Play controller via the file conf/routes located in Play's conf folder.

We name our Play controller Library and its implementation is sketched below.


package controllers;

import play.*;
import play.mvc.*;
import models.*;

public class Library  extends Controller {

	public void static getBookByISBN(String isbn){
		Book book = … look up book by isbn
		renderJSON(book);
	}

}

The Library controller contains scripting to look up the book Book book = … look up book by isbn (could be done using JPA) and a call to an inbuilt function renderJSON(book) to return the book formatted as JSON.

(In case we use JPA and for some reason need a transactional context, then Play is handling the transaction implicitly by executing the getBookingByISBN call within a transaction.)

The URL mapping, in the Play file conf/routes, is shown below.



GET     /library/books/{isbn}    Library.getBookByISBN


The structure of the conf/routes configuration line is to be read as: For HTTP GET requests then map the URI path /library/books/{isbn} to the class and function Library.getBookByISBN.

Notice the name isbn. It is, intentionally, the same name as the name of the parameter isbn of the static method getBookByISBN of the Library controller. This is a general principle in the Play framework, called smart binding.

The rendered model objects are shown below. They are just simple POJOs (Plain Old Java Objects) but are shown here to complete the example. Again, the model objects are deliberately made simple for legibility reasons.


package models;
import java.util.*;
public class Book {
	public String isbn;
	public String title;
	public List authors = new ArrayList();
}



package models;

public class Author {
	public String firstName;
	public String lastName;
}


That was, very briefly, one way to expose a REST service in Play!

Let's move on and see how we can implement the same example in Java EE 6 using JAX-RS annotations.

When possible, we will use the same names as in the Play example above to ease our comparison between the two examples. For the simplicity of the example, we will also reuse the POJOs from the Play example above.

The Java EE 6 example is packaged and deployed as a web application (war). (During development this is done automatically for you if you are using the Netbeans 7.1 IDE as I am).

Below I have shown what corresponds to the Library controller in the Play example. Notice it is a POJO with JAX-RS annotations. The POJO exists within the classpath of the web application.


package controllers;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import models.Author;
import models.Book;

@Path("/library")
public class Library {

    @GET
    @Path("/books/{isbn}")
    @Produces("application/json")
    public Book getBookByISBN(@PathParam("isbn") String isbn) {
        Book b = … look up book by isbn
        return b;
    }
}

Notice, that all the URI path configuration to a class and method is done via the JAX-RS annotations: @Path("/library"), @Path("/books/{isbn}"). The mapping between the isbn part of the URI and the parameter isbn is done via the @PathParam("isbn") annotation. The mapping to the GET request is done via the annotation @GET. The representation of the output as JSON is here done implicitely via the annotation @Produces("application/json").

(In case we need a transactional context, we could easily turn the POJO above into a stateless session bean by adding the annotation @javax.ejb.Stateless at the class level of the POJO.).

Now we need to add the following configuration snippet code shown below to the web.xml of the web application. If you are using Netbeans 7.1, then this is done automatically by Netbeans for you.


<servlet>
    <servlet-name>ServletAdaptor</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>ServletAdaptor</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
    
    

Again, job done, this was very briefly, one way to expose a REST service using Java EE 6.

In conclusion:

Amount of code: With respect to the amount of code to write to get up running, then based on the presentation above, I think it is fair to conclude that the two examples are kind of "equal".

Complexity: With respect to complexity it is more difficult to compare. It depends on our knowledge and experience with the two platforms.

If you look at the "learning curve" as an indicator of complexity between the two examples I think Play is less complex than Java EE 6. E.g. if you compare JAX-RS annotations with the conf/routes configuration in Play, then based on the steepness of the implicit learning curve I think Play is less complex than JAX-RS. When using Java EE 6 you need some knowledge of the Java EE 6 platform and you need to know of the use and meaning of the different JAX-RS annotations.

Maybe the needed tooling used to create the examples can be used as an indicator of the implicit complexity of the examples. The Play example above was created using a terminal and a simple text editor (I used BBEdit). The Java EE 6 example above was created using the Netbeans 7.1 IDE. Netbeans hide away the complexity of the Java EE 6 platform. So, when looking at the tooling as an indicator of complexity, then Play is less complex than Java EE 6.

And that completes the presentation … :-)

References:

7 comments:

Arun Gupta said...

Thanks for the nice post!

"web.xml" is optional in Java EE 6 and can be replaced with:

@javax.ws.rs.ApplicationPath("/*")
public class ApplicationConfig extends javax.ws.rs.core.Application {
}

Jersey will then register an implementation specific Servlet.

Unknown said...

Hi Arun ... :-) Thx for your comment ... :-)

Sandesh Kumbhar said...
This comment has been removed by the author.
Sandesh Kumbhar said...
This comment has been removed by the author.
Unknown said...

Your background hurts my eyes

Unknown said...

Your background hurts my eyes

Unknown said...

Your background hurts my eyes