CHAPTER 3

Understanding Domain Classes

Object-oriented (OO) applications almost always involve a domain model representing the business entities that the application deals with. Our gTunes application will include a number of domain classes including Artist, Album, and Song. Each of these domain classes has properties associated with it, and you must map those properties to a database in order to persist instances of those classes.

Developers of object-oriented applications face some difficult problems in mapping objects to a relational database. This is not because relational databases are especially difficult to work with; the trouble is that you encounter an "impedance mismatch"3 between the object-oriented domain model and a relational database's table-centric view of data.

Fortunately, Grails does most of the hard work for you. Writing the domain model for a Grails application is significantly simpler than with many other frameworks. In this chapter, we are going to look at the fundamentals of a Grails domain model. In Chapter 10, we will cover more advanced features of the GORM tool.

Persisting Fields to the Database

By default, all the fields in a domain class are persisted to the database. For simple field types such as Strings and Integers, each field in the class will map to a column in the database. For complex properties, you might require multiple tables to persist all the data. The Song class from Chapter 2 contains two String properties and an Integer property. The table in the database will contain a separate column for each of those properties.

In MySql, that database table will look something like Listing 3-1.

Listing 3-1. The Song Table

+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version  | bigint(20)   | NO   |     | NULL    |                |
| artist   | varchar(255) | NO   |     | NULL    |                |
| duration | int(11)      | NO   |     | NULL    |                |
| title    | varchar(255) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+

Notice that the table includes not only a column for each of the properties in the domain class, but also an id column and a version column. The id is a unique identifier for a row and Grails uses the version column to implement optimistic locking4.

Listing 3-1 shows the default mapping. Grails provides a powerful DSL for expressing how a domain model maps to the database. Details about the mapping DSL appear later in this chapter in the "Customizing Your Database Mapping" section.

Validating Domain Classes

You'll probably encounter business rules that constrain the valid values of a particular property in a domain class. For example, a Person must never have an age that is less than zero. A credit-card number must adhere to an expected pattern. Rules like these should be expressed clearly, and in only one place. Luckily, Grails provides a powerful mechanism for expressing these rules.

A Grails domain class can express domain constraints simply by defining a public static property named constraints that has a closure as a value. Listing 3-2 shows a version of the Song class that has several constraints defined.

Listing 3-2. The Song Domain Class

class Song {     String title     String artist     Integer duration     static constraints = {         title(blank: false)         artist(blank: false)         duration(min: 1)     } }

The Song class in Listing 3-2 defines constraints for each of its persistent properties. The title and artist properties cannot be blank. The duration property must have a minimum value of 1. When constraints are defined, not every property necessarily needs to be constrained. The constraints closure can include constraints for a subset of properties in the class.

The validators used in Listing 3-2 are blank and min. Grails ships with a lot of standard validators that cover common scenarios (see Table 3-1).

Table 3-1. Standard Validators in Grails

Name Example Description
blank login(blank:false) Set to false if a string value cannot be blank
creditCard cardNumber(creditCard:true) Set to true if the value must be a credit-card number
email homeEmail(email:true) Set to true if the value must be an e-mail address
inList login(inList:['Joe', 'Fred']) Value must be contained within the given list
length login(length:5..15) Uses a range to restrict the length of a string or array
min duration(min:1) Sets the minimum value
minLength password(minLength:6) Sets the minimum length of a string or array property
minSize children(minSize:5) Sets the minimum size of a collection or number property
matches login(matches:/[a-zA-Z]/) Matches the supplied regular expression
max age(max:99) Sets the maximum value
maxLength login(maxLength:5) Sets the maximum length of a string or array property
maxSize children(maxSize:25) Sets the maximum size of a collection or number property
notEqual login(notEqual:'Bob') Must not equal the specified value
nullable age(nullable:false) Set to false if the property value cannot be null
range age(range:16..59) Set to a Groovy range of valid values
scale salary(scale:2) Set to the desired scale for floating-point numbers
size children(size:5..15) Uses a range to restrict the size of a collection or number
unique login(unique:true) Set to true if the property must be unique
url homePage(url:true) Set to true if a string value is a URL address

