Using Groovy's GORM in Spring

Joseph Nusairat
  • September 2009
  • Java
  • Groovy
  • Grails

Groovy and Grails has stormed the Java world as the new way to create reliable Web 2.0 applications in a concise and fast manner. The ability to go from the start of a project to the end, especially for a smaller demo, is exponentially faster. This is due to the many features of Grails. Out of the box applications are easier to build, create, test, and deploy because of the convention over configuration methodology. In addition Grails is written in Groovy, a dynamic language that can run on the JVM and interact as if they were Java classes. Groovy gives the power to write dynamic code with power and features that are normally unavailable in Java. Possibly the best example of this power in Groovy and Grails is the creation of the Grails Object Relational Mapper (GORM).

However, we can’t all just go to our managers and say “Hey, let’s rewrite this entire application in Grails”. We would more than likely get laughed out the door. At many companies it also isn’t feasible to ask for an entire framework shift. However, most of us can request “small changes”, especially if they help save time.

With Spring 2.0 and above we can create Spring beans out of Groovy objects. This gives us a nice ability to use Groovy nomenclature in our Spring code (e.g. the Meta Object Programming (MOP), cleaner syntax, etc). However, what we do not get with straight Groovy is a better way to interact with the database. For that we need the power of GORM. With Grails 1.1 that has become significantly easier.

Why Do I Want to Use GORM?

You may be familiar with Hibernate and wonder why you should bother with GORM. Hibernate is a GREAT ORM, and the framework has been developed steadily since its inception. While Spring’s wrapping of Hibernate has made it easier to interact with the database, it is still missing the readability and ease of use that most modern developers want. The following example demonstrates how GORM brings simplicity to Hibernate code. (Please note that although GORM derives from Hibernate any mention of Hibernate here will specifically be in reference to the pure Java Hibernate form.)

This example starts by performing a simple query to retrieve items from the Todo table in the database where name and description matched some given text. When using Spring’s Hibernate Template, the code would look something like this:

public List find(final String name, final String desc) {
  final String hqlQuery =         
    "select t from Todo t where t.name = :name and t.description = :desc";
  return (List) getHibernateTemplate().execute(new HibernateCallback() {
    public Object doInHibernate(Session session) throws HibernateException {
      Query query = session.createQuery(hqlQuery);      
      query.setString("name", name);
      query.setString("desc", desc);
      return query.list();
    }
  });    
}

Listing NUS-1

While this code does the job, something more readable would not only make it easier for everyone to understand, but would also cut down on time and errors.

Now if we were using Java Persistence API (JPA) supported queries we could make the code in Listing NUS-1 a bit simpler as shown in Listing NUS-2.

@PersistenceContext
EntityManager manager;
          
public List find(final String name, final String desc) {
  final String hqlQuery =         
    "select t from Todo t \
    where t.name = :name and t.decscription = :desc";
    return manager.createQuery(hqlQuery)
                  .setParameter(“name”, name)
                  .setParameter(“desc”, desc)
                  .returnResultList();
}

Listing NUS-2

This is more concise and fairly readable, but several queries in a row would require repeating the same block of code many times with slight alterations and would increase our time and effort to do so. You may be asking yourself what is the problem with this? After all I am sure many of you have witten similar or even more verbose code before. The problem lies in the fact that code should be easily readable. As good developers we want to concern ourselves with the business logic, using the write tools. We shouldn’t have to spend too much of our time deciphering easy parts of the code, and queries to the database are often just that. Using GORM helps us to solve that problem, and here’s how.

Let’s take what that code is doing and write it in English. The code is wanting to query the Todo table to find all by name and description. Well how do we write that out? How about this:

Todo.findAllByNameAndDesc(name, desc)

That is simple, concise, and in GORM that line is actual code. This begins to show the ease of using GORM over Hibernate and we will expand on that concept when using Criteria queries later. But first, let’s see how to use GORM in our Spring application..

Injecting GORM

