Adds custom validation to a field.


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

password1( validator: { val, obj ->['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 // 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:

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