I did some experiments, and here are some conclusions. This is all empirical research; please correct me if I am wrong.
First of all, it's easy to see when the constraints call is computed. Just add debug output:
static constraints = { println "Entering constraints..." name(blank:false, maxSize:50) // etc. println "Exiting constraints..." }
You will see that it is really evaluated when the application starts. For some reason, I do not understand, this is usually evaluated twice. Also note that constraints marked as static, so it has nothing to do with specific instances of class Race .
Further, it is easy to find out that name , startDate , etc., are indeed functional calls. Just try specifying restrictions on a nonexistent property:
static constraints = { no_such_thing(nullable:true) }
You cannot do it! Result:
Error Error executing script Shell: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManagerPostProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.codehaus.groovy.runtime.InvokerInvocationException: groovy.lang.MissingMethodException: No signature of method: Race.no_such_thing() is applicable for argument types: (java.util.LinkedHashMap) values: [[nullable:true]]
Of course, you never defined all of these methods, i.e. name , startDate , etc., and you have not yet inherited your domain class from anything else. But since Grails recognizes it as a domain class, it uses the power of Groovy to inject methods into an object, bypassing the limitations of traditional object-oriented programming.
Now it does not literally introduce methods into the object. You can easily check:
static constraints = { println Race.metaClass.methods*.name.sort().unique()
You will not see any methods called name , startDate , etc., and you cannot println Race.name inside the constraints { } block. I think Groovy intercepts calls to nonexistent methods Race.name , Race.startDate , etc., and writes this restriction information elsewhere for future use. If you want, try to apply methods, for example, for example. Race.name ; I think I managed to prevent the restrictions from working, but I cannot reproduce it.
Regarding the question of what is being assessed when, I think we have some confusion here about Groovy closing. Take a look at
startDate(validator: {return (it > new Date())})
Here we have a closure: {return (it > new Date())} . If Groovy was a pure interpreted language such as Python, it would just save that literal code and reinterpret it with any call. This way you will also get the latest date. I assume that Groovy mimics this behavior, even if the code seems to be compiled: it will transfer this code to the closure object and will call this object every time a check is requested. This closure will be saved somewhere ; presumably in the same place where all other restrictions are stored. The confusion arises from the nature of closures: if you store 3 , it will always remain 3 ; if you store a closure (function), it can evaluate different results in different cases.
To repeat, code
{return (it > new Date())}
Not “running” or “evaluating” when the application starts; It is just kept for future use. You can easily check this:
static constraints = { startDate(validator: {println "Validating startDate..."}) }
Then run grails shell and
groovy> (new Race()).validate()