(Quick Reference)



Adds custom validation to a field.


even( validator: {
   return (it % 2) == 0

password1( validator: { val, obj -> obj.properties['password2'] == val })

magicNumber( validator: someClosureWithTwoParameters)

// This one assumes you have an error message defined like: // classname.propertyName.custom.error=My error shows arguments {3} and {4} for value {0} otherProperty( validator: { return ['custom.error', arg1, arg2] } )

// The following example does not use custom validation. // A custom message may be defined in messages.properties: // user.login.blank=Please enter a login // which will be used instead of default.blank.message class User { String login static constraints = { login(blank:false) } }

// In the following example, custom validation is used: // user.login.validator.invalid=Please enter a login class User { String login static constraints = { login(validator: { return (it.length != 0) }) } }

// The following might define the error message as: // user.login.invalid.bountyhunter=Invalid bounty hunter ({2}) tried to log in. (Class name = {1}. Property name = {0}) class User { String login static constraints = { login(validator: { if (!it.startsWith('boba')) return ['invalid.bountyhunter'] }) } }


Set to a closure or block to use for custom validation. A single or no parameter block receives the value, a two-parameter block receives the value and object reference.

A three-parameter Closure receives the value, object reference and the errors object.

The closure can return:

  • null or true to indicate that the value is valid
  • false to indicate an invalid value and use the default message code
  • a string to indicate the error code to append to the "classname.propertName." string used to resolve the error message. If a field specific message cannot be resolved, the error code itself will be resolved allowing for global error messages.
  • a list containing a string as above, and then any number of arguments following it, which can be used as formatted message arguments indexed at 3 onwards. See grails-app/i18n/message.properties to see how the default error message codes use the arguments.

If the closure is a three-parameter closure the return value is ignored and the closure is expected to populate the errors object.

The closure also has access to the name of the field that the constraint applies to via propertyName:

myField(validator: { val, obj -> return propertyName == "myField" })

Error Code: className.propertyName.validator.error