Member Menu
 
 Monthly JBoss newsletter:
 
Java Persistence with Hibernate
CaveatEmptor

Proxy Visitor Pattern

Note: The explanation in the first paragraph is not entirely correct, better read the one in the "Performance" chapter of the reference documentation first.

Anyone using Hibernate for any length of time has no doubt run into the dreaded "proxy problem" when using polymorphic collections. In Hibernate, lazy loading of persistent relationships and collections is facilitated by proxies. For example, let's say you have a LooneyBin object that has a collection of Nutter objects that is lazily loaded. If you call looneyBin.getNutters(), Hibernate will only load the ID and version number of the Nutter objects, thus saving all the work of loading individual objects until later. You think you have all the related Nutter objects, but what you really have is a collection of proxies. The thinking is that if you have a collection of a few hundred items, chances are good that you'll only work with a few of them, so why go through the effort of instantiating all the objects. This can be a huge performance gain in certain situations.

Hibernate Proxies and Polymorphism

Proxies are created dynamically by subclassing your object at runtime. The subclass has all the methods of the parent, and when any of the methods are accessed, the proxy loads up the real object from the DB and calls the method for you. Very nice in simple cases with no object hierarchy. Typecasting and instanceof work perfectly on the proxy in this case since it is a direct subclass. But there's a big problem lurking that can cause no end of grief: Polymorphism. Let's say you have the following object hierarchy:

public class Politician {
  ...
}
public class Democrat extends Politician {
  public Intern getFavoriteIntern() { ... }
}
public class Republican extends Politician {
  public Lobbyist getGolfBuddy() { ... }
}

Now, let's say you've got a collection of lazy Politicians. Oh, I mean a lazy collection of Politicians. Let's also say that you want to extract all the Interns from the Democrats. Assuming you had an instance of a Congress object that has a related collection of politicians, you'd be tempted to do something like:

public List getInterns(Congress congress) {
  Collection lazyPoliticians = congress.loadPoliticians();
  ArrayList interns = new ArrayList();

  for (Iterator iter=lazyPoliticians.iterate(); iter.hasNext(); ) {
    Politician politician = (Politician)iter.next();
    if (politician instanceof Democrat) {
      interns.add(((Democrat)politician).getFavoriteIntern());
    }
  }
}

But guess what? Not only is this bad form (instanceof is the hallmark of bad design), this won't work if the collection is populated with lazy Hibernate proxies. The reason is that when Hibernate creates the proxies at runtime it creates proxies that descend from Politician, not from each of the individual subclasses. That means that typecasts and instanceof operations will not work. Some would argue (myself included) that this sucks and breaks a fundamental aspect of the Java language. Whether you agree with this or not, you do have to agree that code constructs like:

for (Iterator iter=lazyPoliticians.iterate(); iter.hasNext(); ) {
  Politician politician = (Politician)iter.next();
  if (politician instanceof Democrat) {
    interns.add(((Democrat)politician).getFavoriteIntern());
  } else if (politician instanceof Republican) {
    lobbyists.add(((Republican)politician).getGolfBuddy());
  } else if (politician instanceof Libertarian) {
    wwf.giveBack(politician);
  }
}

are not only ugly and unmaintainable, but are fragile and easy to screw up when the hierarchy changes. Plus, more to the point, they don't work with Hibernate lazy proxies. You can just plan on ClasCastException(s). But don't worry, there's an elegant OO way to solve it. The visitor pattern.

The Visitor Pattern

The Visitor pattern is a "Gang of Four" design pattern that allows you to manipulate a collection of polymorphic objects without all the messy typecasts and instanceof operations. It can also be used to "visit" a single object as well, allowing you to adapt the object in various ways. Here's how it works in code:

public interface PoliticianVisitor {
  public void visit(Democrat dem);
  public void visit(Republican rep);
  public void visit(Libertarian lib);
}
public class Politician {
  public void accept(PoliticianVisitor visitor) {
    // do nothing
  }
}
public class Democrat {
  public void accept(PoliticianVisitor visitor) {
    visitor.visit(this);
  }
}

Notice that we didn't have to make Republican override the accept() method? If the subclass doesn't need it, you can just ignore it. Now, I don't like having to override all the methods of an iterface every time I want to use it, so I like to have an adapter:

