How to live with hibernate proxies

Stumbled over the fucking hibernate-CGlib-Proxies again. So here is what I found out and what helped me a lot:

If you load an object via the load()-method hibernate returns a proxy by default. As long as you don’t access any primitive property this thing won’t materialize. No prob, you might think and in most circumstances it isn’t. But consider this example:

class Plan {

// Cascade-type all, fetch lazy
private Plan lastVersion;
private boolean active

public Plan(Plan lastVersion){
if (lastVersion != null){
lastVersion.active = false;
}
this.active = true;
}
}

I don’t want to expose a public setter here to ensure the integrity of my versioning. Now the fuck-up:

Let’s say I get the current Plan from my Client and want to save it, the following code seems pretty straight forward:

// transactionmanaged service-method

Plan lastVersion = getHibernateTemplate().load(Plan.class, 4)

Plan currentPlan = new Plan(lastVersion);

getHibernateTemplate().saveOrUpdate(currentPlan);

BUT (as you might have guessed) this doesn’t work. At the end I do have two entries in my db both marked as active. Why that? lastVersion is a cglib-Proxy and hibernate does not recognize any changes that are not done by the setter. A possible workaround would be a private setter in the plan class, but somehow not even this is recognized by hibernate. So what are our options? One is to change the fetchmode of the lastversion. But doing so means sucking all previous versions from db when loading. Same happens when you mark the class @Proxy(lazy=false) as its a recursive structure. Played around with access types a while but that doesn’t have any influence. Finally I found out, that if you work with the “real” object instead of the proxy, it all works fine. To do so, you have to use the method get() instead of load(). Get() makes the db call instantly and returns a materialized object. In difference to the eager-fetchmode, all containing subtypes remain proxies.

That all leads to the questions, how we can make a clean separation between the ORM-Layer and our business-objects with hibernate. It’s just not transparent, when we got hibernate-specific-behaving objects flyin’ around in our domain-layer. And well, I don’t really have an answer on that…