The constraints block in a domain class will help prevent invalid data from being saved to the database. The save() method on a domain object will automatically validate against the constraints before the data is written to the database. Data is not written to the database if validation fails. Listing 3-3 demonstrates how code can react to the return value of the save() method.

Listing 3-3. Validating a Song Object

// −68 is an invalid duration
def song = new Song(title:'The Rover',
                    artist:'Led Zeppelin',
                    duration:-68)
if(song.save()) {
    println "Song was created!"
} else {
    song.errors.allErrors.each { println it.defaultMessage }
}

An interesting aspect of Listing 3-3 is the usage of the errors property on domain classes. This property is an instance of the Spring Framework's org.springframework. validation.Errors interface, which allows advanced querying of validation errors. In Listing 3-3, when validation fails, the code generates a list of all the errors that occurred and prints them to stdout.

Some of the more useful methods in the Spring Errors interface are shown in Listing 3-4.

Listing 3-4. Methods in the Spring Errors Interface

package org.springframework.validation;
interface Errors {
     List getAllErrors();
     int getErrorCount();
     FieldError getFieldError(String fieldName);
     int getFieldErrorCount();
     List getFieldErrors(String fieldName);
     Object getObjectName();
     boolean hasErrors();
     boolean hasFieldErrors(String fieldName);
     // ...x remaining methods
}

Occasionally you'll find it useful to make changes to the domain model before committing to the save() method. In this case, Grails provides a validate() method, which returns a Boolean value to indicate whether validation was successful. The semantics are exactly the same as in the previous example with the save() method, except, of course, that the validate() method doesn't perform persistent calls.

If validation does fail, the application might want to make changes to the state of the domain object and make another attempt at validation. All domain objects have a method called clearErrors(), which will clear any errors left over from a previous validation attempt. Listing 3-5 demonstrates how code might react to the return value of the validate() method.

Listing 3-5. Validating a Song Object, Revisited

def song = new Song(title:'The Rover',
                    duration:339)
if(!song.validate()) {
    song.clearErrors()
    song.artist = 'Led Zeppelin'
    song.validate()
}

Using Custom Validators

Grails provides a wide array of built-in validators to handle many common scenarios. However, it is impossible to foresee every feasible domain model and every specific kind of validation that an application might need. Fortunately, Grails provides a mechanism that allows an application to express arbitrary validation rules (see Listing 3-6).

Listing 3-2. Constraining the Password Property in the User Domain Class

class User {
    static constraints = {
        password(unique:true, length:5..15, validator:{val, obj ->
            if(val?.equalsIgnoreCase(obj.firstName)) {
                return false
            }
        })
    }
}

The validator in Listing 3-6 will fail if the password is equal to the firstName property of the User class. The validator closure should return false if validation fails; otherwise it should return true. The first argument passed to the closure is the value of the property to be validated. The second argument passed to the closure is the object being validated. This second argument is often useful if validation requires the inspection of the object's other properties, as in Listing 3-6.

In addition, when you return false from a custom validator, an error code such as user.password.validator.error is produced. However, you can specify a custom error code by returning a String:

if(val?.equalsIgnoreCase(obj.firstName)) {
         return "password.cannot.be.firstname"
}

In this example, you can trigger a validation error simply by returning a String with the value password.cannot.be.firstname. You'll be learning more about error codes and how they relate to other parts of the application in later chapters. For now, let's move on to the topic of transient properties.

Understanding Transient Properties

By default, every property in a domain class is persisted to the database. For most properties, this is the right thing to do. However, occasionally a domain class will define properties that do not need to be persisted. Grails provides a simple mechanism for specifying which properties in a domain class should not be persisted. This mechanism is to define a public static property named transients and assign to that property a value that is a list of Strings. Those Strings represent the names of the class's properties, which should be treated as transient and not saved to the database (see Listing 3-7).

Listing 3-7. A Transient Property in the Company Domain Class

class Company {
    String name
    Integer numberOfEmployees
    BigDecimal salaryPaidYTD
    static transients = ['salaryPaidYTD']
}

In Listing 3-7, the salaryPaidYTD property has been flagged as transient and will not be saved to the database. Notice that the default generated schema for this domain class does not contain a column for the salaryPaidYTD property (see Listing 3-8). In other words, the company table does not contain a column for the transient property.

Listing 3-8. The Company Table

