While "deep validation" currently isn't documented for the validate() and save() methods, it will be in future (the document states that the documentation has been missing, while being relevant for the complete 1.3.x tree). The documentation on these methods' deepValidate parameter then will state:
@deepValidate@ (optional) - Determines
whether associations of the domain
instance should also be validated,
i.e. whether validation cascades or
not. This is @true@ by default - set
to @false@ to disable cascading
validation.
Tests, however, show that "deep validation" is not performed in any of these cases:
- one-to-one associations
- one-to-many associations
- associated objects assigned using the matching setter
- associated objects assigned using the matching
addTo*(..) method, e.g., person.addToAddresses(..)
- using both the
validate() and save() methods,
- and also, using both methods with an explicit
deepValidate: true parameter
Similar findings have been published at another place, categorizing the "non-behavior" as a "known issue". My own, comprehensive, test cases can be downloaded from here.
The solution, finally, is to manually invoke validation on the child object:
class Person {
Address primaryAddress
static hasMany = [secondaryAddresses: Address]
static constraints = {
primaryAddress validator: {
it?.validate()
}
secondaryAddresses validator: {
it?.every { it?.validate() }
}
}
}