Chapter 9
[ 227 ]
when:
fred.firstName = "Freddie"
fred.save()
def customers = Customer.list()
then:
customers[0].firstName == 'Freddie'
}
}
The preceding example saves a new customer "Barney" to the database, gets the
customer object for "Fred", and updates the firstName field. The list method
returns all customers as a regular list collection.
Let's take a second to look at what Grails has done to our class. The Customer class
that we declared had no base class to inherit methods from, and it did not define
these methods. Grails has somehow used the features Groovy to add these methods.
Given what we know already from previous chapters, we can probably guess some
of the ways this might have been achieved.
We know that we can add methods to a class at runtime via metaClass.
So, this might be one approach:
Customer.metaClass.static.get = { ... }
Customer.metaClass.static.list = { ... }
Customer.metaClass.save = { ... }
Grails is built on top of Spring, so we could hook into the initialization of
ApplicationContext and enhance the Customer metaClass directly with the
properties and methods we need to implement persistence. An alternative approach,
as we have learned, is that we could use an AST transformation to add the individual
methods to the Customer class at compile time.
A third and better approach would be to declare a trait for persistence, which could
have the additional persistence properties we need such as ID and VERSION and the
additional persistence methods such as save(), list(), and get(). This trait could
then be added to the Customer class via a Global AST transformation.
Grails uses the convention that all classes in the grails-app/domain folder are
considered to be domain classes that should be persistent. So, if we were to use the
build system to compile all classes in the domain folder in one compilation task, and
if we were to apply a Global AST transformation during this compilation, then we
could enhance all the domain classes as we pleased.