+---------------------+--------------+------+-----+---------+----------------+
| Field               | Type         | Null | Key | Default | Extra          |
+---------------------+--------------+------+-----+---------+----------------+
| id                  | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version             | bigint(20)   | NO   |     | NULL    |                |
| name                | varchar(255) | NO   |     | NULL    |                |
| number_of_employees | int(11)      | NO   |     | NULL    |                |
+---------------------+--------------+------+-----+---------+----------------+

Not all persistent properties necessarily correspond to a field in a domain class. For example, if a domain class has a method called getName() and a method called setName(), then that domain class has a persistent property called name. It doesn't matter that the class doesn't have a field called "name." Grails will handle that situation by creating the appropriate column in the database to store the value of the name property. But you can use the transients property to tell Grails not to do that if the property really should not be persisted, as in Listing 3-9.

Listing 3-2. A Transient Property in the Company Domain Class

class Company {
    BigDecimal cash
    BigDecimal receivables
    BigDecimal capital
    BigDecimal getNetWorth() {
        cash + receivables + capital
    }
    static transients = ['netWorth']
}

Customizing Your Database Mapping

As we have seen already, Grails does a good job of mapping your domain model to a relational database, without requiring any kind of mapping file. Many developer productivity gains that Grails offers arise from its Convention over Configuration (CoC) features. Whenever the conventions preferred by Grails are inconsistent with your requirements, Grails does a great job of providing a simple way for you to work with those scenarios. The Custom Database Mapping DSL in Grails falls in this category.

Grails provides an ORM DSL for expressing your domain mapping to help you deal with scenarios in which the Grails defaults will not work for you. A common use case for taking advantage of the ORM DSL is when a Grails application is being developed on top of an existing schema that is not entirely compatible with Grails' default domain-class mappings.

Consider a simple Person class (see Listing 3-10).

Listing 3-10. The Person Domain Class

class Person {
    String firstName
    String lastName
    Integer age
}

The default mapping for that class will correspond to a schema that looks like Listing 3-11.

Listing 3-12. The Default Person Table

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version    | bigint(20)   | NO   |     | NULL    |                |
| age        | int(11)      | NO   |     | NULL    |                |
| first_name | varchar(255) | NO   |     | NULL    |                |
| last_name  | varchar(255) | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+

That works perfectly if you have a greenfield application that doesn't need to map to an existing schema. If the application does need to map to an existing schema, the schema will probably not match up exactly to the Grails defaults. Imagine that a schema does exist, and that it looks something like Listing 3-12.

Listing 3-12. A Legacy Table Containing Person Data

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| person_id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| person_age        | int(11)      | NO   |     | NULL    |                |eee
| person_first_name | varchar(255) | NO   |     | NULL    |                |
| person_last_name  | varchar(255) | NO   |     | NULL    |                |
+-------------------+--------------+------+-----+---------+----------------+

Notice that the table contains no version column and all the column names are prefixed with person_. You'll find it straightforward to map to a schema like that using Grails' ORM DSL. But to take advantage of the ORM DSL, your domain class must declare a public property called mapping and assign a closure to the property (see Listing 3-13).

Listing 3-13. Custom Mapping for the Person Domain Class

class Person {
    String firstName
    String lastName
    Integer age
    static mapping = {
        id column:'person_id'
        firstName column:'person_first_name'
        lastName column:'person_last_name'
        age column:'person_age'
        version false
    }
}

The example in Listing 3-13 defines column names for each of the properties and turns off the version property, which Grails uses for optimistic locking. These are just a couple of the features that the ORM DSL supports.

The default table name for persisting instances of a Grails domain class is the name of the domain class. Person objects are stored in a person table and Company objects are stored in a company table. If Person objects need to be stored in a people table, the ORM DSL allows for that. Listing 3-14 includes the necessary mapping code to store Person instances in the people table.

Listing 3-14. A Custom Table Mapping for the Person Domain Class

class Person {
    String firstName
    String lastName
    Integer age
    static mapping = {
        table 'people'
    }
}

We'll cover custom database mapping in more detail in Chapter 17.

Building Relationships

