figure 1.
groovy:000> String.metaClass.doubleString = { -> delegate + delegate } ===> groovy.lang.ExpandoMetaClass$ExpandoMetaProperty@14a18d groovy:000> “ACM Queue”.doubleString() ===> ACM QueueACM Queue
figure 2.
using Annotations for oRm
using XmL for oRm
@Entity
class Customer {
…
@Id
@GeneratedValue
private long id;
@Version private long version ;
<hibernate-mapping default-access=“field”>
<class name=“Customer”>
<id name=“id”>
<generator class=“native” />
</id>
<version name=“version”/>
private String name;
<property name=“name”/>
@One ToMany private Set<Account> accounts; … }
<set name=“accounts”>
<key/>
<one-to-many class=“Account”/>
</set>
…
</class>
…
</hibernate-mapping>
Groovy provides a couple of different ways to add methods and properties to a class at runtime. The simplest approach is to define property Missing() or method Missing() 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 im-
plements the new method.
Groovy applications often use methodMissing() and ExpandoMetaClass together. The first time an undefined method is invoked, miss-ingMethod() defines the method using the ExpandoMetaClass. The next time around, the newly defined method is called directly, thereby bypassing the relatively expensive miss-ingMethod() 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.
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 Spring
16
have begun to adopt the concept. Today, developers expect modern Java EE
50 communicAtionS of the Acm | APriL 2009 | voL. 52 | no. 4
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 a handler class. Similarly, GORM has rules for defining which classes to persist and how to include defaults for column and table names. Because of CoC, a typical Grails application contains significantly less configuration code and metadata than an application using a traditional framework.
Now that we have looked at the key underpinnings of GORM, let’s learn how to use it.
A key part of using an ORM framework is specifying how the object model maps to the database. The developer must specify how classes map to tables, attributes map to columns, and relationships map to either foreign keys or join tables. This section looks at how this works using a traditional ORM framework and then how it is accomplished in Grails.
Mapping with XML and annotations. The persistent state of a Java class is either its fields or its properties. A field is the Java equivalent of an instance variable. A property is defined by getter and setter methods that follow the JavaBeans6 naming conventions. For example, getFoo() and setFoo() define the property called foo. The getter and setter methods often provide access to a field of the same name as the property, although they are not required to do so.
A Hibernate application can map the fields or properties of domain classes to the database schema using either XML or annotations. Figure 2 shows an annotation example on the left and an XML example on the right. Both examples persist the fields of the Customer class, but an application can persist properties either by annotating the getter methods or by omitting the default-access attribute from the XML document.
XML and annotations produce equivalent metadata. They both specify that the Customer class is persistent. They also specify that Hibernate should generate an object’s primary key using whatever mechanism is appropriate for the underlying database and store
References:
Archives