The interesting thing about writing an article on Using GORM with Spring is that there is barely enough setup required to fill a blog entry, let alone an entire article. In fact, you could almost Twitter the entire extra XML needed; however, for the purpose of learning we are going to go into a bit more detail. We will show not only how to set up GORM in Spring but also various options when using Spring. This will require configuring the Spring beans, installing the right JARs, and, most importantly, understanding the various ways to use GORM in your application.

Configuring the Spring Beans

We are going to go over in this section the necessary modifications to the spring files needed for using GORM with Spring. The modifications here will be to your bean configurations and are independent of whether you are using Spring in web environment or a standalone application. That being said of course if you were to be using Spring in a web environment no modifications are needed for the web specific files (like web.xml) The first thing to do is to add an XML namespace to your bean configuration. This one is specifically for GORM: xmlns:gorm="http://grails.org/schema/gorm"

Once the namespace is set you will be able to use the GORM Session Factory instead of the Hibernate Session Factory. Listing NUS-3 is an example of the GORM bean definition that would go into your bean definition file.

<gorm:sessionFactory
  base-package="com.integrallis.demo.domain"
  data-source-ref="dataSource"
  message-source-ref="messageSource">
  <property name="hibernateProperties">
    <util:map>
      <entry key="hibernate.hbm2ddl.auto" value="update"/>
    </util:map>
  </property> 
</gorm:sessionFactory>

Listing NUS-3

Luckily, this listing isn't too complicated. Often times with Spring beans one has to define the classes being used; however, with the use of XML namespaces that is not necessary Spring is aware based on the namespace used With that being said Listing NUS-3 serves the same purpose as your standard Hibernate definitions usually do in Spring and that is to define the Session Factory. In fact, most of the items defined will be similar to Hibernate Session Factory listings.

Line 1 is the name space reference to the GORM Session Factory, which is fairly standard stuff. The rest really is general Hibernate type configurations that are specific to GORM. Line 2 is used to specify where your domain objects exist. Remember, with Hibernate you have to define your domain objects. There are basically two ways to do this: one is to define a directory full of hibernate XML mapping files, the other is to specify a directory of domain objects. Line 3, data-source-ref, references a data source that you have defined in Spring. This can be a Java Naming and Directory Interface (JNDI) data source, in memory data source or a more database specific data source. Line 4, message-source-ref, is specific to GORM itself. GORM allows one to define validation constraints in its domain, these constraints then print out messages via a message resource bundle. In Grails this message resource bundle is a predefined name and area, with GORM you will have to specify that item yourself. In GORM these validators are in a specific place with a specific name, but with Spring one can customize the location and name of this resource bundle. On line 5 we start to define the Hibernate properties. If you were using Grails these items would be specified inside your DataSource.groovy file and if you were using JPA would be in the persistence.xml file.

JAR Files Needed

In addition to defining the GORM Session Factory we will also need a few of the Grails JAR files to make this work. Only three jars from Grails are needed and can be included either manually or via your Ivy/Maven configurations:

  • grails-bootstrap 1.1
  • grails-gorm 1.1
  • grails-web 1.1

Configuring the Domain Class

When configuring domain classes with Hibernate the classes are JavaBeans. When using GORM they have that JavaBean look but with less baggage (i.e. no getters / setters needed with Groovy). In addition, we are able to set validations, mappings, constraints, etc with our GORM domain objects. All of that will still be available when using GORM with Spring. However, one important addition needs to be made in order to make GORM work with Spring. The @Entity annotation needs to be added to the class level domain object so that it is recognized as a GORM object by the container. Listing NUS-4 is a partial listing of a Todo domain class with the @Entity annotation.

package com.integrallis.demo.domain
import grails.persistence.Entity
          
@Entity
class Todo {
  String name
String descr
  // Any GORM constraints and mappings
}

Listing NUS-4

Using GORM to Create Criteria Queries

