In case anyone is interested this was the problem:
Of course Hibernate requires that there be only one java instance of a persistent entity per Hibernate session. Session.load(instance) will not always work well with this requirement because it is trying to bind another java instance to the persistent entity.
Before I added the cache, the order of events was:
1. re-associated the instance saved on the HTTP session with the persistent entity using Session.load(instance).
2. accessed the same entity as one member of a one-to-many lazy persistent collection
Since the Hibernate session controls the contents of a lazy persistent collection, this order was not creating another java instance of the same entity, it was only just returning the instance that had originally been on the HTTP session.
After I added the cache, the entity owning the lazy collection was saved on the cache and the object graph containing this entity happened to be accessed before I was re-associating the instance from the HTTP session with the current Hibernate session. Thus the order was:
1. accessed the same entity as one member of a one-to-many lazy persistent collection (from object graph stored in cache)
2. re-associated the instance saved on the HTTP session with the persistent entity using Session.load(instance)
This ordering is problematic because step 2 tries to associate another java instance with the persistent entity, which is illegal if there is a pre-existing java instance already so associated.
So, the solution I came up with is to re-associate the instance from the HTTP session this way:
Code:
instance = session.load(instance.getClass(), instance.getId());
which solved the previous problem.