Using ORM tools allow you to map the data to a database independently of how your object model looks. Grails supports one-to-many and one-to-one relationships if you want to have the data in different table. But what about when you want to map a single table to multiple objects? In Grails a has a relationship where all the data is stored in a single table is defined by using the embedded syntax. (This creates a component in the Hibernate mapping world.)
An example of using the embedded syntax to create a compositional relationship:
This is all great, but... When you attempt to databind against the Person model including Address properties, you end up with an exception:
2009-04-17 20:36:10,058 [[email protected]] ERROR errors.GrailsExceptionResolver - java.lang.ClassCastException: Address$__clinit__closure1 org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.ClassCastException: Address$__clinit__closure1 at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:92) at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1061) at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:910) at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:892) at groovy.lang.Closure.call(Closure.java:279) at groovy.lang.Closure.call(Closure.java:274)
It ends up there is a bug in Grails versions 1.0.4, 1.0.5 and 1.1 that is causing this. That bug is related to the constraints on the embedded class, in this case the Address class. Removing the constraints allows the object to be properly databound, with the obvious downside of lacking constraints.
I have filed a bug about this: GRAILS-4446. So hopefully it will be fixed soon. Hopefully if other people are having this problem they will help them out.
Update: There is another workaround which is to declare the embedded class in its own file which makes it a first-class Domain object. When that's done the constraints work as expected. The downside is that this means that a table will be created for the embedded domain class (and never used).