diff --git a/documentation/src/test/java/org/hibernate/userguide/pc/FilterTest.java b/documentation/src/test/java/org/hibernate/userguide/pc/FilterTest.java index d3b185d6b0..c13f2db15e 100644 --- a/documentation/src/test/java/org/hibernate/userguide/pc/FilterTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/pc/FilterTest.java @@ -213,7 +213,7 @@ public class FilterTest extends BaseEntityManagerFunctionalTestCase { ) @Filter( name="activeAccount", - condition="{a}.active_status = :active" + condition="active_status = :active" ) private List accounts = new ArrayList<>( ); diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java new file mode 100644 index 0000000000..f9d241bec3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/CustomCollectionTypeSemantics.java @@ -0,0 +1,165 @@ +/* + * 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 http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.collection.internal; + +import java.util.Iterator; +import java.util.function.Consumer; + +import org.hibernate.collection.spi.CollectionInitializerProducer; +import org.hibernate.collection.spi.CollectionSemantics; +import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.FetchTiming; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.CollectionClassification; +import org.hibernate.metamodel.mapping.CollectionPart; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.collection.internal.BagInitializerProducer; +import org.hibernate.sql.results.graph.collection.internal.ListInitializerProducer; +import org.hibernate.sql.results.graph.collection.internal.MapInitializerProducer; +import org.hibernate.type.CollectionType; + +/** + * A collection semantics wrapper for CollectionType. + * + * @author Christian Beikov + */ +public class CustomCollectionTypeSemantics implements CollectionSemantics { + + private final CollectionType collectionType; + + public CustomCollectionTypeSemantics(CollectionType collectionType) { + this.collectionType = collectionType; + } + + @Override + public CollectionClassification getCollectionClassification() { + return CollectionClassification.BAG; + } + + @Override + public Class getCollectionJavaType() { + return collectionType.getReturnedClass(); + } + + @Override + public CE instantiateRaw(int anticipatedSize, CollectionPersister collectionDescriptor) { + return (CE) collectionType.instantiate( anticipatedSize ); + } + + @Override + public Iterator getElementIterator(CE rawCollection) { + return collectionType.getElementsIterator( rawCollection, null ); + } + + @Override + public void visitElements(CE rawCollection, Consumer action) { + getElementIterator( rawCollection ).forEachRemaining( action ); + } + + @Override + public CollectionInitializerProducer createInitializerProducer( + NavigablePath navigablePath, + PluralAttributeMapping attributeMapping, + FetchParent fetchParent, + boolean selected, + String resultVariable, + DomainResultCreationState creationState) { + final Fetch indexFetch; + if ( attributeMapping.getIndexDescriptor() == null ) { + indexFetch = null; + } + else { + indexFetch = fetchParent.generateFetchableFetch( + attributeMapping.getIndexDescriptor(), + navigablePath.append( CollectionPart.Nature.INDEX.getName() ), + FetchTiming.IMMEDIATE, + selected, + null, + creationState + ); + } + final Fetch elementFetch = fetchParent.generateFetchableFetch( + attributeMapping.getElementDescriptor(), + navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), + FetchTiming.IMMEDIATE, + selected, + null, + creationState + ); + if ( indexFetch == null ) { + return new BagInitializerProducer( attributeMapping, null, elementFetch ); + } + else if ( indexFetch.getResultJavaTypeDescriptor().getJavaTypeClass() == Integer.class ) { + return new ListInitializerProducer( attributeMapping, indexFetch, elementFetch ); + } + else { + return new MapInitializerProducer( attributeMapping, indexFetch, elementFetch ); + } + } + + @Override + public CollectionInitializerProducer createInitializerProducer( + NavigablePath navigablePath, + PluralAttributeMapping attributeMapping, + FetchParent fetchParent, + boolean selected, + String resultVariable, + Fetch indexFetch, + Fetch elementFetch, + DomainResultCreationState creationState) { + if ( indexFetch == null ) { + indexFetch = fetchParent.generateFetchableFetch( + attributeMapping.getIndexDescriptor(), + navigablePath.append( CollectionPart.Nature.INDEX.getName() ), + FetchTiming.IMMEDIATE, + selected, + null, + creationState + ); + } + if ( elementFetch == null ) { + elementFetch = fetchParent.generateFetchableFetch( + attributeMapping.getElementDescriptor(), + navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), + FetchTiming.IMMEDIATE, + selected, + null, + creationState + ); + } + if ( indexFetch == null ) { + return new BagInitializerProducer( attributeMapping, null, elementFetch ); + } + else if ( indexFetch.getResultJavaTypeDescriptor().getJavaTypeClass() == Integer.class ) { + return new ListInitializerProducer( attributeMapping, indexFetch, elementFetch ); + } + else { + return new MapInitializerProducer( attributeMapping, indexFetch, elementFetch ); + } + } + + @Override + public PersistentCollection instantiateWrapper( + Object key, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return collectionType.instantiate( session, collectionDescriptor, key ); + } + + @Override + public PersistentCollection wrap( + CE rawCollection, + CollectionPersister collectionDescriptor, + SharedSessionContractImplementor session) { + return collectionType.wrap( session, rawCollection ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardCollectionSemanticsResolver.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardCollectionSemanticsResolver.java index a5de6c2450..5adecb7809 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardCollectionSemanticsResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardCollectionSemanticsResolver.java @@ -31,53 +31,6 @@ public class StandardCollectionSemanticsResolver implements CollectionSemanticsR @Override public CollectionSemantics resolveRepresentation(Collection bootDescriptor) { - if ( bootDescriptor instanceof PrimitiveArray ) { - return StandardArraySemantics.INSTANCE; - } - - if ( bootDescriptor instanceof Array ) { - return StandardArraySemantics.INSTANCE; - } - - if ( bootDescriptor instanceof Bag ) { - return StandardBagSemantics.INSTANCE; - } - - if ( bootDescriptor instanceof IdentifierBag ) { - return StandardIdentifierBagSemantics.INSTANCE; - } - - if ( bootDescriptor instanceof List ) { - return StandardListSemantics.INSTANCE; - } - - if ( bootDescriptor instanceof Map ) { - if ( bootDescriptor.isSorted() ) { - return StandardSortedMapSemantics.INSTANCE; - } - - if ( bootDescriptor.hasOrder() ) { - return StandardOrderedMapSemantics.INSTANCE; - } - - return StandardMapSemantics.INSTANCE; - } - - if ( bootDescriptor instanceof Set ) { - if ( bootDescriptor.isSorted() ) { - return StandardSortedSetSemantics.INSTANCE; - } - - if ( bootDescriptor.hasOrder() ) { - return StandardOrderedSetSemantics.INSTANCE; - } - - return StandardSetSemantics.INSTANCE; - } - - throw new MappingException( - "Unexpected org.hibernate.mapping.Collection impl [" - + bootDescriptor + "]; unknown CollectionSemantics" - ); + return bootDescriptor.getCollectionSemantics(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Array.java b/hibernate-core/src/main/java/org/hibernate/mapping/Array.java index 4cd5c250e6..474d23d2d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Array.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Array.java @@ -10,6 +10,8 @@ import org.hibernate.MappingException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardArraySemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.type.ArrayType; import org.hibernate.type.CollectionType; import org.hibernate.type.PrimitiveType; @@ -46,6 +48,11 @@ public class Array extends List { } } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + return StandardArraySemantics.INSTANCE; + } + @Override public CollectionType getDefaultCollectionType() throws MappingException { return new ArrayType( getTypeConfiguration(), getRole(), getReferencedPropertyName(), getElementClass() ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java b/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java index 5de48f7a63..4f3591e02b 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Bag.java @@ -7,6 +7,8 @@ package org.hibernate.mapping; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardBagSemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.type.BagType; import org.hibernate.type.CollectionType; @@ -28,6 +30,11 @@ public class Bag extends Collection { //create an index on the key columns?? } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + return StandardBagSemantics.INSTANCE; + } + public Object accept(ValueVisitor visitor) { return visitor.accept(this); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java index 1d9d0b1dc8..92e2b76932 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java @@ -20,6 +20,8 @@ import org.hibernate.MappingException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.collection.internal.CustomCollectionTypeSemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.FilterConfiguration; @@ -388,6 +390,29 @@ public abstract class Collection implements Fetchable, Value, Filterable { return getCollectionType(); } + public CollectionSemantics getCollectionSemantics() { + if ( typeName == null ) { + return getDefaultCollectionSemantics(); + } + else { + final CollectionType collectionType = MappingHelper.customCollection( + typeName, + typeParameters, + role, + referencedPropertyName, + getMetadata() + ); + return new CustomCollectionTypeSemantics( collectionType ); + } + } + + public CollectionSemantics getDefaultCollectionSemantics() { + throw new MappingException( + "Unexpected org.hibernate.mapping.Collection impl [" + + this + "]; unknown CollectionSemantics" + ); + } + public CollectionType getCollectionType() { // todo (6.0) : hook in CollectionSemantics if ( typeName == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java index 35ffe02b56..7aea4b2539 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/IdentifierBag.java @@ -7,6 +7,8 @@ package org.hibernate.mapping; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardIdentifierBagSemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.type.CollectionType; import org.hibernate.type.IdentifierBagType; @@ -23,6 +25,11 @@ public class IdentifierBag extends IdentifierCollection { return new IdentifierBagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() ); } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + return StandardIdentifierBagSemantics.INSTANCE; + } + public Object accept(ValueVisitor visitor) { return visitor.accept(this); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/List.java b/hibernate-core/src/main/java/org/hibernate/mapping/List.java index d5abd42901..4bc5eb3d7e 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/List.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/List.java @@ -8,6 +8,8 @@ package org.hibernate.mapping; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardListSemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.type.CollectionType; import org.hibernate.type.ListType; @@ -28,6 +30,11 @@ public class List extends IndexedCollection { super( buildingContext, owner ); } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + return StandardListSemantics.INSTANCE; + } + public CollectionType getDefaultCollectionType() throws MappingException { return new ListType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Map.java b/hibernate-core/src/main/java/org/hibernate/mapping/Map.java index a51a4e785d..41abd552fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Map.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Map.java @@ -8,6 +8,10 @@ package org.hibernate.mapping; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardMapSemantics; +import org.hibernate.collection.internal.StandardOrderedMapSemantics; +import org.hibernate.collection.internal.StandardSortedMapSemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.type.CollectionType; import org.hibernate.type.MapType; import org.hibernate.type.OrderedMapType; @@ -26,6 +30,19 @@ public class Map extends IndexedCollection { return true; } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + if ( isSorted() ) { + return StandardSortedMapSemantics.INSTANCE; + } + + if ( hasOrder() ) { + return StandardOrderedMapSemantics.INSTANCE; + } + + return StandardMapSemantics.INSTANCE; + } + public CollectionType getDefaultCollectionType() { if ( isSorted() ) { return new SortedMapType( getTypeConfiguration(), getRole(), getReferencedPropertyName(), getComparator() ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java b/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java index 77055c30df..fd8b3a80d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PrimitiveArray.java @@ -7,6 +7,8 @@ package org.hibernate.mapping; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardArraySemantics; +import org.hibernate.collection.spi.CollectionSemantics; /** * A primitive array has a primary key consisting of the key columns + index column. @@ -20,6 +22,11 @@ public class PrimitiveArray extends Array { return true; } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + return StandardArraySemantics.INSTANCE; + } + public Object accept(ValueVisitor visitor) { return visitor.accept(this); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Set.java b/hibernate-core/src/main/java/org/hibernate/mapping/Set.java index 8941fb8a97..8d5cd675d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Set.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Set.java @@ -10,6 +10,10 @@ import java.util.Iterator; import org.hibernate.MappingException; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.collection.internal.StandardOrderedSetSemantics; +import org.hibernate.collection.internal.StandardSetSemantics; +import org.hibernate.collection.internal.StandardSortedSetSemantics; +import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.spi.Mapping; import org.hibernate.type.CollectionType; import org.hibernate.type.OrderedSetType; @@ -43,6 +47,19 @@ public class Set extends Collection { return true; } + @Override + public CollectionSemantics getDefaultCollectionSemantics() { + if ( isSorted() ) { + return StandardSortedSetSemantics.INSTANCE; + } + + if ( hasOrder() ) { + return StandardOrderedSetSemantics.INSTANCE; + } + + return StandardSetSemantics.INSTANCE; + } + public CollectionType getDefaultCollectionType() { if ( isSorted() ) { return new SortedSetType( getTypeConfiguration(), getRole(), getReferencedPropertyName(), getComparator() );