One of the biggest headaches I have ever had with Hibernate was using Criteria queries. These are extremely powerful queries whose biggest advantage is that you are able to create dynamic queries without having to do string concatenation of SQL / HQL strings. Essentially the developer will tell the Criteria object what field(s) to do comparisons against and then to execute the query against a specific domain. Here’s an example of a simple criteria in Hibernate for querying all the records where name or description equal some parameter.

Session.createCriteria(Todo.class)
  .add(Restrictions.or (
    Restrictions.eq("name", someParam),
    Restrictions.eq("description", someParam)
  ) ).list()

Listing NUS-5

Part of the downside to this code is the readability. Never mind the fact you also had to remember to inject the session. The fluidity of this is not as nice as it could be; however, that is corrected using GORM. With GORM criteria queries have a Domain-Specific Language (DSL) associated with them, making the readability and usability easier. Not to mention there is no need to tell the container to inject sessions, data sources, etc. In a purer way all you are dealing with is the domain you are using. Listing NUS-6 is the query from Listing NUS-5, but written in GORM.

Todo.createCriteria().list() {
  or {
    eq("name", someParam)
    eq("description", someParam)
  }
}

Listing NUS-6

This code performs the same query as the Hibernate code did above albeit a bit cleaner. Part of the idea with using GORM is that your code becomes more readable. For one thing, the fact that it is an "or" restriction is much more prominent. However, the skeptic in mind can easily look at the first query and realize using static imports would shorten the text itself. Static imports allow you to define the static methods on classes as imports at the top of your code. So with static imports one would be able to shorten Restrictions.or to or. And while that is true, there is still another value added feature with the GORM that is missing from the Java query: the ability to actually embed code in the DSL. If we want to use a for loop or some simple checks before adding the restrictions, we will break up the readability of the Hibernate Criteria and have to start to build each section of the normal Hibernate query in chunks. However, that is not the case with GORM Criteria queries.

We can insert the code directly inside the closure, so suppose we actually want to pass the name of the field and the value in a map and "or" it against all passed in fields? With GORM that’s simple and DOESN’T breakup the readability.

Todo.createCriteria().list() {
  or {
    map.each() { key, value ->
      eq(key, value)
    }
  }
}

Listing NUS-7

Since Listing NUS-7 is a Groovy closure, one can add any code or call any method from within the closure itself. This provides elegance and simplicity not normally found in Java criteria queries.

Using Groovy or Java?

Hopefully in the preceding section I have convinced you to consider using GORM inside of Spring. Now lets take a look at the practical implications of integrating GORM, which uses meta programming features, with Java and Groovy code.

First off, if your existing code or the code you want to use GORM with is Groovy you are 100% fine. You can use everything we discussed with ease. However, if you are going to start using GORM in existing straight Java code the integration is not AS seamless but it is still pretty easy. Groovy, in the end, compiles down to Java byte code, which allows your Java code to fully interact with the Groovy code. However, this does come with a few caveats and the biggest one does affect your ability to use GORM. One is the way in which Groovy works. Groovy can work just like any regular Java class with methods and properties. By default when you create a method in Groovy that looks like

def myMethod {
  "joseph"
}

When this is compiled and consumed by a Java class the method will assume that it is returning a java.lang.Object. If one had defined an actual return it would assume the actual return. These items work extremely transparently. However in Groovy one can intercept method calls to the class for methods that do not exist already on the class. One way to do this is by defining a method called methodMissing on the Groovy class. This method will then have passed into it the name of the method that was called and all the parameters passed into it as well. It is then the responsibility of this method to determine based on the name what to do.

