Using Hibernate with Google Web Toolkit (GWT)

Hibernate is an excellent tool which saves many projects from substantial amounts of code.  Gone are the days of writing massive datasource layers full of obnoxious JDBC code.  As gravy you also get simple query objects, caching, connection pooling and countless other great features.  GWT on the other hand provides a robust API using a revolutionary new paradigm for writing javascript and complex dhtml interfaces.  The latest version of Hibernate supports annotations, meaning you can ditch all of the XML that was previously required.  This feature of course requires Java 5 to support annotations.  Unfortunately, as of GWT 1.4, only Java 1.4 is supported on the client-side.  I have created a solution to bridge the Java 1.4 to Java 5.0 gap.

In my latest project, I started by creating the server-side code all using Hibernate 3 annotations. I didn't use a single XML file for configuration. Using pojo (Plain Old Java Object) entity classes annotated with EJB 3.0 / Hibernate compatible annotations, I had no problems building the relational object mapping and the core classes of the service.

I had decided on trying GWT for the first time to develop the client-side code. I was able to integrate it into my development environment but immediately ran into an issue when I found out that there was no Java 5 support which is needed for Hibernate 3 annotations. What I ended up doing is creating a client-side class to work as the serializable, transient entity object. Yes, this does mean that I have both a server-side entity class and a client-side entity class, but think: All of your client-side GWT Java compiles into javascript anyway. Of course you'll need a javascript-based entity to work on the client-side.

Example: Mapping two tables with a one-to-many relationship.

The diagram below shows the server-side to client-side responsibilities. Each side has entities, but the server side does all the transformation between the two with the business logic. One could say that the client application requests the service which uses the business logic to process server-side entities and interface with the client-side with client-side entities. With that said, on to the code examples!


In my example we are modeling Shelfs, Books and the relationship between the two. What we have is a relational database with two tables: Shelf and Book. The Book table has a field with a foreign key reference to the Shelf's primary ID, creating a One-To-Many relationship of Shelfs to Books. In the real world this means that a shelf can have many books on it but a book can only be on one shelf at a time.

On the server side, you will end up with some code that may look something like this:

@Entity
@Table(name="shelf")
public class Shelf {
    private Integer id;
    private String name;
    private List<Book> Books;

    public Shelf(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    public void setName(String name) {
        this.name = name;
    }
    @OneToMany(mappedBy="bookId")
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
    public List<Book> getBooks() {
        return Books;
    }
    public void setBooks(List<Book> Books) {
        this.Books = Books;
    }
}

@Entity
@Table(name="book")
public class Book {
    private Integer id;
    private String name;
    private Shelf shelf;

    public Shelf(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    public void setName(String name) {
        this.name = name;
    }
    public Shelf getShelf() {
        return shelf;
    }
    public void setShelf(Shelf shelf) {
        this.shelf = shelf;
    }
}


These annotations provide the meta info Hibernate will use to create object-relational mapping.  This is usable for any server-side code, however GWT can not use annotated code and also can not have hibernate running on the client-side.  Business logic is required to translate the Hibernate entity into a GWT entity.  Unfortunately this does mean that you must have 1 server-side class and a separate client-side class, however both are fairly thin classes and don't require a lot of work.

Your client-side classes in this example would look like this:

public class GWTShelf implements Serializable {
    private Integer id;
    private String name;
    private List Books;

    public Shelf(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    public void setName(String name) {
        this.name = name;
    }
    public List getBooks() {
        return Books;
    }
    public void setBooks(List Books) {
        this.Books = Books;
    }
}

public class GWTBook implements Serializable{
    private Integer id;
    private String name;
    private Shelf shelf;

    public Shelf(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
   
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    public void setName(String name) {
        this.name = name;
    }
    public GWTShelf getShelf() {
        return shelf;
    }
    public void setShelf(GWTShelf shelf) {
        this.shelf = shelf;
    }
}

Now you have both server and client entity classes.  What you need is the business logic to process GWT objects using Hibernate objects on the back end.  In this example, MyService is the proper GWT RPC service and we're going to write a simple method called getStudents which is to return a List of students.

public class MyService extends RemoteService {

