Announcing Grails Constraints Custom Domain Constraint Plugin

by Geoff Lane on October 26th, 2009

I’ve released my first public Grails Plugin today.

The Grails Constraint plugin gives you the ability to create custom Constraints that you can apply to your Domain classes to validate them. These are applied and act just like the built in Domain class constraints.

Why would you want this?

Grails provides two generic, catch-all Constraints in the core application:

  • validator – a generic closure mechanism for validation
  • matches – a regular expression mechanism

While those work, I find myself often wanting to use the same Constraints on multiple Domain classes (think Social Security Number, Phone Number, Zipcode, etc.) and I don’t like to repeat those regular expressions or validations all over the place.

What does this plugin do?

With the Grails Constraints plugin, you can write a custom Constraint class, drop it in /grails-app/utils/ and it will automatically be available to all of your domain classes.

Example

I create a new constrain by hand in /grails-app/utils/ComparisonConstraint.groovy. (You can also use the provided create-constraint script like grails create-constraint com.foo.MyConstraint)

class ComparisonConstraint {
 
    static name = "compareTo"
    static expectsParams = true
 
    def validate = { val, target ->
        def compareVal = target."$params"
        if (null == val || null == compareVal)
            return false
 
        return val.compareTo(compareVal) == 0
    }
}

Then you can apply your constraint to your Domain class:

class Login {
    String password
    String confirm
 
    static constraints = {
        password(compareTo: 'confirm')
    }
}

See Grails Custom Constraints Plugin for the full documentation on what all of the above means and the source code.

From → Code, Groovy

5 Comments
  1. Chii permalink

    +1 that is freaking awesome!

  2. mcv permalink

    I love this idea, but unfortunately, it behaves very erritically for me. Sometimes the validate closure gets called, sometimes it doesn’t, and there doesn’t seem to be any predictability in whether it gets called or not. Sometimes I’ve got it working, then kill the server, clean, restart, and then it fails (as in: the validate closure doesn’t get called).

    And it fails silently. It doesn’t complain that it can’t find the constrain class or anything like that, it just ignores it completely.

    It’s a real shame, because this plugin promises to do exactly what I need: make lots of custom validators easy to maintain and re-use.

    Is there any way I can help you fix this?

  3. @mcv, the most help would be to make a repeatable test case. If that’s not possible, do you mind sending me some of your Constraints so I can take a look at them?

  4. @Geoff
    Is this plugin still relevant with the release of Grails 1.2 that allows re-use of named constraint (it I am correct)?

  5. @fabien7474,
    Yes, I think it’s still relevant with Grails 1.2. Grails 1.2 allows you to create named constraints based on the existing constraints and then apply them to multiple classes. e.g.:

    grails.gorm.default.constraints = {
       myConstraints(nullable:true, blank:false, size:1..20)
    }
     
    static constraints = {
      myProperty shared:"myConstraints"
    }

    The constraints plugin allows you to create fundamentally new constraints. It also allows you to supply parameters to those custom constraints to change the behavior, something that the default constraints setup doesn’t do. This is important, for example, in a constraint that relies on the value of another property (see the CompareToConstraint example above). In that scenario you need to configure the constraint by passing the name of that other property.

    The new feature in Grails 1.2 is really about applying defaults and a way of clustering common constraints together. That’s great for what it is. The plugin is about creating fundamentally new constraints.

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS