Monday, June 29, 2009

Casting hibernate proxies to subclasses

For a hibernate entity with subclasses like the
following:

When retrieving all addresses, hibernate can return a list of proxies instead of the real addresses (something more about proxies). These proxies, subclass Address and not the HomeAddress or WorkAddress class that they could represent. This results in the following exception when casting to HomeAddress or WorkAddress:

java.lang.ClassCastException: package.Address_$$_javassist_36

The solution is to deproxy the classes before casting them as follows:
if (type instanceof HibernateProxy)
type = Address .class.cast(((HibernateProxy) type).getHibernateLazyInitializer().getImplementation());
else
type = Address .class.cast(type);
I ran into this problem when hibernate fetched a list of all rows of one table (some 25 records) and somehow manages to provide actual classes for a number of those and proxies for the rest. If somebody could explain me why it doesn't retrieve all classes (or all proxies), I would be very happy.

3 comments:

OndrejM said...

I found a solution to deproxy a class using standard Java and JPA API. Tested with hibernate, but does not require hibernate as a dependency and should work with all JPA providers.

Onle one reuiqrement - its necessary to modify parent class (Address) and add a simple helper method.

General idea: add helper method to parent class which returns itself. when method called on proxy, it will forward the call to real instance and return this real instance.

Implementation is a little bit more complex, as hibernate recognizes that proxied class returns itself and still returns proxy instead of real instance. Workaround is to wrap returned instance into a simple wrapper class, which has different class type than the real instance.

In code:

class Address {
public AddressWrapper getWrappedSelf() {
return new EntityWrapper(this);
}
...
}

class AddressWrapped {
private Address wrappedAddress;
...
}

To cast Address proxy to real subclass, use following:
Address address = dao.getSomeAddress(...);
Address deproxiedAddress = address.getWrappedSelf().getWrappedAddress();
if (deproxiedAddress instanceof WorkAddress) {
WorkAddress workAddress = (WorkAddress)deproxiedAddress;
}

Roshni Johnson said...

Hi,
Were you able to find why some objects are returned as classes and others as objects of hibernate proxies?

Garrick Co Ida said...

Amazing & Great informative blog,it gives very useful practical information to developer like me. Besides that Wisen has established as Best Hibernate Training in Chennai . or learn thru Online Training mode Hibernate Online Training | Java EE Online Training. Nowadays Hibernate ORM has tons of job opportunities on various vertical industry.

 
The opinions expressed in this blog are those of Jeroen Wyseur and may not reflect the opinion of his employer or any customer of said employer.