    public List getStudents() {
        List gwtStudents = new ArrayList();
        List<Student> students = getHibSession().createCriteria(Student.class).list(); // lists all students
        //iterate students, create a GWTStudent from each
        for (Student student : students) {
            GWTStudent gwtStudent = new GWTStudent();
            gwtStudent.setId(student.getId());
            gwtStudent.setName(student.getName());
            //iterate books, create list of GWTBooks, set on student (optional)
            ...
        }
        return gwtStudents;
    }
}

This is a very simple example that only shows 1-directional use of this.  To save a gwt version of a class into a hibernate version, just pass the gwt object into the service call and convert it back to Hibernate's version.  There are a few caveats, though:

You must query the object by ID, then update its fields to update it.
Updating lists requires special handling
You must be careful to honor lazy loading to some degree else you may load a whole DB with one call
GWT Objects must be serializable and Java 1.4 compliant.

I've successfully employed this strategy in my latest web application.  It did the trick for every case I had.  Though it's not the perfect solution, it does get the job done and still gives you operating efficiencies gained with using Hibernate while allowing full use of GWT's capabilities.

15 Comments

Post a comment here or discuss this and other topics in the forums

Haha it is. You should send

Haha it is. You should send me an email!

is this rugburn?

Sorry, that's how I always read rbgrn. Thought you were a sysadmin, I'm working on a GWT project now just ran into this.

Use JDO, not Hibernate

Though Hibernate is an excellent system, the Google APP Engine uses JDO, which is to say: if you use JDO with your GWT application, then your application will port painlessly to the App engine. Not true if you use Hibernate. Though there are many differences between the two systems, they're roughly comparable in capabilities (though JDO is not nearly as SQL-specific as Hibernate because it doesn't presuppose that it's sitting on top of a RDMS). Find a very good open-source JDO implementation at http://www.datanucleus.com/

c'est qoui , c'est truc qui

c'est qoui , c'est truc qui date de 2007 !!

Using Hibernate POJO with GWT

Using Hibernate POJO with GWT generally leads to two issues :

* Lazy properties issue : when trying to send a partially loaded Hibernate POJO to the client-side of GWT (Javascript), the GWT compiler throws a Serialization exception because it the CGLIB generated proxy does not belong to the JRE emulation.

* Type issue : Hibernate replaces some basic Java types with various subclassed implementation (such as java.sql.Timestamp instead of java.util.Date or PersistentList for List collections). Javascript serialization of these classes will fail, since they do not belong to the JRE emulation supported by GWT 1.4 (note : the Java SQL dates are now supported by GWT 1.5)

The goal of hibernate4gwt is to solve them and allow seamless use of Hibernate POJO with GWT client code.

re: Using Hibernate with Google Web Toolkit (GWT)

Hibernate4GWT provides a Java5 support mode, that seamlessly clone your annotated Hibernate POJO to GWT compatible DTO. It can save you writing a lot of code :GWTStudent gwtStudent = new GWTStudent();gwtStudent.setId(student.getId());gwtStudent.setName(student.getName());...is just replaced by beanManager.clone(student, GWTStudent.class) !Furthermore, note that even when GWT will support annotations and Java5 syntax, you will not be able to directly send your Hibernate POJO to the client layer, because of Hibernate dynamic proxy which are not supported byt the GWT JRE. You can read http://hibernate4gwt.sourceforge.net/hibernate_gwt_problem.html for more details.RegardsBruno

re: Using Hibernate with Google Web Toolkit (GWT)

I would have tried Hibernate4GWT but like others have stated, it does not support annotations. Hopefully the next iteration of GWT will have annotations support and we'll see community support from products like Hibernate4GWT for that.Thank you all for the suggestions.

re: Using Hibernate with Google Web Toolkit (GWT)

You can use hibernate4gwt (http://sourceforge.net/projects/hibernate4gwt/). With hibernate4gwt you can have only one data model for Hibernate and GWT.Weakness of this solution:- you can't use annotations :( but I hope that GWT come soon :)Regards,

re: Using Hibernate with Google Web Toolkit (GWT)

Hello Robert,Did you try hibernate4gwt library (http://hibernate4gwt.sourceforge.net) ? It will help you to seamlessly clone your Hibernate class to DTO, and takes care about lazy associations.RegardsBruno

re: Using Hibernate with Google Web Toolkit (GWT)

bwtaylor,That was a very insightful comment. Thank you. My approach works for small models but you're correct on the difficulty in maintaining as you scale up. I also wish there was a better method than parallel models to implement this but for now it's how it has to be. I'll try out Dozer if I run into a project requiring a larger model.Thanks again

re: Using Hibernate with Google Web Toolkit (GWT)

We didn't take this approach for several reasons:- Writing the assembler code by hand is a lot of work for big data models- Keeping it and its unit tests in sync is a maintenance barrier to staying agile with the object model- Dealing with associations between entities is hard (eg: what if your Student has a Teacher)- Dealing with collections is hard, especially when you use a real class hierarchy so that a collection called facultyMemebers can include a Teacher, Principal, SubstituteTeacher, Counseler, Coach, etc...We use Dozer as it can navigate through those issues. We also use hibernatetools with custom freemarker templates to generate our DTOs (the GWTxyz objects in your model) and then we use Dozer to map them. Dozer is very finicky and doesn't have a lot of examples with complex situations.Really, it's kind of sad that there's not an easy way to solve the assembler problem.

re: Using Hibernate with Google Web Toolkit (GWT)

Artur,The reason I said that is because I had made the mistake of assuming that Hibernate would know to load the entity given a pojo version with an ID set. That doesn't work. You have to explicitly call load for that class and ID to get a Hibernate-instantiated object and then you can update fields and save.

re: Using Hibernate with Google Web Toolkit (GWT)

Rajesh,I'm keeping my eye out for a more elegant solution but until GWT supports Java 5 standards, I don't see the parallel object models going away if you wish to use Annotated Hibernate entities.

re: Using Hibernate with Google Web Toolkit (GWT)

Great article. I use similar approach.I recommend using Dozer for converting entities (it supports collections also). Also, I think that GWTShelf and GWTBook should implement com.google.gwt.user.client.rpc.IsSerializable instead of java.io.SerializableCan you also put some detail why you watch for this: "You must query the object by ID, then update its fields to update it."... I don't see such requirement is needed

re: Using Hibernate with Google Web Toolkit (GWT)

With the latest version of GWT I thought it was not necessary to create parallel object models?