Typically an application is not made up of a bunch of disconnected domain classes. More often, domain classes have relationships to one another. Of course, not every domain class has a direct relationship with every other domain class, but it is not common for a domain class to exist in total isolation with no relationship to any other domain class.

Grails provides support for several types of relationships between domain classes. In a one-to-one relationship (the simplest type), each member of the relationship has a reference to the other. The relationship represented in Listing 3-15 is a bidirectional relationship.

Listing 3-15. A One-to-One Relationship Between a Car and an Engine

class Car {
    Engine engine
}
class Engine {
    Car car
}

In this model, clearly a Car has one Engine and an Engine has one Car. The entities are peers in the relationship; there is no real "owner." Depending on your application requirements, this might not be exactly what you want. Often a relationship like this really does have an owning side. Perhaps an Engine belongs to a Car, but a Car does not belong to an Engine. Grails provides a mechanism for expressing a relationship like that, and Listing 3-16 demonstrates how to specify the owning side of it.

Listing 3-16. An Engine Belongs to a Car

class Car {
    Engine engine
}
class Engine {
    static belongsTo = [car:Car]
}

The value of the belongsTo property in the Engine class is a Map. The key in this map is "car" and the value associated with that key is the Car class. This property tells Grails that the Car is the owning side of this relationship and that an Engine "belongs to" its owning Car. The key in the map can be named anything—the name does not need to be the same as the owning-class name. However, naming the key that way almost always makes sense. That key represents the name of a property that will be added to the Engine class, as well as representing the reference back to the owner. The Engine class in Listing 3-16 has a property called car of type Car.

You might encounter situations where a relationship needs an owning side but the owned side of the relationship does not need a reference back to its owner. Grails supports this type of relationship using the same belongsTo property, except that the value is a Class reference instead of a Map. With the approach used in Listing 3-17, the Engine still belongs to its owning Car, but the Engine has no reference back to its Car.

Listing 3-17. An Engine Belongs to a Car But Has No Reference to Its Owner

class Engine {
    static belongsTo = Car
}

One of the implications of having the belongsTo property in place is that Grails will impose cascaded deletes. Grails knows that an Engine "belongs to" its owning Car, so any time a Car is deleted from the database, its Engine will be deleted as well.

One-to-many relationships are equally simple to represent in Grails domain classes. Our gTunes application will require several one-to-many relationships, including the relationship between an Artist and its Albums and between an Album and its Songs. You might say that an Artist has many Albums and an Album has many songs. That "has many" relationship is expressed in a domain class with the hasMany property (see Listing 3-18).

Listing 3-18. The hasMany Property

class Artist {
    String name
    static hasMany = [albums:Album]
}
class Album {
    String title

    static hasMany = [songs:Song]
    static belongsTo = [artist:Artist]
}

class Song {
    String title
    Integer duration

    static belongsTo = Album
}

In Listing 3-18, an Artist has many Albums and an Album belongs to its owning Artist. An Album also has a reference back to its owning Artist. An Album has many Songs and a Song belongs to its owning Album. However, a Song does not have a reference back to its owning Album.

The value of the hasMany property needs to be a Map. The keys in the map represent the names of collection properties that will be added to the domain class, and the values associated with the keys represent the types of objects that will be stored in the collection property. The Artist class has a domain property called albums that will be a collection of Album objects. The default collection type that Grails will use is a java.util.Set, which is an unordered collection. Where this is the desired behavior, you don't need to declare the property explicitly. Grails will inject the property for you. If you need the collection to be a List or a SortedSet, you must explicitly declare the property with the appropriate type, as shown in Listing 3-19.

Listing 3-19. The Album Class Has a SortedSet of Song Objects

class Album {
    String title
    static hasMany = [songs:Song]
    static belongsTo = [artist:Artist]
    SortedSet songs
}

Note For this to work, the Song class must implement the Comparable interface. This requirement isn't specific to Grails; it's how standard SortedSet collections work in Java.


A domain class might represent the owning side of numerous one-to-many relationships. The Map associated with the hasMany property might have any number of entries in it, each entry representing another one-to-many-relationship. For example, if an Artist has many Albums but also has many Instruments, you could represent that by adding another entry to the hasMany property in the Artist class, as shown in Listing 3-20.

Listing 3-20. Multiple Entries in the hasMany Map