public class PoliticianVisitorAdapter implements PoliticianVisitor {
  public void visit (Democrat dem) { // do nothing }
  public void visit (Republican rep) { // do nothing }
  public void visit (Libertarian lib) { // do nothing }
}

And, here's our same code to iterate the list of politicians and extract all the interns from the Democrat objects in the collection:

public List getInterns(Congress congress) {
  Collection lazyPoliticians = congress.loadPoliticians();
  final ArrayList interns = new ArrayList();

  PoliticalVisitor extractIntern = new PoliticalVisitorAdapter() {
    public void visit(Democrat democrat) {
      interns.add(democrat.getFavoriteIntern());
    }
  }

  for (Iterator iter=lazyPoliticians.iterate(); iter.hasNext(); ) {
    Politician politician = (Politician)iter.next();
    politician.accept(extractIntern);
  }
}

Notice the use of an annonymous inner class? You don't have to do it that way, but you can. Get jiggy with it and you'll find all sorts of creative ways to use this pattern. For example, you could create a visitor that manipulates both Republicans and Democrats at the same time, all without a single instanceof. Better yet, it will penetrate the Hibernate proxy and actually execute within the real object.

Visiting a Single Proxied Object

Sometimes it's helpful to be able to work with a single object and "introspect" it in some way. For example if you're creating a Tapestry page that dynamically changes form fields depending on the type of object. Not that it's good form, but you can create a visitor like:

public class PoliticianViewHelper extends PoliticianVisitorAdapter {
  private Democrat democrat;
  public PageVisitor(Politiican politician) {
    politician.accept(this);
  }
  public void visit(Democrat democrat) {

    this.democrat = democrat;
  }
  public boolean isDemocrat() {
    return this.democrat != null;
  }
  public Democrat getDemocrat() {
    return this.democrat;
  }
}

// and on the page...
...
public PoliticianViewHelper getPoliticianHelper() {
  return new PoliticianViewHelper(getPolitician());
}

// and in your Tapestry page...
<!-- Only show interns for democrats -->
<span jwcid="@Conditional" condition="ognl:politicianHelper.democrat">
  <span jwcid="@Insert" value="ognl:politicianHelper.favoriteIntern.name"/>
</span>;

// or, in JSP EL //
<!-- Only show interns for democrats -->
<c:if test="${politicianHelper.democrat}">
  ${politicianHelper.favoriteIntern.name}
</c:if>

The view (Tapestry or JSP page) is able, in a Hibernate proxy-safe way, to introspect the objects without the nasty instanceof and typecast code. You can also see how the code could be extended to allow the page to dynamically respond to different types of politicians - you'd just add PoliticianViewHelper.isRepublican() and .getGolfBuddy() methods.

As you can see the Visitor pattern is an effective OOP club to knock some sense into Hibernate proxies.

Kurtis Williams

http://www.jroller.com/page/cardsharp


  NEW COMMENT

typo fix 06 Jul 2005, 14:04 zdila
Excellent! Thanks. 
 
Just apply this patch to the last sample code: 
 
PoliticianViewHelper extends PoliticianVisitorAdapter { 
  private Democrat democrat; 
-  public PageVisitor 
+  public PoliticianViewHelper  
 
Martin
 
Identity test fails? 01 Aug 2005, 08:21 greyfairer
I wrote similar code, but found weird behaviour when running JUnit tests 
on it.  I posted a question on the user forum, http://forum.hibernate.
org/viewtopic.php?t=945748.

Basically,backporting to your code:
 
Democrat proxy = session.load(Democrat.class, id);
Democrat visited = new PoliticianViewHelper(proxy).getDemocrat();
assertNotNull(visited); //ok
assertEquals(id, visited.id); //ok
assertSame(proxy, visited; //FAILS

It turns out that in the invocation of the accept() method, the 'this' 
pointer does not point to the proxy instance, but to a real instance of 
the Democrat class.

The Visitor pattern as you described is still very valuable, off course, 
but this one surprised me.
 
Another approach? 04 Nov 2005, 15:52 eraymond
Is there a way to indicate in the mapping that the "list" of 
politicians is lazy, but the elements of the list are not lazy?  The
idea would be that if you loaded an object which contained such a list,
it would not be loaded until you accessed it.  But as soon as you
accessed it, the list would immediately fetch all the members ..
presumably getting the proxy to be the proper subclass 9and avoiding the
problem).

In many cases the performance would be as good or better than a lazy
collection of lazy politicians (which I think describes the example in
the article above.)

P.S.  It feels *very* odd for the perstance framework to be driving
structural changes to the users java code (e.g., use this design pattern
to avoid this error from a library).
 
another approach to polymorphism in hibernate 28 Mar 2006, 08:05 sebster
POST QUESTIONS ON THE FORUM! COMMENTS HERE SHOULD ADD VALUE TO THE
PAGE!I have a different solution which also works (and also has its
drawbacks). What I did is to let the base class (Politician) have two
methods:

    public boolean instanceOf(Class<?> otherClass) {
	return otherClass.isAssignableFrom(getPoliticianClass());
    }

    public Class<?> getPoliticianClass() {
        return Politician.class;
    }

Next I override the getPoliticianClass() for the Democrat as follows:

    public Class<?> getPoliticianClass() {
        return Democrat.class;
    }

Now you can do the following in your code:

    Politician politician = ...; // code to find your (s)elected politician
    if (politician.instanceOf(Democrat.class) {
        // politician is a democrat
        Democrat democrat = (Democrat) session.get(Democrat.class,
politician.getId())
        // Use your democrat.
    }

Note that regetting your instance from the session narrows the proxy to
the Democrat class and breaks ==, i.e., in the above code democrat ==
politician returns false. However you DO still have a proxy around your
democrat (which does lazy loading etc), which doesn't seem to be the
case if you implement the above visitor pattern.

I would really like hibernate to just make a proxy for the narrowest
entity class for each entity it loads to begin with, then == works again
and so do regular instanceof checks and typecasts. However I don't know
the technical details why hibernate does not do this... (perfomance?).

Regards,
Sebastiaan
 
force initialization 07 Jul 2006, 13:03 jkookie
Can't polymorphic classes and CGLIB be handled with the static 
initialize method e.g

public void forceInitializeProxy(Object o) {
         if(!Hibernate.isInitialized(o)){
             Hibernate.initialize(o);
         }
    }

I thought the initialize method's function was to explicitly 
initialize the proxy. So now if i retrieved an object using hibernate 
and then forceinitialize it using the above method, would i then be 
able to use 'instance of' (I know it's bad form, and i already have 
the visitor pattern implemented) to distinguish between different 
subclasses of the object retrieved?
I'm just trying to understand if the initialize method does what i 
think it does. Thank you in advance.
 
Re: force initialization 07 Aug 2006, 00:59 motravo
On 07 Jul 2006 13:03, jkookie wrote:

>Can't polymorphic classes and CGLIB be handled with the static
>initialize method e.g

>public void forceInitializeProxy(Object o) {
>         if(!Hibernate.isInitialized(o)){
>             Hibernate.initialize(o);
>         }
>    }

That wouldn't work. Say you have:

class Super {}
and
class Sub extends Super {}

and you call session.load(Super.class,4). (Some of the resulting objects 
may be Subs.) Assuming Super is set up for lazy fetching, what you will 
get are objects whose runtime type is something like:

class Super_HibernateProxy extends Super {}

So the objects you have are not Subs, and calling Hibernate.initialize() 
is not going to change their class.

I wish Hibernate provided a way to load an object non-lazily for just a 
single query. There are some cases (for instance, when displaying 
properties of persistent subclass in your presentation layer) where 
using a Visitor is not convenient.

I'd also settle for a static method in org.hibernate.Hibernate that 
loaded the concrete subclass object given a proxy object.
 
Re: force initialization 07 Aug 2006, 01:36 motravo
>I wish Hibernate provided a way to load an object non-lazily for just a
>single query. There are some cases (for instance, when displaying
>properties of persistent subclass in your presentation layer) where
>using a Visitor is not convenient.

>I'd also settle for a static method in org.hibernate.Hibernate that
>loaded the concrete subclass object given a proxy object.

Actually, object obtained through Session.createQuery (rather than 
Session.load or Session.get) would return the concrete subclass, not a 
proxy.
 
Simpler solution with a PoliticianVisitorCollector 23 Feb 2007, 06:41 astedile
This solution is simpler and it seems to work for me. One advantage is, 
that the individual politicians need not be listed in the visitor. I 
checked and saw that the returned objects and their classes are OK.

I implement a specialized <code>PoliticianVisitorCollector</code>. It 
takes any kind of collection and adds one Politician of correct sub-
class instance on each call to abstract <code>accept()</code> method. 
So I can convert a collection of proxies to a collection of polymorphic 
instances.

<code>
public interface PoliticianVisitor {
    void visit(Politician p);
}

public class PoliticianVisitorCollector implements PoliticianVisitor {

    private Collection<Politician> politicians;

    public PoliticianVisitorCollector(Collection<Politician> 
collection) {
        politicians = collection;
    }

    public void visit(Politician p) {
        politicians.add(p);
    }
}

public abstract class Politician {
    ...
    public abstract void accept(PoliticianVisitor visitor);
}

public class Republican extends Politician {
    ...
    @Override
    public void accept(PoliticianVisitor visitor) {
        visitor.visit(this);
    }
}

public class Democrat extends Politician {
    ...
    @Override
    public void accept(PoliticianVisitor visitor) {
        visitor.visit(this);
    }
}
</code>

Test example:

<code>
public class PoliticianVisitorCollectorTest extends TestCase {

    public void testVisit() throws Exception {
        List<Politician> politiciansOut = new ArrayList<Politician>(2);
        PoliticianVisitorCollector visitor = new 
PoliticianVisitorCollector(politiciansOut);

        List<Politician> politiciansIn = Arrays.asList(new 
Republican(), new Democrat());
        for (Politician politician : politiciansIn) {
            politician.accept(visitor);
        }

        assertEquals("Republican", 
politiciansOut.get(0).getClass().getSimpleName());
        assertEquals("Democrat", 
politiciansOut.get(1).getClass().getSimpleName());
        assertEquals(2, politiciansOut.size());
    }
}
</code>

I tried the same with a <code>public void getThis()</code> method 
instead of the <code>accept()</code>. This did not work.

Hope this helps.
 
© Copyright 2006, Red Hat Middleware, LLC. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc. [Privacy Policy]