Building Standalone GORM applications in Maven
Wednesday, February 25, 2009 at 12:01AM I spent a little time researching the use of the GORM support outside of grails this week. That's right, with some work, you can mount Groovy, GORM and Hibernate in a Spring MVC application, and get the highly adaptable Grails Object Relational Mapping API in a Spring web app.
There is a great example built using Ant and Ivy in the Grails 1.1-RC1 samples directory (petclinic-mvc). However, I use Maven for my builds, and wanted to attempt the same thing. Let's take a look at how we can get this done.
What is GORM?
If I define an Employee groovy class, place it in a pre-configured directory (in grails, it's grails-app/domain), and define it this way:
class Employee {
String firstName
String lastName
}
I get the following things for free:
- Methods injected into the Employee class that allow it to operate both as a Domain object and a mechanism to load, query, persist and create Employees
- A default primary key ('Id') using the default key generation mechanism for the database selected
- An equals and hashCode method for comparison between domain objects
- Versioning
- And much more
Here is an example of GORM in action:
def e = new Employee(firstName:"Ken", lastName:"Rimple").save()
// later...
def results = Employee.findByLastName("Rimple")
Grails functions as an Object-Relational Mapping system. It wraps Hibernate and follows the information in the Domain classes to build the mappings.
Grails normally uses an "open session in view" approach to expose the hibernate domain objects to the JSP. In our example, we will do the same thing. You could, of course, add in your own Hibernate to business Data Transfer Object layer, and avoid exposing the domain objects to your view layer.
Spring MVC and ORM
Spring MVC traditionally uses Controllers to communicate with Services, which often delegate database access to Data Access Objects (DAOs) or Repositories (Hibernate/JPA DAO equivalents). GORM bypasses the DAO to JDBC boundary and provides a simple wrapper in the form of "mix-in" methods.
GORM within a Spring MVC Application
GORM is a very agile and nimble data mapping solution. However, it comes with the Grails platform, which you may or may not be able to use in your environment. Luckily, the Grails team has been able to isolate GORM and make it available as a separate set of libraries that can run within a Spring Application Context.
You won't get everything. For example, I can't figure out a way currently to integration-test the Domain classes (I've tried deferring the tests until the end of the Maven install phase, but that doesn't work). However, you will gain rapid application development abilities within a Spring MVC application.
The Spring Configuration
GORM requires a Spring Configuration, and is configured in the Application Context. There is a Grails namespace available if you include the right libraries. I have added to my configuration (based on the release notes for 1.1):
<gorm:sessionFactory base-package="maven.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>
We must provide a mounted DataSource, a ResourceBundleMessageSource, and to place our domain classes in a particular package structure (maven.demo.domain in this example). I also enabled the
<context:annotation-config/> and <tx:annotation-driven/> settings.Maven Configuration
With the current state of artifacts in Maven, you'll need to set up a repository and a plugin repository in order to build. That's because we're using gmaven, a codehaus project, to build the groovy code, and only the latest release candidate supports a special annotation we will use to define a GORM Domain Class (more on that below).
Here are the relevant fragments needed to configure the repositories, the GMaven plugin and the dependencies needed to build the application:
Repositories:
<repositories>
<repository>
<id>codehaus-snapshots</id>
<url>http://snapshots.repository.codehaus.org</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>codehaus-plugin-snapshots</id>
<url>http://snapshots.repository.codehaus.org</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
GMaven Compiler Plugin
<build>
...
<plugins>
...
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0-rc-5-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy.maven.runtime</groupId>
<artifactId>gmaven-runtime-1.6</artifactId>
<version>1.0-rc-5-SNAPSHOT</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Dependencies
This is a list of dependencies I've used to build and test my code. There are probably redundancies here. I've stripped out a few.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.0.1B_spec</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-bootstrap</artifactId>
<version>1.1-RC1</version>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-gorm</artifactId>
<version>1.1-RC1</version>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-web</artifactId>
<version>1.1-RC1</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.3.0.ga</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.7</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.8.0.GA</version>
</dependency>
</dependencies>
One Last Thing
If you're building GORM Domain Classes outside of Grails, you have to annotate them this way:
import grails.persistence.Entity@Entity
class Employee {
...
}
Wrap-Up
If you are building with Ant, you already have a good example to go on from the distribution. However, for Maven, it is a little more complicated to configure, and thus the example posted here.
I would highly recommend you take some time and review the application context, Spring MVC settings (including a set of annotation-driven Groovy-based controllers and JSP views) in the petclinic-mvc sample application, otherwise that information would just be duplicated here. Even without using GORM, you can see the difference between using the old-style XML-based controllers and annotation-driven Controllers, and gain even more agility writing them in Groovy.
I used the sample solution's ivy.xml settings and other information to base my research on. I've had a great amount of help from Graeme Rocher and Domingo Suarez Torres who set me straight on the gmaven plugin settings. The URL for reference is here and also in the goovy-user group here.
Ken Rimple |
1 Comment | 

