Sunday, April 22, 2012

JPA Pagination and batch reading of one-to-many relations

Context: You work at a library and you are to develop a web service which consumers can use to access library information. E.g. there is to be a service to browse authors and their associated books. The library have more than 1 million books from about just as many authors.

Pagination is one way to browse a large result set of a query as e.g. returned from the JPQL query “select a from Author a order by a.lastName, a.firstName “, and luckily, JPA supports query pagination out of the box.

If you in front of your JPA component have a web service which is to return a list of complex structures like e.g. authors and the books they have written, you will need to load all data to be returned. This might cause a performance problem, because with N authors in the result set, you will get N database calls, to fetch the books for each author, in total N+1 database calls.

Maybe you would consider to “remove” the N database calls of the books and select the books together with the authors e.g. using join fetch of the books e.g. “select a from Author a join fetch a.books order by a.lastName, a.firstName” (*), that would give you all your needed information in 1 database call. The problem is that pagination in JPA does not work (as expected) with join fetch of a one-to-many association.

If you are using eclipselink then a solution to this potential performance problem could be to fetch associated data using batch reading. In the author example above you would then be able to reduce N+1 database calls into 2 calls. One call to get the authors and one call to get all the authors associated books.

Eclipselink supports three types of batch reading: EXISTS, IN and JOIN.

One thing to notice is that when using batch reading in eclipselink then associated data will be loaded in batches the first time they are accessed. This means you need to access data to load them. I.e. data is not eagerly loaded.

The javadoc for the BatchFetchType.IN option is shown here

This uses an SQL IN clause in the batch query passing in the source object Ids. This has the advantage of only selecting the objects not already contained in the cache, and can work better with cursors, or if joins cannot be used. This may only work for singleton Ids on some databases.

Below in green I have shown three different ways to configure the use of batch reading in eclipselink. I have shown it for BatchFetchType.IN, but it applies as well for EXISTS and JOIN.

Example 1: Annotation on the associated @OneToMany mapped property
@Entity
@Table(name="AUTHOR")
public class Author implements Serializable {
    …

    @OneToMany(mappedBy="author")
    @BatchFetch(value=BatchFetchType.IN)
    private Set books;

    ...
}
Example 2: @QueryHint in @NamedQuery
@NamedQueries(value={
@NamedQuery(
    name="Author.selectAll", 
    query="select a from Author a order by a.lastName, a.firstName", 
    hints={
        @QueryHint(name="eclipselink.batch.type", value= "IN"),
        @QueryHint(name=QueryHints.BATCH, value="a.books")})})
Example 3: setHint on the query
TypedQuery q = em.createQuery("select a from Author a 
		order by a.lastName, a.firstName", Author.class);
q.setHint("eclipselink.batch.type", "IN");
q.setHint(QueryHints.BATCH, "a.books");
Further reading:

(*): Or “select distinct a from Author a join fetch a.books order by a.lastName, a.firstName” if you want to remove duplicates

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: