[hibernate-dev] HHH-5855 bug report and a possible fix

Gail Badner gbadner at redhat.com
Wed Dec 23 13:51:38 EST 2015


Hi Vlad,

I've spend quite a bit of time on this one and already have a fix. I just
have some tests to add to confirm. I will look into what you suggest, but
please check with me first if you see that an issue is assigned to me.

Thanks,
Gail

On Wed, Dec 23, 2015 at 4:13 AM, Vlad Mihalcea <mihalcea.vlad at gmail.com>
wrote:

> Hi guys
>
> I decided to spend some time to investigate the infamous HHH-5855 (
> https://hibernate.atlassian.net/browse/HHH-5855 )  bug and this is my
> report.
>
> One of the first thing that I noticed is that Sets are fine, while this bug
> only replicates with bidirectional Bags.
>
> After some hours of debugging and logging (since debugging triggers
> collection initialization), I found the culprit.
>
> In the org.hibernate.type.TypeHelper.replace(Object[] original, Object[]
> target, Type[] types, SessionImplementor session, Object owner, Map
> copyCache) method, when copying the cached entity state (which contains the
> newly added child entity along with its identifier) onto the original
> collection:
>
> copied[i] = types[i].replace( original[i], target[i], session, owner,
> copyCache );
>
> inside the org.hibernate.type.CollectionType.replace(Object[] original,
> Object[] target, Type[] types, SessionImplementor session, Object owner,
> Map copyCache)  method there is this check:
>
> if ( !Hibernate.isInitialized( original ) ) {
>    return target;
> }
>
>
> For Sets, the collection is always initialized because of this line inside
> the add() method of the org.hibernate.collection.internal.PersistentSet:
>
> final Boolean exists = isOperationQueueEnabled() ?
> readElementExistence( value ) : null;
>
> Because of the the readElementExistence( value ) call the Set is always
> initialized and upon triggering the flush, the newly added Entity being
> already managed it will be left alone.
>
> For PersistentList the aforementioned check is false and the replace never
> occurs, hence the transient entity lingers in the persistence context and
> the flush will trigger another insert, so we get duplicates.
>
> To make the Bag behave like the Set, all we need to do is to change the add
> method like this:
>
> public boolean add(Object object) {
>    initialize(false);
>    if ( !isOperationQueueEnabled() ) {
>       write();
>       return bag.add( object );
>    }
>    else {
>       queueOperation( new SimpleAdd( object ) );
>       return true;
>    }
> }
>
> but then four tests will fail:
>
> org.hibernate.test.legacy.MasterDetailTest > testQueuedBagAdds FAILED
>     java.lang.AssertionError at MasterDetailTest.java:1068
>
> org.hibernate.test.unionsubclass.UnionSubclassTest > testUnionSubclass
> FAILED
>     org.hibernate.ObjectDeletedException at UnionSubclassTest.java:364
>
> org.hibernate.test.version.VersionTest > testCollectionNoVersion FAILED
>     java.lang.AssertionError at VersionTest.java:118
>
> org.hibernate.test.version.VersionTest > testCollectionVersion FAILED
>     java.lang.AssertionError at VersionTest.java:79
>
> 3 of them fail because we expect the List not to be initialized and
> the UnionSubclassTest  fails
> for a doubtful reason (we attempt to delete an entity which is still
> referenced).
>
> Basically, such a change will finally fix this issue and the Sets and Lists
> will behave consistently. Since you know the reasons behind the difference
> in how Sets and Lists are initialized, we need to discuss if this change is
> appropriate or we should address this issue differently.
>
> I have a branch on my fork with a test that replicates this issue and that
> the proposed change manages to fix it:
>
> https://github.com/vladmihalcea/hibernate-orm/tree/feature/hhh5855
>
> Let me know what you think and let's discuss it further.
>
> Vlad
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>


More information about the hibernate-dev mailing list