The exception was
org.hibernate.AssertionFailure: collection [package.entity.collectionProperty] was not processed by flush()
at org.hibernate.engine.CollectionEntry.postFlush(CollectionEntry.java:228)
at org.hibernate.event.def.AbstractFlushingEventListener.postFlush(AbstractFlushingEventListener.java:352)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:960)
The error log also showed the following:
org.hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
This confused me because I thought I had finished with the data access layer and hadn't changed anything in that area - certainly nothing that could be categorised as "unsafe use of the session".
We have had this exception before when using hibernate event listeners if lazy loaded collections where touched in the event listener itself. That wasn't the case here.
After removing changes made by others in the data access layer, the problem remained. After testing against daily builds, I confirmed that the problem was in my new code, specifically one line of code in one JPA entity:
@Size(max = 60)
This is clearly not "unsafe use of the session". It isn't even on the collection property reported in the session !!!
This annotation is a little unusual because the it is on a getter method that isn't a persistent property, but it should work without this exception. The problem in this case must be triggered because the getter method includes fetching the properties of an associated entity which is lazy loaded. Somehow that must result in the reported collection property also being loaded.
It appears that in hibernate reading lazy loaded collection properties during a flush results in the above assertion exception. Given that validation needs to happen after any pre-update events and before the actual persistence, the validation in this case is calling the getter method during the flush, triggering loading of the lazy collection property and therefore triggering the hibernate exception.
Solutions include separating and/or moving the validation logic to properties that are not lazy loaded or making the relevant properties eagerly loaded, but these solutions are not always possible or desirable.
In my case I was able to remove the annotation from the getter method.
This was occurring in hibernate 3.6.9. Hibernate 4 has fixed things so this doesn't happen any more (reading a lazy loaded collection during flush doesn't trigger the exception). After upgrading I can put @Size back on!
See https://hibernate.onjira.com/browse/HHH-2763 for the long history of this problem.