Grails Upgrade 2.3 to 2.4: Validation Errors

Recently I have updated our Grails 2.3 based web application to Grails 2.4. Although the 2.3 release was working fine, one doesn’t want to fall too far behind. I know out of experience that this can happen very fast. If you wait too long, then at some point the migration to a newer version is almost like starting from scratch, instead of just updating a few lines of code to accommodate for deprecated APIs. The biggest problem I encountered going to version 2.4 was a behavioral change regarding the validation.
Validation is a very nice feature you get for free on domain classes and command objects and which you can enable on other classes using the grails.validation.Validateable annotation. Inside your class body you define a static constraints = {} closure where you list the constraints for the class’ properties. Objects that can be validated provide the validate() method that checks all of the current object’s property values against the constraints and either returns true or false, depending on whether all of the properties meet their constraints or at least one doesn’t. Domain classes are automatically validated when you call the save() method.

The problem I ran into had to do with two things:

  • Getter methods were suddenly treated as properties.
  • Change in behavior for default constraints.

I found the answers to my questions in this Nabble thread which I summarize below.

Getter Methods are Properties

You can define properties in multiple ways. The most common known one is to define a member variable:

class Fish {
    String name
}

Here my class Fish has a property name of type String. As we all know, the Groovy compiler will create the getter and setter methods for us. But, when you only create a getter method this is a property too.

@Validateable
class Fish {
    String name
    int getSize() {
        …
    }
}

This Fish now has two properties, name and size.

As the user Jeff Scott Brown-3 in the Nabble thread explains, a bug in versions before Grails 2.4 resulted in properties defined through getters to not be included in the validation process. In our case this resulted in unit and integration tests failing because some of our command objects defined getter methods (which were not used as properties but rather helper methods that compute a value) and with Grails 2.4 they were now part of the validation.

One solution to this problem can be to specify a nullable:true constraint like so:

@Validateable
class Fish {
    String name
    int getSize() {
        …
    }

static constraints = {
 size nullable: true
 }
}

Default Constraints

The second piece of the puzzle is how default constraints are enforced. In Grails 2.3, if you didn’t specify any constraint on a command object (or any other class), it defaulted to nullable:true. With Grails 2.4 the behavior changed to be consistent with domain classes which always default to nullable:false. This information can be found in the upgrade guide.

Together with getter methods now being properly processed during validation, this change resulted in a seemingly weird outcome. The values of properties that are not defined in the constraints closure are checked now and tests suddenly failed where they shouldn’t have. In our case it wasn’t because of the property value being null where it shouldn’t be, but rather because of an exception that was caused by trying to create a result from a null-value.

As is the case with the getter-constraints, you can work around this by simply adding a nullable:true constraint to your property. If you have a lot this can be a tedious task though. For that situation, the @Validateable annotation can be parameterized to make all properties default to nullable:true.

@Validateable(nullable=true)
class Fish {
    String name
    int getSize() {
        …
    }
}

Now all properties can be null unless specified otherwise.

This JIRA describes another bug fix around the nullable:true constraint. In Grails 2.4.3 it seems that even for nullable objects the value was fetched. If your getter methods perform expensive calculations this could essentially mean that time was being wasted. This issue was a result of the discussion in the Nabble thread.

The one good thing that came out of this was that many getters had been called while an object’s internal state was inconsistent with what was expected. This resulted in a few NullPointerExceptions during the tests. While this breaking change caused some headaches it also helped to find a few subtle bugs and potential problems.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.