In theory one could easily make use of the same features with Java; however, since Java has to get compiled first you would throw errors because the compiler could not see the method at compile time. With Groovy, and other dynamic languages, we do not have this limitation. And it is this power that makes the dynamic queries like Todo.findByName() work. However, this will also have consequences when interacting between Java and Groovy that we will discuss below. So what are your choices?

  1. Convert the classes you have that are Java based that you want to use GORM with into Groovy classes. Now this may seem like quite the cop out of an answer but truthfully, why not? Aside from removing the public from the class declaration and changing the extension of the file name, the code can remain the same. Not only that but now your class will have access to all of Groovy and Java’s abilities.
  2. If the first way scares you then another method is creating the traditional Data Access Object (DAO) class. In this case your DAO would be a Groovy file that would mainly serve to call the domain class. For the most part, these classes will probably only be about one line long for many queries, but may be a bit longer if you are using HQL or Criteria queries. One advantage of this methodology is that it is easier to perform unit testing on not only the service calling it, but the DAO itself.
  3. The last solution takes the idea of using a DAO but does it in more of a Grails way. That is to put your database interactions directly on the domain class in the form of concrete static methods. This methodology can also be used if you pick the first method and are using non MOP created queries.

Performance Considerations

One of the odd things with Java developers and their reasons against using Groovy is the "performance considerations". The reason I say this is odd is because there was a similar argument in the late '90s between the C world and the Java world. The argument basically boiled down to which was faster and does it matter. Well that argument has arisen again when comparing Groovy to Java, so I wanted to take a look and see if it matters and by how much. And while the Groovy code may be slower, is it really going to matter when factoring in the time delays when interacting with the database.

Before we start let’s remember to take these numbers as an example and not the Holy Grail of performance calculations. This is not just running two classes but running two classes and a whole lot of overhead that can easily vary. Even within our runs you will see subsequent runs of the same code will vary. We have the JVM to contend with, when Garbage collection is running, the MySql database all factors in contributing to time and that can cause differences.

So my experiment was fairly simple: I wanted to test inserting and retrieving from the database. The first test created a for loop that creates a thousand records and saves them. The second test, which performs a query based off of description, returns a thousand records as well (because all my descriptions I inserted were the same). To make things a bit tougher on GORM I used a MOP query instead of an HQL query. The Java version uses a Hibernate HQL query. I had considered using a straight JDBC query for the Java portion of the tests, but I felt that would not necessarily be a fair comparison since most of us would not use straight JDBC. In addition these tests were both ran on a MySql database.

The Results

We will take a look at the results below which may surprise you. For the experiment I ran each set three times through the UI using Springs PerformanceMonitorInterceptor to capture the timings of the DAO call.

Record Insertion

The first batch was to test inserting 1000 records into a Todo table using GORM versus using Java Hibernate.

Run 1 Run 2 Run 3
GORM 1438 ms 711 ms 625 ms
Hibernate – Java 640 ms 491 ms 412 ms

I found the results interesting mainly due to the time it took GORM for the FIRST time it ran. While the Hibernate inserts ran faster they both steadily progressed at a faster rate for each subsequent test. Both results in the end were fairly good though.

Record Retrieval

The second set of tests checked the performance of retrieving from the database. In addition, Hibernate and GORM would have to create actual Todo objects of each record and return them in a List back to the calling service.

In this case I wanted to show you the queries used since it’s not as straight forward as insertions. For the Groovy query we used the MOP query:

def findByDescription(String s) {
  Todo.findAllByDescription(s)
}

For the Hibernate example we used the HibernateDAOSupport subclass that comes with Spring to create a one line query:

public List findByDescription(String desc) {
  return getHibernateTemplate().find("From Todo t where t.description = ? ", desc);
}

The results actually surprised me a bit.

Run 1 Run 2 Run 3
GORM 85 112 131
Hibernate – Java 199 244 254

The GORM query actually performed FASTER. Without further investigation I cannot tell you why. . These tests are obviously not an "end all, be all" in performance comparisons but at least give you some ideas when weighing in on whether to use GORM.

Conclusion

Interacting with the database in traditional Spring applications can be a tedious process; however, I hope what I’ve shown here is that using GORM to create our Spring applications can make the process much easier. Using a dynamic language has advantages over traditional static languages; readability and the ease to create being the major ones. In the end, using GORM, you will have cleaner and more maintainable code, which should be a goal for all of our projects.

Share