Hi
I've been spending some time over the last few months, building a prototype for an application using Hibernate 3.6 and Spring. During that time, I have posted five questions on this forum, none of which have received a single response. So I don't expect a response from this either - I just want to put on public record a fundamental problem with Hibernate, that may show it up as unsuitable for use in web applications.
Here is the scenario:
I have a Java POJO, backed by a database table. I use Hibernate to map between the two. Now I create a view, which effectively adds information to the records in my table. I represent this as a subclass of my original POJO, again managed by Hibernate.
I can perform selects on the table and get a list of superclass instances, or perform selects on the view and get a list of subclass instances.
Now I implement two Spring controller methods: one processes a request to create a new superclass instance, the other processes a request to update an existing superclass instance. The methods are very similar - one does a persist, the other does a find, update, and merge. Finally, each retrieves a list of subclass instances and returns.
Both controller methods call on two services: one manages superclass instances, the other retrieves subclass instances. All service methods are marked as transactional.
Can you guess what happens? The update controller method always succeeds, whilst the create method always fails, with:
Code:
Data access failure: Object with id: 295 was not of the specified subclass: net.deepthought.next.domain.view.ForumSubjectHeadline (loaded object was of wrong class class net.deepthought.next.domain.entity.ForumSubject); nested exception is org.hibernate.WrongClassException: Object with id: 295 was not of the specified subclass: net.deepthought.next.domain.view.ForumSubjectHeadline (loaded object was of wrong class class net.deepthought.next.domain.entity.ForumSubject)
(By way of explanation, "net.deepthought.next.domain.view.ForumSubjectHeadline" is the subclass, "net.deepthought.next.domain.entity.ForumSubject" is the superclass.)
I think it is fairly obvious what is going on here: in the case of the update, the application code treats the entity as if it was a superclass instance. Hibernate sees it as a subclass instance, but this does not matter. In the case of the create, again we are asserting that the object is a superclass instance. But this time, Hibernate has not touched the instance as a subclass. So now - despite the fact that the transaction boundary should have ended when the persist completed - the new instance cannot be seen as a member of the subclass.
(A subsequent web request to list subclass instances always succeeds, in both cases.)
There is too much caching going on here. The designers of Hibernate have assumed that an object cannot change class, but we have just seen that it can. Perhaps there is an explicit cache invalidation command that could be used at this point, but such type of manual control diminishes the value of automatic O/R. It should not be necessary in any case, since we have moved to a new transaction.
Use Hibernate at your peril?
Bruno.