From f0dfc1269b425640833eda00bced4543ffc3b0dc Mon Sep 17 00:00:00 2001 From: barreiro Date: Fri, 24 Jun 2016 06:06:44 +0100 Subject: [PATCH] HHH-10865 - ManyToMany relation dropped from database when lazy loading is active --- .../spi/BytecodeEnhancementMetadata.java | 2 + .../tuple/entity/AbstractEntityTuplizer.java | 5 +- ...ytecodeEnhancementMetadataNonPojoImpl.java | 6 + .../BytecodeEnhancementMetadataPojoImpl.java | 10 +- .../bytecode/enhancement/EnhancerTest.java | 2 + .../UnexpectedDeleteThreeTestTask.java | 152 ++++++++++++++++++ 6 files changed, 172 insertions(+), 5 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/HHH_10708/UnexpectedDeleteThreeTestTask.java diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java index 20b9626cb4..b71ba5aad2 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/BytecodeEnhancementMetadata.java @@ -59,4 +59,6 @@ public interface BytecodeEnhancementMetadata { LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException; boolean hasUnFetchedAttributes(Object entity); + + boolean isAttributeLoaded(Object entity, String attributeName); } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java index 0b195e4f4b..ea284898c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java @@ -15,6 +15,7 @@ import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.PersistenceContext; @@ -495,13 +496,13 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer { @Override public Object[] getPropertyValues(Object entity) { - boolean getAll = shouldGetAllProperties( entity ); + final BytecodeEnhancementMetadata enhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata(); final int span = entityMetamodel.getPropertySpan(); final Object[] result = new Object[span]; for ( int j = 0; j < span; j++ ) { NonIdentifierAttribute property = entityMetamodel.getProperties()[j]; - if ( getAll || !property.isLazy() ) { + if ( !property.isLazy() || enhancementMetadata.isAttributeLoaded( entity, property.getName() ) ) { result[j] = getters[j].get( entity ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java index 38e53c95e8..10286c23a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataNonPojoImpl.java @@ -57,4 +57,10 @@ public class BytecodeEnhancementMetadataNonPojoImpl implements BytecodeEnhanceme public boolean hasUnFetchedAttributes(Object entity) { return false; } + + @Override + public boolean isAttributeLoaded(Object entity, String attributeName) { + return true; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java index 621b91bbc4..48134c0cee 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java @@ -67,12 +67,16 @@ public class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhancementM @Override public boolean hasUnFetchedAttributes(Object entity) { - LazyAttributeLoadingInterceptor interceptor = isEnhancedForLazyLoading() - ? extractInterceptor( entity ) - : null; + LazyAttributeLoadingInterceptor interceptor = enhancedForLazyLoading ? extractInterceptor( entity ) : null; return interceptor != null && interceptor.hasAnyUninitializedAttributes(); } + @Override + public boolean isAttributeLoaded(Object entity, String attributeName) { + LazyAttributeLoadingInterceptor interceptor = enhancedForLazyLoading ? extractInterceptor( entity ) : null; + return interceptor == null || interceptor.isAttributeLoaded( attributeName ); + } + @Override public LazyAttributeLoadingInterceptor extractInterceptor(Object entity) throws NotInstrumentedException { if ( !enhancedForLazyLoading ) { 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 a0f5cbc350..3273667412 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 @@ -25,6 +25,7 @@ import org.hibernate.test.bytecode.enhancement.join.HHH3949TestTask2; import org.hibernate.test.bytecode.enhancement.join.HHH3949TestTask3; import org.hibernate.test.bytecode.enhancement.join.HHH3949TestTask4; import org.hibernate.test.bytecode.enhancement.lazy.HHH_10708.UnexpectedDeleteOneTestTask; +import org.hibernate.test.bytecode.enhancement.lazy.HHH_10708.UnexpectedDeleteThreeTestTask; import org.hibernate.test.bytecode.enhancement.lazy.HHH_10708.UnexpectedDeleteTwoTestTask; import org.hibernate.test.bytecode.enhancement.lazy.LazyBasicFieldNotInitializedTestTask; import org.hibernate.test.bytecode.enhancement.lazy.LazyCollectionLoadingTestTask; @@ -116,6 +117,7 @@ public class EnhancerTest extends BaseUnitTestCase { public void testLazyUnexpectedDelete() { EnhancerTestUtils.runEnhancerTestTask( UnexpectedDeleteOneTestTask.class ); EnhancerTestUtils.runEnhancerTestTask( UnexpectedDeleteTwoTestTask.class ); + EnhancerTestUtils.runEnhancerTestTask( UnexpectedDeleteThreeTestTask.class ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/HHH_10708/UnexpectedDeleteThreeTestTask.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/HHH_10708/UnexpectedDeleteThreeTestTask.java new file mode 100644 index 0000000000..f847f382ff --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/HHH_10708/UnexpectedDeleteThreeTestTask.java @@ -0,0 +1,152 @@ +/* + * 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.lazy.HHH_10708; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask; +import org.junit.Assert; + +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class UnexpectedDeleteThreeTestTask extends AbstractEnhancerTestTask { + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { Parent.class, Child.class }; + } + + @Override + public void prepare() { + Configuration cfg = new Configuration(); + cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); + prepare( cfg ); + + Session s = getFactory().openSession(); + s.beginTransaction(); + + Child child = new Child(); + child.setId( 2L ); + s.save(child); + + Parent parent = new Parent(); + parent.setId( 1L ); + parent.setNames( Collections.singleton( "name" ) ); + + Set children = new HashSet(); + children.add(child); + parent.setChildren( children ); + + s.save( parent ); + + s.getTransaction().commit(); + s.clear(); + s.close(); + } + + @Override + public void execute() { + Session s = getFactory().openSession(); + s.beginTransaction(); + + Parent parent = s.get( Parent.class, 1L ); + Set children = parent.getChildren(); + if (children == null) { + children = new HashSet(); + parent.setChildren( children ); + } + Child child = new Child(); + child.setId( 1L ); + s.save(child); + children.add(child); + + // We need to leave at least one attribute unfetchd + //parent.getNames().size(); + s.save(parent); + + s.getTransaction().commit(); + s.close(); + + s = getFactory().openSession(); + s.beginTransaction(); + + Parent application = s.get( Parent.class, 1L ); + Assert.assertEquals( "Loaded Children collection has unexpected size", 2, application.getChildren().size() ); + + s.getTransaction().commit(); + s.close(); + } + + @Override + protected void cleanup() { + } + + // --- // + + @Entity public static class Child { + + private Long id; + + @Id + @Column(name = "id", unique = true, nullable = false) + public Long getId() { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + } + + @Entity public static class Parent { + + private Long id; + private Set names; + private Set children; + + @Id @Column(name = "id", unique = true, nullable = false) + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + @ElementCollection + public Set getNames() { + return names; + } + + public void setNames(Set secrets) { + this.names = secrets; + } + + @ManyToMany(fetch = FetchType.LAZY, targetEntity = Child.class) + public Set getChildren() { + return children; + } + + public void setChildren(Set children) { + this.children = children; + } + + } + +} \ No newline at end of file