class Artist {
    String name
    static hasMany = [albums:Album, instruments:Instrument]
}

Extending Classes with Inheritance

Grails domain classes can extend other Grails domain classes. This inheritance tree might be arbitrarily deep, but a good domain model will seldom involve more than one or two levels of inheritance.

The syntax for declaring that a Grails domain class extends from another domain class is standard Groovy inheritance syntax, as shown in Listing 3-21.

Listing 3-21. Extending the Person Class

class Person {
    String firstName
    String lastName
    Integer age
}
class Employee extends Person {
    String employeeNumber
    String companyName
}
class Player extends Person {
    String teamName
}

How should these classes map to the database? Should there be separate tables for each of these domain classes? Should there be one table for all types of Person objects? Grails provides support for both of those solutions. If all Person objects—including Players and Employeesare to be stored in the same table, this approach is known as a table-per-hierarchy mapping. That is, a table will be created for each inheritance hierarchy (see Listing 3-22). Grails imposes table-per-hierarchy mapping as the default for an inheritance relationship.

Listing 3-22. The Person Table Representing a Table-Per-Hierarchy Mapping

+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version         | bigint(20)   | NO   |     | NULL    |                |
| age             | int(11)      | NO   |     | NULL    |                |
| first_name      | varchar(255) | NO   |     | NULL    |                |
| last_name       | varchar(255) | NO   |     | NULL    |                |
| class           | varchar(255) | NO   |     | NULL    |                |
| company_name    | varchar(255) | YES  |     | NULL    |                |
| employee_number | varchar(255) | YES  |     | NULL    |                |
| team_name       | varchar(255) | YES  |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

Notice that Listing 3-22 includes columns for all the attributes in the Person class along with columns for all the attributes in all the subclasses. In addition, the table includes a discriminator column called class. Because this table will house all kinds of Person objects, the discriminator column is required to represent what specific type of Person is represented in any given row. The application should never need to interrogate this column directly, but the column is critical for Grails to do its work.

The other type of inheritance mapping is known as table-per-subclass (see Listing 3-23).

Listing 3-23. Table-Per-Subclass Mapping

class Person {
    String firstName
    String lastName
    Integer age
    static mapping = {
        tablePerHierarchy false
    }
}

Table-per-subclass mapping results in a separate table for each subclass in an inheritance hierarchy (see Listing 3-24). To take advantage of a table-per-subclass mapping, the parent class must use the ORM DSL to turn off the default table-per-hierarchy mapping.

Listing 3-24. The Person, Employee, and Player Tables with Table-Per-Subclass Mapping

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version    | bigint(20)   | NO   |     | NULL    |                |
| age        | int(11)      | NO   |     | NULL    |                |
| first_name | varchar(255) | NO   |     | NULL    |                |
| last_name  | varchar(255) | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
+-----------------+--------------+------+-----+---------+-------+
| Field           | Type         | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| id              | bigint(20)   | NO   | PRI | NULL    |       |
| company_name    | varchar(255) | YES  |     | NULL    |       |
| employee_number | varchar(255) | YES  |     | NULL    |       |
+-----------------+--------------+------+-----+---------+-------+
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| id        | bigint(20)   | NO   | PRI | NULL    |       |
| team_name | varchar(255) | YES  |     | NULL    |       |
+-----------+--------------+------+-----+---------+-------+

Which of these mappings should you use? The answer depends on several factors. One of the consequences of the table-per-hierarchy approach is that none of the subclasses can have nonnullable properties, but because no joins are being executed, queries will perform better. This is because all the subclasses share a table that includes columns for all the properties in all the subclasses. When a Player is saved to the person table, the company_name column would be left null because players don't have a company name. Likewise, when an Employee is saved to the player table, the team_name column would be left null. One of the consequences of using the table-per-subclass approach is that you must pay a performance penalty when retrieving instances of the subclasses because database joins must be executed to pull together all the data necessary to construct an instance.

Grails lets you choose the approach that makes the most sense for your application. Consider your application requirements and typical query use cases. These should help you decide which mapping strategy is right for any particular inheritance relationship. Note that you don't need to apply the same mapping strategy across the entire application. There's nothing wrong with implementing one inheritance relationship using table-per-subclass mapping because you must support nonnullable properties, and implementing some other unrelated inheritance relationship using table-per-hierarchy mapping for performance reasons.

