From 7b489b180c35aecd73c6f8e7b0aa634b20d91c77 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 27 Nov 2019 07:22:49 -0600 Subject: [PATCH] HH-13720: Implement mapping model support for plural attributes - sorted set --- .../AbstractPersistentCollection.java | 7 ++- .../collection/spi/PersistentCollection.java | 5 +++ ...bstractImmediateCollectionInitializer.java | 15 ++++--- .../collections/EntityContainingSets.java | 25 +++++++++++ .../collections/MapOperationTests.java | 17 +++++--- .../PluralAttributeMappingTests.java | 5 ++- .../collections/SetOperationTests.java | 43 +++++++++++++++---- .../orm/test/query/hql/SelectClauseTests.java | 5 +++ .../orm/domain/gambit/EntityOfSets.java | 14 ++++++ 9 files changed, 111 insertions(+), 25 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java index 2cebf531d5..5c869d3589 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java @@ -59,10 +59,12 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers private transient SharedSessionContractImplementor session; private boolean isTempSession = false; + private boolean initialized; + private transient boolean initializing; + private transient List operationQueue; private transient boolean directlyAccessible; - private transient boolean initializing; private Object owner; private int cachedSize = -1; @@ -615,7 +617,8 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers this.initialized = true; } - protected boolean isInitializing() { + @Override + public boolean isInitializing() { return initializing; } diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java index 1893912994..bfb788b742 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java @@ -342,6 +342,11 @@ public interface PersistentCollection { */ boolean isWrapper(Object collection); + /** + * Is this PersistentCollection in the process of being initialized? + */ + boolean isInitializing(); + /** * Is this instance initialized? * diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/collection/AbstractImmediateCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/collection/AbstractImmediateCollectionInitializer.java index b2a47d47eb..7c55776cac 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/collection/AbstractImmediateCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/collection/AbstractImmediateCollectionInitializer.java @@ -300,13 +300,16 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol // the LoadingCollectionEntry won't finalize this for us without at least one row. final PersistenceContext persistenceContext = context.getSession().getPersistenceContext(); final PersistentCollection collection = persistenceContext.getCollection( collectionKey ); - collection.beforeInitialize( getCollectionAttributeMapping().getCollectionDescriptor(), 0 ); - collection.beginRead(); - collection.endRead(); - final CollectionEntry entry = persistenceContext.getCollectionEntry( collection ); - if ( entry != null ) { - entry.postInitialize( collection ); + if ( ! collection.isInitializing() ) { + collection.beforeInitialize( getCollectionAttributeMapping().getCollectionDescriptor(), 0 ); + collection.beginRead(); + collection.endRead(); + + final CollectionEntry entry = persistenceContext.getCollectionEntry( collection ); + if ( entry != null ) { + entry.postInitialize( collection ); + } } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/EntityContainingSets.java b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/EntityContainingSets.java index 35ac311424..f596652214 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/EntityContainingSets.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/EntityContainingSets.java @@ -8,7 +8,10 @@ package org.hibernate.orm.test.metamodel.mapping.collections; import java.util.HashSet; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; import javax.persistence.Convert; import javax.persistence.ElementCollection; import javax.persistence.Embedded; @@ -19,6 +22,8 @@ import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; +import org.hibernate.annotations.SortNatural; + /** * @author Steve Ebersole */ @@ -34,6 +39,8 @@ public class EntityContainingSets { private Set setOfComponents; private Set setOfEntities; + private SortedSet sortedSetOfBasics; + public EntityContainingSets() { } @@ -141,4 +148,22 @@ public class EntityContainingSets { } setOfEntities.add( value ); } + + @ElementCollection() + @CollectionTable( name = "EntityOfSet_sortedBasics") + @SortNatural + public SortedSet getSortedSetOfBasics() { + return sortedSetOfBasics; + } + + public void setSortedSetOfBasics(SortedSet sortedSetOfBasics) { + this.sortedSetOfBasics = sortedSetOfBasics; + } + + public void addSortedBasic(String value) { + if ( sortedSetOfBasics == null ) { + sortedSetOfBasics = new TreeSet<>(); + } + sortedSetOfBasics.add( value ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/MapOperationTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/MapOperationTests.java index b0c14ade76..59c1088a6b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/MapOperationTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/MapOperationTests.java @@ -58,16 +58,16 @@ public class MapOperationTests { // there is a problem with deleting entities which have basic collections. for some reason those // do not register as cascadable, so we do not delete the collection rows first -// scope.inTransaction( -// session -> { -// final EntityContainingMaps entity = session.load( EntityContainingMaps.class, 1 ); -// session.delete( entity ); -// } -// ); + scope.inTransaction( + session -> { + final EntityContainingMaps entity = session.load( EntityContainingMaps.class, 1 ); + session.delete( entity ); + } + ); // uber hacky temp way: - TempDropDataHelper.cleanDatabaseSchema( scope, domainModelScope ); +// TempDropDataHelper.cleanDatabaseSchema( scope, domainModelScope ); } @Test @@ -98,5 +98,8 @@ public class MapOperationTests { session.delete( entity ); } ); + + // re-create it so the drop-data can succeed + createData( scope ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/PluralAttributeMappingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/PluralAttributeMappingTests.java index f8c8412e97..39dd0dbc91 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/PluralAttributeMappingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/PluralAttributeMappingTests.java @@ -67,7 +67,7 @@ public class PluralAttributeMappingTests { final DomainMetamodel domainModel = scope.getSessionFactory().getDomainModel(); final EntityMappingType containerEntityDescriptor = domainModel.getEntityDescriptor( EntityContainingSets.class ); - assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 6 ) ); + assertThat( containerEntityDescriptor.getNumberOfAttributeMappings(), is( 7 ) ); final AttributeMapping setOfBasics = containerEntityDescriptor.findAttributeMapping( "setOfBasics" ); assertThat( setOfBasics, notNullValue() ); @@ -84,6 +84,9 @@ public class PluralAttributeMappingTests { final AttributeMapping setOfEntities = containerEntityDescriptor.findAttributeMapping( "setOfEntities" ); assertThat( setOfEntities, notNullValue() ); + + final AttributeMapping sortedSetOfBasics = containerEntityDescriptor.findAttributeMapping( "sortedSetOfBasics" ); + assertThat( sortedSetOfBasics, notNullValue() ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/SetOperationTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/SetOperationTests.java index 5859b22020..0c822cc29c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/SetOperationTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/metamodel/mapping/collections/SetOperationTests.java @@ -6,6 +6,8 @@ */ package org.hibernate.orm.test.metamodel.mapping.collections; +import java.util.Iterator; + import org.hibernate.Hibernate; import org.hibernate.testing.orm.junit.DomainModel; @@ -44,6 +46,9 @@ public class SetOperationTests { entity.addBasic( "a value" ); entity.addBasic( "another value" ); + entity.addSortedBasic( "def" ); + entity.addSortedBasic( "abc" ); + entity.addEnum( EnumValue.ONE ); entity.addEnum( EnumValue.TWO ); @@ -60,14 +65,12 @@ public class SetOperationTests { @AfterEach public void dropData(SessionFactoryScope scope, DomainModelScope domainModelScope) { -// scope.inTransaction( -// session -> { -// final EntityContainingSets entity = session.load( EntityContainingSets.class, 1 ); -// session.delete( entity ); -// } -// ); - - TempDropDataHelper.cleanDatabaseSchema( scope, domainModelScope ); + scope.inTransaction( + session -> { + final EntityContainingSets entity = session.load( EntityContainingSets.class, 1 ); + session.delete( entity ); + } + ); } @Test @@ -117,10 +120,12 @@ public class SetOperationTests { session.delete( entity ); } ); + + // re-create it so the drop-data can succeed + createData( scope ); } @Test - @FailureExpected( reason = "not sure" ) public void testTriggerFetch(SessionFactoryScope scope) { scope.inTransaction( session -> { @@ -135,4 +140,24 @@ public class SetOperationTests { } ); } + + @Test + public void testSortedSetAccess(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + final EntityContainingSets entity = session.get( EntityContainingSets.class, 1 ); + assert ! Hibernate.isInitialized( entity.getSortedSetOfBasics() ); + + Hibernate.initialize( entity.getSortedSetOfBasics() ); + + assertThat( entity.getSortedSetOfBasics().size(), is( 2 ) ); + + final Iterator iterator = entity.getSortedSetOfBasics().iterator(); + final String first = iterator.next(); + final String second = iterator.next(); + assertThat( first, is( "abc" ) ); + assertThat( second, is( "def" ) ); + } + ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/SelectClauseTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/SelectClauseTests.java index d0e90f297a..46ff4a36e5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/SelectClauseTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/SelectClauseTests.java @@ -246,6 +246,11 @@ public class SelectClauseTests extends BaseSqmUnitTest { EntityOfSets.class.getName() + ".setOfOneToMany", "b" ); + collectionValueFunctionAssertions( + interpretSelect( "select value(b) from EntityOfSets e join e.sortedSetOfBasics b" ), + EntityOfSets.class.getName() + ".sortedSetOfBasics", + "b" + ); // todo : ManyToMany not properly handled atm } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityOfSets.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityOfSets.java index c11a1b7592..44feda66ca 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityOfSets.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/domain/gambit/EntityOfSets.java @@ -8,6 +8,7 @@ package org.hibernate.testing.orm.domain.gambit; import java.util.HashSet; import java.util.Set; +import java.util.SortedSet; import javax.persistence.CollectionTable; import javax.persistence.ElementCollection; import javax.persistence.Entity; @@ -17,6 +18,7 @@ import javax.persistence.OneToMany; import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollectionOption; +import org.hibernate.annotations.SortNatural; /** * @author Steve Ebersole @@ -31,6 +33,8 @@ public class EntityOfSets { private Set setOfOneToMany; private Set setOfManyToMany; + private SortedSet sortedSetOfBasics; + public EntityOfSets() { } @@ -103,4 +107,14 @@ public class EntityOfSets { this.setOfManyToMany = setOfManyToMany; } + @ElementCollection() + @CollectionTable( name = "EntityOfSet_sortedBasics") + @SortNatural + public SortedSet getSortedSetOfBasics() { + return sortedSetOfBasics; + } + + public void setSortedSetOfBasics(SortedSet sortedSetOfBasics) { + this.sortedSetOfBasics = sortedSetOfBasics; + } }