Grails – my domain class instance says its class is abstract!

November 18, 2013 at 09:56

I recently faced a weird problem when using Grails and a domain class hierarchy that contained abstract classes, let’s say:

abstract class A { ...}
abstract class B extends C { ...}
class C extends A { ...}
class D extends B { ...}

So the problem was that a certain instance of the class D, in a certain context (i.e. given the same instance, it didn’t show the problem always, but actually only when used in a certain gsp), was saying that its class was B (which is absurd, since B is abstract and therefore it can’t be anybody effective class!).

I found out that the instance was actually a Hibernate proxy, which shouldn’t be a problem if I accessed the class using the Grails domainClass attribute. But still was. Let’s put it in code:

void testThatTheEffectiveClassIsNotAbstract(Long id) {
   assert B.get(id).getClass() != B_$$_javassist_100
   assert B.get(id).domainClass.clazz != B
   Sql.newInstance(ctx.dataSource).eachRow("select class from a where id = ${id}") {
      it.class == D.name
   } 
}

So, this test was failing in a certain situation for only certain instances. WTF? Anyway, I’m sick of having problems with the whole Hibernate proxy thing and I couldn’t spend time figuring out the whole thing (and moreover, it was impossible for me to reproduce it in a test case), so I ended up adding the the following method to my (constantly growing) GrailsUtils.groovy class (although maybe I should rename it to GrailsHacks.groovy 🙁 ):

import java.lang.reflect.Modifier
import static org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil.unwrapIfProxy

static Class getDomainClassInstanceEffectiveClass(instance) {
   Class proxiedClass = instance.domainClass.clazz
   Modifier.isAbstract(proxiedClass.getModifiers()) ?
      unwrapIfProxy(instance).getClass() : proxiedClass
}

which actually got the correct class everytime. Surprising? I don’t know what to think anymore…