Wire up custom collection types

This commit is contained in:
Christian Beikov 2021-08-09 11:25:09 +02:00
parent ffff90757a
commit 1544493edc
11 changed files with 261 additions and 49 deletions

View File

@ -213,7 +213,7 @@ public class FilterTest extends BaseEntityManagerFunctionalTestCase {
)
@Filter(
name="activeAccount",
condition="{a}.active_status = :active"
condition="active_status = :active"
)
private List<Account> accounts = new ArrayList<>( );

View File

@ -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 <code>CollectionType</code>.
*
* @author Christian Beikov
*/
public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics<CE, E> {
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<E> getElementIterator(CE rawCollection) {
return collectionType.getElementsIterator( rawCollection, null );
}
@Override
public void visitElements(CE rawCollection, Consumer<? super E> 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<E> instantiateWrapper(
Object key,
CollectionPersister collectionDescriptor,
SharedSessionContractImplementor session) {
return collectionType.instantiate( session, collectionDescriptor, key );
}
@Override
public PersistentCollection<E> wrap(
CE rawCollection,
CollectionPersister collectionDescriptor,
SharedSessionContractImplementor session) {
return collectionType.wrap( session, rawCollection );
}
}

View File

@ -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();
}
}

View File

@ -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() );

View File

@ -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);
}

View File

@ -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 ) {

View File

@ -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);
}

View File

@ -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() );
}

View File

@ -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() );

View File

@ -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);
}

View File

@ -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() );