From 7ed51f44dd9ddcb7e596c397d97ba24ca883323a Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 3 Jun 2016 00:14:04 -0700 Subject: [PATCH] HHH-10562 : ManagedEntity linked list broken when non-associated enhanced entity is evicted --- .../engine/internal/EntityEntryContext.java | 5 +- .../bytecode/enhancement/EnhancerTest.java | 6 ++ .../eviction/EvictionTestTask.java | 94 +++++++++++++++++++ .../bytecode/enhancement/eviction/Parent.java | 39 ++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/EvictionTestTask.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/Parent.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java index b79868645d..a6d9027587 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/EntityEntryContext.java @@ -181,10 +181,13 @@ public class EntityEntryContext { } // if we could not resolve it, just return (it was not associated with this context) - if ( managedEntity == null ) { + if ( managedEntity == null || managedEntity.$$_hibernate_getEntityEntry() == null) { return null; } + // TODO: should dirty be set to true only if managedEntity is associtated with this context + // (instead of setting it at the top of this method)? + // prepare for re-linking... final ManagedEntity previous = managedEntity.$$_hibernate_getPreviousManagedEntity(); final ManagedEntity next = managedEntity.$$_hibernate_getNextManagedEntity(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java index f71fdb36ea..a0f5cbc350 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/EnhancerTest.java @@ -6,6 +6,7 @@ */ package org.hibernate.test.bytecode.enhancement; +import org.hibernate.test.bytecode.enhancement.eviction.EvictionTestTask; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils; @@ -62,6 +63,11 @@ public class EnhancerTest extends BaseUnitTestCase { EnhancerTestUtils.runEnhancerTestTask( DirtyTrackingTestTask.class ); } + @Test + public void testEviction() { + EnhancerTestUtils.runEnhancerTestTask( EvictionTestTask.class ); + } + @Test public void testAssociation() { EnhancerTestUtils.runEnhancerTestTask( OneToOneAssociationTestTask.class ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/EvictionTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/EvictionTestTask.java new file mode 100644 index 0000000000..1dc21fa1b1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/EvictionTestTask.java @@ -0,0 +1,94 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.eviction; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.spi.ManagedEntity; +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; + +import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +/** + * @author Gail Badner + */ +public class EvictionTestTask extends AbstractEnhancerTestTask { + + + public Class[] getAnnotatedClasses() { + return new Class[] {Parent.class}; + } + + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + super.prepare( cfg ); + + // Create a Parent + Session s = getFactory().openSession(); + s.beginTransaction(); + + Parent p = new Parent(); + p.setName( "PARENT" ); + s.persist( p ); + + s.getTransaction().commit(); + s.close(); + } + + public void execute() { + // Delete the Parent + Session s = getFactory().openSession(); + s.beginTransaction(); + Parent loadedParent = (Parent) s.createQuery( "SELECT p FROM Parent p WHERE name=:name" ) + .setParameter( "name", "PARENT" ) + .uniqueResult(); + assertTyping( ManagedEntity.class, loadedParent ); + ManagedEntity managedParent = (ManagedEntity) loadedParent; + // before eviction + assertNotNull( managedParent.$$_hibernate_getEntityInstance() ); + assertNotNull( managedParent.$$_hibernate_getEntityEntry() ); + assertNull( managedParent.$$_hibernate_getPreviousManagedEntity() ); + assertNull( managedParent.$$_hibernate_getNextManagedEntity() ); + + assertTrue( s.contains( managedParent ) ); + s.evict( managedParent ); + + // after eviction + assertFalse( s.contains( managedParent ) ); + assertNotNull( managedParent.$$_hibernate_getEntityInstance() ); + assertNull( managedParent.$$_hibernate_getEntityEntry() ); + assertNull( managedParent.$$_hibernate_getPreviousManagedEntity() ); + assertNull( managedParent.$$_hibernate_getNextManagedEntity() ); + + // evict again + s.evict( managedParent ); + + assertFalse( s.contains( managedParent ) ); + assertNotNull( managedParent.$$_hibernate_getEntityInstance() ); + assertNull( managedParent.$$_hibernate_getEntityEntry() ); + assertNull( managedParent.$$_hibernate_getPreviousManagedEntity() ); + assertNull( managedParent.$$_hibernate_getNextManagedEntity() ); + + s.delete( managedParent ); + + s.getTransaction().commit(); + s.close(); + } + + protected void cleanup() { + } + + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/Parent.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/Parent.java new file mode 100644 index 0000000000..bea25eee58 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/eviction/Parent.java @@ -0,0 +1,39 @@ +package org.hibernate.test.bytecode.enhancement.eviction; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Basic; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +/** + * Created by barreiro on 12/9/15. + */ +@Entity +public class Parent { + private Long id; + private String name; + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +}