8

How can I unproxy a hibernate object, such that polymorphism would be supported?

Consider the following example. Classes A and B are two hibernate entities. B has two subtypes C and D.

List<A> resultSet = executeSomeHibernateQuery();
for(A nextA : resultSet) {
    for(B nextB : nextA.getBAssociations() {
        if(nextB instanceof C) {
            // do something for C
        } else if (nextB instanceof D) {
            // do something for D
        }
    }
}

This code fails to execute either the C or D block, since the B collection has been lazy loaded, and all instances of B are Hibernate proxies. I'd like a way to unproxy each instance.

Note: I realize the query can be optimized to eagerly fetch all B's. I'm looking for an alternative.

Peter Bratton
  • 6,024
  • 5
  • 35
  • 60
  • 1
    I know it's an old question, but as it appeared as first result in a google search, I'll have to comment here that if you have to use `instanceof`, then you're probably doing polymorphism wrong. – drigoangelo Aug 29 '14 at 12:42

3 Answers3

19

Here's our solution, added to our persistence utils:

public T unproxy(T proxied)
{
    T entity = proxied;
    if (entity instanceof HibernateProxy) {
        Hibernate.initialize(entity);
        entity = (T) ((HibernateProxy) entity)
                  .getHibernateLazyInitializer()
                  .getImplementation();
    }
    return entity;
}
Keppil
  • 43,696
  • 7
  • 86
  • 111
Peter Bratton
  • 6,024
  • 5
  • 35
  • 60
  • Is this solution working for you? I have implemented similar method and I still have got a `HibernateProxy` as a class of my object. Here is my question: http://stackoverflow.com/q/11518091/845220 – woyaru Jul 17 '12 at 09:54
  • 1
    This does not adress the problem of a `PersistentCollection`. Typically you could have a `List` that has actually been proxified as a `PersistentCollection`. If passed through this method, the test `entity instanceof HibernateProxy` would fail and the method would return without doing anything. A solution would be to also test `entity instanceof PersistentCollection`, use `Hibernate.initialize()` as well, then iterate and unproxy every object of the collection. More easy to describe than to implement though.. – Aldian Oct 25 '16 at 14:37
  • 2
    Note that you don't need to check that entity is not null (see http://stackoverflow.com/questions/2950319/is-null-check-needed-before-calling-instanceof) – laurent Oct 27 '16 at 16:17
11

Nowadays Hibernate has dedicated method for that: org.hibernate.Hibernate#unproxy(java.lang.Object)

Radek Postołowicz
  • 3,636
  • 2
  • 25
  • 40
2

The solution using the HibernateProxy and the getImplementationMethod is correct.

However, I assume you're running into this because your collection is defined as an interface, and hibernate is presenting proxies to the interface.

This leads to the design question, of why have the "if" with the "instanceof" instead of using a interface method to do what you need.

So your loop becomes:

for(B nextB : nextA.getBAssociations() {
    nextB.doSomething();
}

That way, hibernate would delegate the call to "doSomething()" to the actual implementation object, and you'd never know the difference.

Matt
  • 10,997
  • 2
  • 19
  • 32
  • Good points all, and our use of inheritance is probably less than ideal. In this particular case, we actually have other logic depending on the type of each item in the collection. So one thing we could have done is add isC() and isD() abstract methods, but that also felt a little a clunky. FWIW, our hierarchy works for most of our use cases, this is part of the 20%. – Peter Bratton Jun 27 '12 at 19:21