Object-Relational
Mapping
ORM
in Dynamic
Languages
This article looks at how GORM works. It compares
and contrasts GORM with Hibernate, focusing on three
areas: defining object-relational mapping; performing
basic save, load, and delete operations on persistent
objects; and executing queries. It describes how GORM
leverages the dynamic features of Groovy to provide a
different flavor of ORM that has some limitations but for
many applications is much easier to use.
GROOVY, GRAILS, AND GORM
GORM is the persistence component of Grails, which
is an open source framework that aims to simplify Web
development. Grails is written in Groovy, a dynamic,
object-oriented language that runs on the JVM (Java Virtual Machine). Because Groovy interoperates seamlessly
with Java, Grails can leverage several mature Java frameworks. In particular, GORM uses Hibernate, a popular and
robust ORM framework.
GORM, however, is much more than a simple wrapper around the Hibernate framework. Instead, it provides
a very different kind of API. GORM is different in two
ways. First, the dynamic features of the Groovy language
enable GORM to do things that are impossible in a static
language. Second, the pervasive use of CoC (
Convention over Configuration) in Grails reduces the amount of
configuration required to use GORM. Let’s look at each of
these reasons in more detail.
to add methods and properties to a class at runtime.
The simplest approach is to define propertyMissing() or
methodMissing() methods. The propertyMissing() method
is called by the Groovy runtime when the application
attempts to access an undefined property. Similarly, the
methodMissing() method is called when the application
calls an undefined method. These methods enable an
object to behave as if the property or method existed.
The second and more sophisticated approach is to use
the wonderfully named ExpandoMetaClass. Every Groovy
class has a metaClass property that returns an
ExpandoMetaClass. An application can add methods or properties
to a class by manipulating this metaclass. For example,
figure 1 is a code snippet that adds a method to the String
class that concatenates a string with itself.
This code snippet obtains the String metaclass and
assigns to its doubleString property a closure (a kind of
anonymous method) that implements the new method.
Groovy applications often use methodMissing() and
ExpandoMetaClass together. The first time an undefined
method is invoked, missingMethod() defines the method
using the ExpandoMetaClass. The next time around, the
newly defined method is called directly, thereby bypassing the relatively expensive missingMethod() mechanism.
Later you will see how Grails uses methodMissing() and
ExpandoMetaClass to inject persistence-related methods
and properties into domain classes at runtime, thereby
simplifying application code.
DYNAMIC GROOVY
GORM relies heavily on the dynamic capabilities of the
Groovy language. In particular, it makes extensive use of
Groovy’s ability to define methods and properties at runtime. In a static language such as Java, a property access
or a method invocation is resolved at compile time.
In comparison, Groovy
does not resolve property accesses and method
invocations until runtime.
A Groovy application can
dynamically define methods and properties.
Groovy provides a
couple of different ways
CONVENTION OVER CONFIGURATION
The second key idea in GORM is CoC. Its premise is that
a framework should have sensible defaults and should
not require developers explicitly to configure every facet;
instead, only the exceptional cases should require configuration. CoC was first popularized by the Rails and Grails
frameworks, but mainstream Java EE frameworks including Spring9 have begun to adopt the concept. Today,
developers expect modern Java EE frameworks to require
much less configuration than older frameworks.
CoC is used throughout Grails. For example, built-in defaults determine how to map an HTTP request to
g r oovy:000> String.metaClass.doubleString={->delegate+delegate}
= ==> groovy.lang.ExpandoMetaClass$ExpandoMetaProperty@14a18d
g roovy:000> “ACM Queue”.doubleString()
= ==>ACMQueueACMQueue
FIG 1