Embedding Objects

Grails supports the notion of composition, which you can think of as a stronger form of relationship. With that kind of relationship, it often makes sense to embed the "child" inline where the "parent" is stored. Consider a simple relationship between a Car and an Engine. If that relationship were implemented with composition, the Engine would really belong to the Car. One consequence of that: If a Car were deleted, its Engine would be deleted with it (see Listing 3-25).

Listing 3-25. A Composition Relationship Between the Car and Engine Domain Classes

class Car {
    String make
    String model
    Engine engine
}
class Engine {
    String manufacturer
    Integer numberOfCylinders
}

Normally Car objects and Engine objects would be stored in separate tables, and you'd use a foreign key to relate the tables to each other (see Listings 3-26 and 3-27).

Listing 3-26. The Car Table

+-----------+--------------+------+-----+---------+---------------+
| Field     | Type         | Null | Key | Default | Extra         |
+-----------+--------------+------+-----+---------+---------------+
| id        | bigint(20)   | NO   | PRI | NULL    | auto_increment|
| version   | bigint(20)   | NO   |     | NULL    |               |
| engine_id | bigint(20)   | NO   | MUL | NULL    |               |
| make      | varchar(255) | NO   |     | NULL    |               |
| model     | varchar(255) | NO   |     | NULL    |               |
+-----------+--------------+------+-----+---------+---------------+

Listing 3-27. The Engine Table

+---------------------+--------------+------+-----+---------+----------------+
| Field               | Type         | Null | Key | Default | Extra          |
+---------------------+--------------+------+-----+---------+----------------+
| id                  | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| version             | bigint(20)   | NO   |     | NULL    |                |
| manufacturer        | varchar(255) | NO   |     | NULL    |                |
| number_of_cylinders | int(11)      | NO   |     | NULL    |                |
+---------------------+--------------+------+-----+---------+----------------+

To treat the relationship between those classes as composition, the Car class must instruct Grails to "embed" the Engine in the Car. You do this by defining a public static property called embedded in the Car class and assign that property a list of strings that contains the names of all the embedded properties (see Listing 3-28).

Listing 3-28. Embedding the Engine in a Car

class Car {
    String make
    String model
    Engine engine
    static embedded = ['engine']
}

With that embedded property in place, Grails knows that the Engine property of a Car object should be embedded in the same table with the Car object. The car table will now look like Listing 3-29.

Listing 3-29. The Car Table with the Engine Attributes Embedded

+----------------------------+--------------+------+-----+---------+---------------+
| Field                      | Type         | Null | Key | Default | Extra         |
+----------------------------+--------------+------+-----+---------+---------------+
| id                         | bigint(20)   | NO   | PRI | NULL    | auto_increment|
| version                    | bigint(20)   | NO   |     | NULL    |               |
| engine_manufacturer        | varchar(255) | NO   |     | NULL    |               |
| engine_number_of_cylinders | int(11)      | NO   |     | NULL    |               |
| make                       | varchar(255) | NO   |     | NULL    |               |
| model                      | varchar(255) | NO   |     | NULL    |               |
+----------------------------+--------------+------+-----+---------+---------------+

Testing Domain Classes

Automated tests can be an important part of building complex applications and confirming that the system behaves as intended. In particular, testing is an important part of building complex systems with a dynamic language like Groovy. With dynamic languages, developers don't get the same kinds of feedback from the compiler that they might get if they were working with a statically typed language like Java.

For example, in Java if you make a typo in a method invocation, the compiler will let you know that you have made the mistake. The compiler cannot flag that same error when you use Groovy because of the language's dynamic nature and its runtime. With a dynamic language like Groovy, many things are not known until runtime. You must execute the code to learn whether it's correct. Executing the code from automated tests is an excellent way to help ensure that the code is doing what it is supposed to do.

Grails offers first-class support for testing many aspects of your application. In this section, we will look at testing domain classes.

