When using the three parameter (value, object, errors) version of the validate closure, the underlying code assumes that all errors will be added to the errors object. In order to returning a string or list of strings representing a message key.
The behavior is the same if using Command Objects as well.
Here's a working example of the two-parameter validate closure:
class ObjectA {
ObjectB fieldB
ObjectC fieldC
static constraints = {
fieldC(nullable: true, validator: { value, object->
if (object.fieldB != ObjectB.SOMETHING && !value) {
return "default.null.message"
// You can also use the list style return (especially if you need to pass additional parameters used by the message)
//return ["default.null.message"]
}
})
}
}
And here is a working example of the three-parameter validate closure:
class ObjectA {
ObjectB fieldB
ObjectC fieldC
static constraints = {
fieldC(nullable: true, validator: { value, object, errors ->
if (object.fieldB != ObjectB.SOMETHING && !value) {
// When "errors" is passed into the closure, you must use it to signal error cases
errors.rejectValue("defaultBrand", "default.null.message", ["defaultBrand"] as Object[], "The field \"{0}\" cannot be null")
}
})
}
}