Ok. So the title tells you something, but it might not get you through this scratcher. Here’s the domain class that we’re working with:

package constrainme

class Book {

    String title
    String author

    static constraints = {
        title blank: false
        author blank: false
    }
}

 

Now let’s imagine we want to make sure those constraints are working properly…

package constrainme

import grails.test.mixin.*
import org.junit.*
import spock.lang.*

@TestFor(Book)
@Mock(Book)
class BookSpec extends Specification {

    def "A global GORM nullable overrides a local object blank constraint"() {

       given:
       Book book = new Book()
       mockForConstraintsTests(Book, [book])

       when:
       def isValid = book.validate()

       then:
       !isValid
       book.hasErrors()

    }
}

 

This test will fail. And this exact scenario owned most of my morning. You know that blank trumps nullable, so there’s no way I should be able to pass that blank object in there. Right? Wrong…

Little did you know, I was busy supplying some GORM defaults to the whole project. Normally all object properties are not null by default, but you can override that in Config.groovy by a little, well, config:

grails.gorm.default.constraints = {
    '*'(nullable: true)
}

You can read about the deets in the manual. But what about our blank scenario? This one had me stumped for ages, and I noticed that the Fields plugin had stopped marking up my blank:false fields as “required”, so I knew something was up on the Book instances themselves. Time to retreat to the Grails Console plugin and have a look at what was happening at runtime!

Screenshot of the scratching situation below…

So it seems my Title field is now constrained as….

[title:org.codehaus.groovy.grails.validation.ConstrainedProperty@1313c837
[class constrainme.Book,title,class java.lang.String,
{blank=org.codehaus.groovy.grails.validation.BlankConstraint@55aa7971[false], 
nullable=org.codehaus.groovy.grails.validation.NullableConstraint@2b0b15a7[true]}]

blank: false but nullable: true? Wat?!? Yes, well it seems like my Global constraint is kicking in. What if I take my GORM defaults block out and retest?

[title:org.codehaus.groovy.grails.validation.ConstrainedProperty@284dbb2f
[class constrainme.Book,title,class java.lang.String,
{blank=org.codehaus.groovy.grails.validation.BlankConstraint@7c2d0928[false], 
nullable=org.codehaus.groovy.grails.validation.NullableConstraint@70b460c8[false]}]

Ah. That’s better. And my test is Green again!

I’m not exactly sure if this behaviour is an issue, or just by design. But it’s making me think twice about changing GORM defaults globally, since it may well violate the principle of least surprise for the next guy coming along…

But a great brain workout for the morning!

(Oh, and if you’ve got some new guys on your team that are getting up to speed on Grails, send them our way since we’re now in MEAP for Grails in Action 2!)

Glen.