Fork me on GitHub

29 Jun 2010

Acyclic relationship validation in Grails

A common domain class use-case is for a self-referential relationship that must not be circular (a directed acyclic graph). For example, a Person class may have a parent property that is a many-to-one relationship with another Person instance. However a given Person cannot be his own parent or ancestor.

We're using just such a relationship for trees of pages that inherit certain characteristics from their ancestors. In order to validate that our users aren't setting up circular references I implemented the following constraint:Then I just needed to register my new constraint by adding ConstrainedProperty.registerNewConstraint(AcyclicConstraint.NAME, AcyclicConstraint) to grails-app/conf/spring/resources.groovy. Using the constraint is as simple as this:
class Person {

    String name
    Person parent

    static constraints = {
        parent acyclic: true
    }
}
The constraint can be mixed with others such as nullable: true. The really nice thing is that the constraint implementation doesn't reference any of my domain classes directly, meaning it can be re-used in any other domain class.

When you're using similar validation logic in multiple classes defining a constraint like this is a much better option than using a validator closure and like many things in Grails it turns out to be pretty easy to implement.

24 Jun 2010

Defaulting Joda Time Hibernate Types with Grails

Grails 1.2 added the ability to define default Hibernate mappings that apply to all GORM classes. It turns out this is incredibly useful if you're using Joda-Time types instead of java.util.Date in your domain objects. Previously you had to specify the Hibernate user type for every single field, like this:
import org.joda.time.*
import org.joda.time.contrib.hibernate.*

DateTime dateCreated
DateTime lastUpdated
LocalDate birthday

static mapping = {
    dateCreated type: PersistentDateTime
    lastUpdated type: PersistentDateTime
    birthday type: PersistentLocalDate
}
Now you can just add this to your Config.groovy once and do away with the type mappings in the individual classes:
grails.gorm.default.mapping = {
    "user-type" type: PersistentDateTime, class: DateTime
    "user-type" type: PersistentLocalDate, class: LocalDate
}
Correction: I had previously posted that the method call in the default mapping DSL could be anything, but on further investigation it turns out it has to be user-type. Apologies for the error.

I'll look into the possibility of the Joda-Time plugin doing this itself to make things even easier.

15 Jun 2010

Export Selenium IDE scripts for Grails

Thanks to the documentation provided on Adam Goucher's blog I've created a simple Firefox plugin that extends the Selenium IDE and adds formatters that allow you to export a script as a Grails Selenium RC test case. You have the option of JUnit 3 (extends GroovyTestCase, uses assertEquals) or JUnit 4 (doesn't extend anything, uses annotations and assertThat) formats.

I think everything is working. There are some things I'd still like to do:
  • Custom commands are currently exported as commented out which they don't need to be given Grails Selenium RC test cases can call Javascript extension functions directly.
  • I haven't yet figured out how to output a command such as
    selenium.waitForAlertPresent()
    rather than
    selenium.waitFor {
        selenium.isAlertPresent()
    }

The Firefox plugin is available from Selenium HQ. You will need to have Selenium IDE installed for it to work, obviously. Once installed you should find options
  • Export Test Case As -> Grails Selenium RC (JUnit 3)
  • Export Test Case As -> Grails Selenium RC (JUnit 4)
have been added to Selenium IDE's File menu.

Whilst I would certainly not leave the exported test case as is it's a quick way to get started. From the exported script you can easily refactor out some page objects or helper methods.