Hibernate, lazy loading and inheritance
By: gnoij, 8 March 2010A common problem with typecasting a lazy loaded entity to its child is a ClassCastException. This exception occurs because the dynamic created proxy implements the baseclass and has no knowledge about its subclasses.
Suppose we have a class B which extends A and a class C which has class A as a member as shown below.
The following test will fail with a ClassCastException on the last line.
The methods save(), clearSession() and retrieve() are just helper methods which implement the Hibernate session methods save(), clear() and get().
A search on the Internet shows a couple of solutions for this problem.
- Using interfaces as a proxy in the hibernate mappings. This will result in accessing the object through its interface only so all methods must be exposed in the interface. I don’t want to expose every public or protected method in the interface which are not intended for use by external parties.
- Using the Visitor Pattern to access the correct childclass. This means that users of these objects must write a lot of code just to use some getters. I don’t want to burden someone else with a local Hibernate problem.
- Using ((HibernateProxy)object).getHibernateLazyInitializer().getImplementation() whenever a typecast of an object to its child class is needed.
All of the solutions mentioned above are not suitable for me so I decided on another solution which is a variant of solution 3.
With a slight modification of the method getA() in class C, exposing the HibernateProxy is avoided.
Now the test completes without failure.
This has to be done for every getter which can return a lazy loaded proxy.
And if you (like me) don’t want Hibernate code in your domain model, you can move this code to the persistence layer and use dependency injection to use it.
It’s still not an elegant solution (IMHO there isn’t one), but its the best usable for me.

8 March 2010 om 2:08 pm
Might not be a very elegant solution, but it solves the problem.
One thing comes to mind when reading “done for every getter”: AOP!
You are probably able to do this by creating a pointcut on all domain-classes which adds this functionality to all getters. That way the implementation is transparant and can be switched off. Your domain objects won’t have a compile-time dependency to Hibernate.
Something like:
import org.hibernate.proxy.HibernateProxy;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* Aspect will automagically remove all the proxies from the Hibernate getters.
* WARNING: Written from the top of my head and absolutely not tested, correct nor run!
*/
@Aspect
public class HibernateDeProxyAspect {
@Around(“execution(* com.example.domain.get*(..))”)
public Object deProxy(ProceedingJoinPoint pjp) throws Throwable {
//Call the getter:
Object retVal = pjp.proceed();
//Now deproxy if needed:
if (object instanceof HibernateProxy) {
return ((HibernateProxy)object).getHibernateLazyInitializer().getImplementation();
}
}
}