diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/LazyLoadingByEnhancerSetterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/LazyLoadingByEnhancerSetterTest.java index dd4b55ac6f..9f6c1dd48a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/LazyLoadingByEnhancerSetterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/LazyLoadingByEnhancerSetterTest.java @@ -82,7 +82,7 @@ public class LazyLoadingByEnhancerSetterTest extends BaseCoreFunctionalTestCase } @Test - @FailureExpected( jiraKey = "HHH-10747" ) +// @FailureExpected( jiraKey = "HHH-10747" ) public void testProperty() { doInHibernate( this::sessionFactory, s -> { ItemProperty input = new ItemProperty(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/NoDirtyCheckingContext.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/NoDirtyCheckingContext.java new file mode 100644 index 0000000000..e1a1948937 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/NoDirtyCheckingContext.java @@ -0,0 +1,13 @@ +package org.hibernate.orm.test.bytecode.enhancement.lazy; + +import org.hibernate.bytecode.enhance.spi.UnloadedClass; + +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; + +public class NoDirtyCheckingContext extends EnhancerTestContext { + + @Override + public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) { + return false; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateTest.java index a7c6b5b298..3a42834366 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateTest.java @@ -6,11 +6,15 @@ */ package org.hibernate.orm.test.bytecode.enhancement.lazy.basic; +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; + import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; @@ -24,6 +28,7 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; @RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext( {EnhancerTestContext.class, NoDirtyCheckingContext.class} ) public class MultiLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { private Long entityId; @@ -52,6 +57,8 @@ public class MultiLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); + assertNull( entity.getEagerProperty() ); + assertNull( entity.getLazyProperty2() ); } ); // non-null -> non-null @@ -62,16 +69,8 @@ public class MultiLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); + assertNull( entity.getEagerProperty() ); } ); } @@ -80,37 +79,27 @@ public class MultiLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { // null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setEagerProperty( "update1" ); + entity.setEagerProperty( "eager_update1" ); entity.setLazyProperty1( "update1" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertEquals( "update1", entity.getEagerProperty() ); + assertEquals( "eager_update1", entity.getEagerProperty() ); assertEquals( "update1", entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); } ); // non-null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setEagerProperty( "update2" ); + entity.setEagerProperty( "eager_update2" ); entity.setLazyProperty1( "update2" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertEquals( "update2", entity.getEagerProperty() ); + assertEquals( "eager_update2", entity.getEagerProperty() ); assertEquals( "update2", entity.getLazyProperty1() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setEagerProperty( null ); - entity.setLazyProperty1( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getEagerProperty() ); - assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); } ); } @@ -120,36 +109,26 @@ public class MultiLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update1" ); - entity.setLazyProperty2( "update1" ); + entity.setLazyProperty2( "update2_1" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); - assertEquals( "update1", entity.getLazyProperty2() ); + assertEquals( "update2_1", entity.getLazyProperty2() ); + assertNull( entity.getEagerProperty() ); } ); // non-null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update2" ); - entity.setLazyProperty2( "update2" ); + entity.setLazyProperty2( "update2_2" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - assertEquals( "update2", entity.getLazyProperty2() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - entity.setLazyProperty2( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); - assertNull( entity.getLazyProperty2() ); + assertEquals( "update2_2", entity.getLazyProperty2() ); + assertNull( entity.getEagerProperty() ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateToNullTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateToNullTest.java new file mode 100644 index 0000000000..380e80d5b4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/MultiLazyBasicUpdateToNullTest.java @@ -0,0 +1,146 @@ +/* + * 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.orm.test.bytecode.enhancement.lazy.basic; + +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext({ EnhancerTestContext.class, NoDirtyCheckingContext.class }) +public class MultiLazyBasicUpdateToNullTest extends BaseCoreFunctionalTestCase { + + private Long entityId; + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { LazyEntity.class }; + } + + @Before + public void prepare() { + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = new LazyEntity(); + entity.setEagerProperty( "eager" ); + entity.setLazyProperty1( "update1" ); + entity.setLazyProperty2( "update2" ); + s.persist( entity ); + entityId = entity.getId(); + } ); + } + + @Test + public void updateOneLazyProperty() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNotNull( entity.getLazyProperty2() ); + } ); + } + + @Test + public void updateOneEagerPropertyAndOneLazyProperty() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setEagerProperty( null ); + entity.setLazyProperty1( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getEagerProperty() ); + assertNull( entity.getLazyProperty1() ); + assertNotNull( entity.getLazyProperty2() ); + } ); + } + + @Test + public void updateAllLazyProperties() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + entity.setLazyProperty2( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNotNull( entity.getEagerProperty() ); + assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); + } ); + } + + @Entity + @Table(name = "LAZY_ENTITY") + private static class LazyEntity { + @Id + @GeneratedValue + Long id; + // We need at least one eager property to avoid a different problem. + @Basic + String eagerProperty; + @Basic(fetch = FetchType.LAZY) + String lazyProperty1; + // We need multiple lazy properties to reproduce the problem. + @Basic(fetch = FetchType.LAZY) + String lazyProperty2; + + Long getId() { + return id; + } + + void setId(Long id) { + this.id = id; + } + + public String getEagerProperty() { + return eagerProperty; + } + + public void setEagerProperty(String eagerProperty) { + this.eagerProperty = eagerProperty; + } + + public String getLazyProperty1() { + return lazyProperty1; + } + + public void setLazyProperty1(String lazyProperty1) { + this.lazyProperty1 = lazyProperty1; + } + + public String getLazyProperty2() { + return lazyProperty2; + } + + public void setLazyProperty2(String lazyProperty2) { + this.lazyProperty2 = lazyProperty2; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateTest.java index c211b2215a..3732100cdd 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateTest.java @@ -6,11 +6,11 @@ */ package org.hibernate.orm.test.bytecode.enhancement.lazy.basic; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; @@ -23,7 +23,12 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + @RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext({ EnhancerTestContext.class, NoDirtyCheckingContext.class }) public class OnlyLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { private Long entityId; @@ -52,6 +57,7 @@ public class OnlyLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); } ); // non-null -> non-null @@ -62,16 +68,7 @@ public class OnlyLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); } ); } @@ -81,36 +78,24 @@ public class OnlyLazyBasicUpdateTest extends BaseCoreFunctionalTestCase { doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update1" ); - entity.setLazyProperty2( "update1" ); + entity.setLazyProperty2( "update2_1" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); - assertEquals( "update1", entity.getLazyProperty2() ); + assertEquals( "update2_1", entity.getLazyProperty2() ); } ); // non-null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update2" ); - entity.setLazyProperty2( "update2" ); + entity.setLazyProperty2( "update2_2" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - assertEquals( "update2", entity.getLazyProperty2() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - entity.setLazyProperty2( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); - assertNull( entity.getLazyProperty2() ); + assertEquals( "update2_2", entity.getLazyProperty2() ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateToNullTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateToNullTest.java new file mode 100644 index 0000000000..f96f9de08e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/basic/OnlyLazyBasicUpdateToNullTest.java @@ -0,0 +1,117 @@ +/* + * 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.orm.test.bytecode.enhancement.lazy.basic; + +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext( { EnhancerTestContext.class, NoDirtyCheckingContext.class} ) +public class OnlyLazyBasicUpdateToNullTest extends BaseCoreFunctionalTestCase { + + private Long entityId; + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { LazyEntity.class }; + } + + @Before + public void prepare() { + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = new LazyEntity(); + entity.setLazyProperty1( "update1" ); + entity.setLazyProperty2( "update2" ); + s.persist( entity ); + entityId = entity.getId(); + } ); + } + + @Test + public void updateSomeLazyProperty() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNotNull( entity.getLazyProperty2() ); + } ); + } + + @Test + public void updateAllLazyProperties() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + entity.setLazyProperty2( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); + } ); + } + + @Entity + @Table(name = "LAZY_ENTITY") + private static class LazyEntity { + @Id + @GeneratedValue + Long id; + // ALL properties must be lazy in order to reproduce the problem. + @Basic(fetch = FetchType.LAZY) + String lazyProperty1; + @Basic(fetch = FetchType.LAZY) + String lazyProperty2; + + Long getId() { + return id; + } + + void setId(Long id) { + this.id = id; + } + + public String getLazyProperty1() { + return lazyProperty1; + } + + public void setLazyProperty1(String lazyProperty1) { + this.lazyProperty1 = lazyProperty1; + } + + public String getLazyProperty2() { + return lazyProperty2; + } + + public void setLazyProperty2(String lazyProperty2) { + this.lazyProperty2 = lazyProperty2; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateTest.java index b27eb3b24f..b204745cf5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateTest.java @@ -8,11 +8,14 @@ package org.hibernate.orm.test.bytecode.enhancement.lazy.group; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertNull; import org.hibernate.annotations.LazyGroup; +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; @@ -26,6 +29,7 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; @RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext( { EnhancerTestContext.class, NoDirtyCheckingContext.class} ) public class MultiLazyBasicInLazyGroupUpdateTest extends BaseCoreFunctionalTestCase { private Long entityId; @@ -54,6 +58,8 @@ public class MultiLazyBasicInLazyGroupUpdateTest extends BaseCoreFunctionalTestC doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); + assertNull(entity.getLazyProperty2()); + assertNull(entity.getEagerProperty()); } ); // non-null -> non-null @@ -64,16 +70,8 @@ public class MultiLazyBasicInLazyGroupUpdateTest extends BaseCoreFunctionalTestC doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); + assertNull(entity.getLazyProperty2()); + assertNull(entity.getEagerProperty()); } ); } @@ -82,37 +80,27 @@ public class MultiLazyBasicInLazyGroupUpdateTest extends BaseCoreFunctionalTestC // null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setEagerProperty( "update1" ); + entity.setEagerProperty( "eager_update1" ); entity.setLazyProperty1( "update1" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertEquals( "update1", entity.getEagerProperty() ); + assertEquals( "eager_update1", entity.getEagerProperty() ); assertEquals( "update1", entity.getLazyProperty1() ); + assertNull(entity.getLazyProperty2()); } ); // non-null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setEagerProperty( "update2" ); + entity.setEagerProperty( "eager_update2" ); entity.setLazyProperty1( "update2" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertEquals( "update2", entity.getEagerProperty() ); + assertEquals( "eager_update2", entity.getEagerProperty() ); assertEquals( "update2", entity.getLazyProperty1() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setEagerProperty( null ); - entity.setLazyProperty1( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getEagerProperty() ); - assertNull( entity.getLazyProperty1() ); + assertNull(entity.getLazyProperty2()); } ); } @@ -122,36 +110,26 @@ public class MultiLazyBasicInLazyGroupUpdateTest extends BaseCoreFunctionalTestC doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update1" ); - entity.setLazyProperty2( "update1" ); + entity.setLazyProperty2( "update2_1" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); - assertEquals( "update1", entity.getLazyProperty2() ); + assertEquals( "update2_1", entity.getLazyProperty2() ); + assertNull( entity.getEagerProperty() ); } ); // non-null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update2" ); - entity.setLazyProperty2( "update2" ); + entity.setLazyProperty2( "update2_2" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - assertEquals( "update2", entity.getLazyProperty2() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - entity.setLazyProperty2( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); - assertNull( entity.getLazyProperty2() ); + assertEquals( "update2_2", entity.getLazyProperty2() ); + assertNull( entity.getEagerProperty() ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateToNullTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateToNullTest.java new file mode 100644 index 0000000000..a78d177c6d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/MultiLazyBasicInLazyGroupUpdateToNullTest.java @@ -0,0 +1,150 @@ +/* + * 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.orm.test.bytecode.enhancement.lazy.group; + +import org.hibernate.annotations.LazyGroup; +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext( { EnhancerTestContext.class, NoDirtyCheckingContext.class} ) +public class MultiLazyBasicInLazyGroupUpdateToNullTest extends BaseCoreFunctionalTestCase { + + private Long entityId; + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { LazyEntity.class }; + } + + @Before + public void prepare() { + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = new LazyEntity(); + entity.setEagerProperty( "eager" ); + entity.setLazyProperty1( "update1" ); + entity.setLazyProperty2( "update2" ); + s.persist( entity ); + entityId = entity.getId(); + } ); + } + + @Test + public void updateOneLazyProperty() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNotNull( entity.getLazyProperty2() ); + assertNotNull( entity.getEagerProperty() ); + } ); + } + + @Test + public void updateOneEagerPropertyAndOneLazyProperty() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setEagerProperty( null ); + entity.setLazyProperty1( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getEagerProperty() ); + assertNull( entity.getLazyProperty1() ); + assertNotNull( entity.getLazyProperty2() ); + } ); + } + + @Test + public void updateAllLazyProperties() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + entity.setLazyProperty2( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); + assertNotNull( entity.getEagerProperty() ); + } ); + } + + @Entity + @Table(name = "LAZY_ENTITY") + private static class LazyEntity { + @Id + @GeneratedValue + Long id; + // We need at least one eager property to avoid a different problem. + @Basic + String eagerProperty; + @Basic(fetch = FetchType.LAZY) + @LazyGroup("group1") + String lazyProperty1; + // We need multiple lazy properties to reproduce the problem. + @Basic(fetch = FetchType.LAZY) + @LazyGroup("group2") + String lazyProperty2; + + Long getId() { + return id; + } + + void setId(Long id) { + this.id = id; + } + + public String getEagerProperty() { + return eagerProperty; + } + + public void setEagerProperty(String eagerProperty) { + this.eagerProperty = eagerProperty; + } + + public String getLazyProperty1() { + return lazyProperty1; + } + + public void setLazyProperty1(String lazyProperty1) { + this.lazyProperty1 = lazyProperty1; + } + + public String getLazyProperty2() { + return lazyProperty2; + } + + public void setLazyProperty2(String lazyProperty2) { + this.lazyProperty2 = lazyProperty2; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateTest.java index c1293f44ae..6ced98f0c4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateTest.java @@ -6,13 +6,12 @@ */ package org.hibernate.orm.test.bytecode.enhancement.lazy.group; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - import org.hibernate.annotations.LazyGroup; +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; @@ -25,7 +24,12 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + @RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext({ EnhancerTestContext.class, NoDirtyCheckingContext.class }) public class OnlyLazyBasicInLazyGroupBasicUpdateTest extends BaseCoreFunctionalTestCase { private Long entityId; @@ -54,6 +58,7 @@ public class OnlyLazyBasicInLazyGroupBasicUpdateTest extends BaseCoreFunctionalT doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); } ); // non-null -> non-null @@ -64,16 +69,7 @@ public class OnlyLazyBasicInLazyGroupBasicUpdateTest extends BaseCoreFunctionalT doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); } ); } @@ -83,36 +79,24 @@ public class OnlyLazyBasicInLazyGroupBasicUpdateTest extends BaseCoreFunctionalT doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update1" ); - entity.setLazyProperty2( "update1" ); + entity.setLazyProperty2( "update2_1" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update1", entity.getLazyProperty1() ); - assertEquals( "update1", entity.getLazyProperty2() ); + assertEquals( "update2_1", entity.getLazyProperty2() ); } ); // non-null -> non-null doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); entity.setLazyProperty1( "update2" ); - entity.setLazyProperty2( "update2" ); + entity.setLazyProperty2( "update2_2" ); } ); doInHibernate( this::sessionFactory, s -> { LazyEntity entity = s.get( LazyEntity.class, entityId ); assertEquals( "update2", entity.getLazyProperty1() ); - assertEquals( "update2", entity.getLazyProperty2() ); - } ); - - // non-null -> null - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - entity.setLazyProperty1( null ); - entity.setLazyProperty2( null ); - } ); - doInHibernate( this::sessionFactory, s -> { - LazyEntity entity = s.get( LazyEntity.class, entityId ); - assertNull( entity.getLazyProperty1() ); - assertNull( entity.getLazyProperty2() ); + assertEquals( "update2_2", entity.getLazyProperty2() ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateToNullTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateToNullTest.java new file mode 100644 index 0000000000..a9b257f9c1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/group/OnlyLazyBasicInLazyGroupBasicUpdateToNullTest.java @@ -0,0 +1,120 @@ +/* + * 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.orm.test.bytecode.enhancement.lazy.group; + +import org.hibernate.annotations.LazyGroup; +import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.Basic; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext( { EnhancerTestContext.class, NoDirtyCheckingContext.class} ) +public class OnlyLazyBasicInLazyGroupBasicUpdateToNullTest extends BaseCoreFunctionalTestCase { + + private Long entityId; + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { LazyEntity.class }; + } + + @Before + public void prepare() { + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = new LazyEntity(); + entity.setLazyProperty1( "update1" ); + entity.setLazyProperty2( "update2" ); + s.persist( entity ); + entityId = entity.getId(); + } ); + } + + @Test + public void updateOneLazyProperty() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNotNull( entity.getLazyProperty2() ); + } ); + } + + @Test + public void updateAllLazyProperties() { + // non-null -> null + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + entity.setLazyProperty1( null ); + entity.setLazyProperty2( null ); + } ); + doInHibernate( this::sessionFactory, s -> { + LazyEntity entity = s.get( LazyEntity.class, entityId ); + assertNull( entity.getLazyProperty1() ); + assertNull( entity.getLazyProperty2() ); + } ); + } + + @Entity + @Table(name = "LAZY_ENTITY") + private static class LazyEntity { + @Id + @GeneratedValue + Long id; + // ALL properties must be lazy in order to reproduce the problem. + @Basic(fetch = FetchType.LAZY) + @LazyGroup("group1") + String lazyProperty1; + @Basic(fetch = FetchType.LAZY) + @LazyGroup("group2") + String lazyProperty2; + + Long getId() { + return id; + } + + void setId(Long id) { + this.id = id; + } + + public String getLazyProperty1() { + return lazyProperty1; + } + + public void setLazyProperty1(String lazyProperty1) { + this.lazyProperty1 = lazyProperty1; + } + + public String getLazyProperty2() { + return lazyProperty2; + } + + public void setLazyProperty2(String lazyProperty2) { + this.lazyProperty2 = lazyProperty2; + } + } +}