Grails directly supports two kinds of tests: unit tests and integration tests. Unit tests reside at the top of the project in the test/unit/ directory, and integration tests reside in the test/ integration/ directory. You must understand the difference between unit tests and integration tests. Many dynamic things happen when a Grails application starts up. One of the things Grails does at startup is augment domain classes with a lot of dynamic methods such as validate() and save(). When you run integration tests, all of that dynamic behavior is available, so a test can invoke the validate() or save() method on a domain object even though these methods do not appear in the domain-class source code.

When you run unit tests, however, that full dynamic environment is not fired up, so methods such as validate() and save() are not available. Starting up the whole dynamic environment comes at a cost. For this reason, you should run tests that rely on the full Grails runtime environment only as integration tests.

That said, Grails provides advanced mocking capabilities that let you mock the behavior of these methods in a unit test. If you create a domain class using the create-domain-class command, Grails will create a unit test automatically. If you execute grails create-domain-class Artist (see Listing 3-30), Grails will create grails-app/domain/Artist.groovy and test/ unit/ArtistTests.groovy. Grails is encouraging you to do the right thing—to write tests for your domain classes. If you don't use the create-domain-class command to create your domain class, you can create the test on your own. Make sure to put the test in the appropriate directory.

Listing 3-30. The Unit Test for the Artist Class, Generated Automatically

class ArtistTests extends grails.test.GrailsUnitTestCase {
    void testSomething() {
    }
}

As you can see from Listing 3-30, the default unit-test template extends from the parent class grails.test.GrailsUnitTestCase. The GrailsTestUnitCase class is a test harness that provides a range of utility methods to mock the behavior of a Grails application. To run the test, invoke the test-app Grails command from the command line. The test-app command will run all the unit tests and integration tests that are part of the project. To run a specific test, invoke the test-app target with an argument that represents the name of the test to run. The name of the test to run should be the test-case name without the "Tests" suffix. For example, execute grails test-app Artist to run the ArtistTests test case.

The test-app target will not only run the tests, but also generate a report including the status of all the tests that were run. This report is a standard JUnit test report, which Java developers know very well. An HTML version of the report will be generated under the project root at test/reports/html/index.html.

The Song class in the gTunes application has title and duration properties (see Listing 3-31).

Listing 3-31. The Song Domain Class

class Song {
    String title
    Integer duration
}

The application should consider a nonpositive duration to be an invalid value. The type of the property is java.lang.Integer, whose valid values include the full range of values in a 32-bit signed int, including zero and a lot of negative numbers. The application should include a unit test like that shown in Listing 3-32, which asserts that the system should not accept nonpositive durations.

Listing 3-32. The Song Unit Test

class SongTests extends grails.test.GrailsUnitTestCase {
    void testMinimumDuration() {
       // mock the behavior of the Song domain class
       mockDomain(Song)
       // create a Song with an invalid duration
       def song = new Song(duration: 0)
       // make sure that validation fails
       assertFalse 'validation should have failed', song.validate()
       // make sure that validation failed for the expected reason
       assertEquals "min", song.errors.duration
    }
}

Notice the call to the mockDomain(Class) method in Listing 3-32 that provides a mock implementation of the validate() method on the Song domain class. Executing grails test-app Song will run the test. The test should fail initially because it contains no code specifying that 0 is an invalid value for the duration property. Starting with a failing test like this subscribes to the ideas of Test-Driven Development (TDD). The test represents required behavior, and it will "drive" the implementation to satisfy the requirement.

Adding a simple domain constraint to the Song class as shown in Listing 3-33 should satisfy the test.

Listing 3-33. The Song Domain Class with a Constraint

class Song {
    String title
    Integer duration
    static constraints = {
        duration(min:1)
    }
}

With that constraint in place, the unit test should pass. The domain class is written to satisfy the requirements expressed in the test. Specifically, the domain class considers any nonpositive value for duration to be invalid.

Summary

This chapter covered quite a bit of ground by introducing the fundamentals of Grails domain classes. Grails provides slick solutions to common problems like validating domain classes and mapping to a relational database. The GORM technology is responsible for much of that capability. We'll explore GORM in more detail in later chapters, including Chapters 10 and 17.



3. Scott W. Ambler, "The Object-Relational Impedance Mismatch," http://www.agiledata.org/essays/impedanceMismatch.html, 2006.

4. Wikipedia, "Optimistic concurrency control," http://en.wikipedia.org/wiki/Optimistic_concurrency_control.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset