`@CollectionType` + better CollectionSemantics resolution handling from annotations;
HHH-9688 - Combination of @OrderBy and @SortComparator HHH-9688 was simple change in the code I was working on already, so went ahead and just did it
This commit is contained in:
parent
e16c78f7ea
commit
452f114957
|
@ -31,8 +31,7 @@ public @interface CollectionType {
|
|||
* Names the type.
|
||||
*
|
||||
* Could name the implementation class (an implementation of {@link org.hibernate.type.CollectionType} or
|
||||
* {@link org.hibernate.usertype.UserCollectionType}). Could also name a custom type defined via a
|
||||
* {@link TypeDef @TypeDef}
|
||||
* {@link org.hibernate.usertype.UserCollectionType}).
|
||||
*/
|
||||
String type();
|
||||
|
||||
|
|
|
@ -2028,7 +2028,6 @@ public final class AnnotationBinder {
|
|||
);
|
||||
}
|
||||
CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(
|
||||
propertyHolder.getEntityName(),
|
||||
property,
|
||||
!indexColumn.isImplicit(),
|
||||
// ugh
|
||||
|
@ -2060,7 +2059,6 @@ public final class AnnotationBinder {
|
|||
boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
|
||||
collectionBinder.setIgnoreNotFound( ignoreNotFound );
|
||||
collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
|
||||
collectionBinder.setBuildingContext( context );
|
||||
collectionBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||
|
||||
Ejb3Column[] elementColumns;
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.mapping.Array;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
|
||||
/**
|
||||
* Bind an Array
|
||||
|
@ -16,11 +18,11 @@ import org.hibernate.mapping.PersistentClass;
|
|||
* @author Anthony Patricio
|
||||
*/
|
||||
public class ArrayBinder extends ListBinder {
|
||||
|
||||
public ArrayBinder() {
|
||||
public ArrayBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, buildingContext );
|
||||
}
|
||||
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new Array( getBuildingContext(), persistentClass );
|
||||
protected Collection createCollection(PersistentClass owner) {
|
||||
return new Array( getSemanticsResolver(), owner, getBuildingContext() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
|
||||
/**
|
||||
* Bind a bag.
|
||||
|
@ -14,11 +17,11 @@ import org.hibernate.mapping.PersistentClass;
|
|||
* @author Matthew Inger
|
||||
*/
|
||||
public class BagBinder extends CollectionBinder {
|
||||
public BagBinder() {
|
||||
super( false );
|
||||
public BagBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext context) {
|
||||
super( semanticsResolver, false, context );
|
||||
}
|
||||
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new org.hibernate.mapping.Bag( getBuildingContext(), persistentClass );
|
||||
protected Collection createCollection(PersistentClass owner) {
|
||||
return new org.hibernate.mapping.Bag( getSemanticsResolver(), owner, getBuildingContext() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,11 +72,13 @@ import org.hibernate.cfg.PropertyHolderBuilder;
|
|||
import org.hibernate.cfg.PropertyInferredData;
|
||||
import org.hibernate.cfg.PropertyPreloadedData;
|
||||
import org.hibernate.cfg.SecondPass;
|
||||
import org.hibernate.collection.internal.CustomCollectionTypeSemantics;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.jpa.spi.MutableJpaCompliance;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.Backref;
|
||||
import org.hibernate.mapping.Collection;
|
||||
|
@ -89,8 +91,10 @@ import org.hibernate.mapping.ManyToOne;
|
|||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.EmbeddableInstantiator;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -134,7 +138,9 @@ public abstract class CollectionBinder {
|
|||
java.util.Collection.class
|
||||
);
|
||||
|
||||
private MetadataBuildingContext buildingContext;
|
||||
private final MetadataBuildingContext buildingContext;
|
||||
private final SemanticsResolver semanticsResolver;
|
||||
private final boolean isSortedCollection;
|
||||
|
||||
protected Collection collection;
|
||||
protected String propertyName;
|
||||
|
@ -169,7 +175,6 @@ public abstract class CollectionBinder {
|
|||
private AccessType accessType;
|
||||
private boolean hibernateExtensionMapping;
|
||||
|
||||
private boolean isSortedCollection;
|
||||
private jakarta.persistence.OrderBy jpaOrderBy;
|
||||
private OrderBy sqlOrderBy;
|
||||
private SortNatural naturalSort;
|
||||
|
@ -178,16 +183,18 @@ public abstract class CollectionBinder {
|
|||
private String explicitType;
|
||||
private final Properties explicitTypeParameters = new Properties();
|
||||
|
||||
protected CollectionBinder(boolean isSortedCollection) {
|
||||
protected CollectionBinder(SemanticsResolver semanticsResolver, boolean isSortedCollection, MetadataBuildingContext buildingContext) {
|
||||
this.semanticsResolver = semanticsResolver;
|
||||
this.isSortedCollection = isSortedCollection;
|
||||
this.buildingContext = buildingContext;
|
||||
}
|
||||
|
||||
protected MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
|
||||
public void setBuildingContext(MetadataBuildingContext buildingContext) {
|
||||
this.buildingContext = buildingContext;
|
||||
protected SemanticsResolver getSemanticsResolver() {
|
||||
return semanticsResolver;
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
|
@ -260,151 +267,185 @@ public abstract class CollectionBinder {
|
|||
* collection binder factory
|
||||
*/
|
||||
public static CollectionBinder getCollectionBinder(
|
||||
String entityName,
|
||||
XProperty property,
|
||||
boolean isIndexed,
|
||||
boolean isHibernateExtensionMapping,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final CollectionBinder result;
|
||||
|
||||
if ( property.isArray() ) {
|
||||
if ( property.getElementClass().isPrimitive() ) {
|
||||
result = new PrimitiveArrayBinder();
|
||||
}
|
||||
else {
|
||||
result = new ArrayBinder();
|
||||
}
|
||||
}
|
||||
else if ( property.isCollection() ) {
|
||||
//TODO consider using an XClass
|
||||
final Class<?> returnedClass = property.getCollectionClass();
|
||||
|
||||
final CollectionBinder basicBinder = getBinderFromBasicCollectionType(
|
||||
returnedClass,
|
||||
property,
|
||||
entityName,
|
||||
isIndexed
|
||||
);
|
||||
if ( basicBinder != null ) {
|
||||
result = basicBinder;
|
||||
}
|
||||
else if ( property.isAnnotationPresent( CollectionType.class ) ) {
|
||||
Class<?> semanticsClass = property.getAnnotation( CollectionType.class ).semantics();
|
||||
|
||||
if ( semanticsClass != void.class ) {
|
||||
result = getBinderFromBasicCollectionType( semanticsClass, property, entityName, isIndexed );
|
||||
}
|
||||
else {
|
||||
final Class<?> inferredClass = inferCollectionClassFromSubclass( returnedClass );
|
||||
result = inferredClass != null ? getBinderFromBasicCollectionType(
|
||||
inferredClass,
|
||||
property,
|
||||
entityName,
|
||||
isIndexed
|
||||
) : null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = null;
|
||||
}
|
||||
if ( result == null ) {
|
||||
throw new AnnotationException(
|
||||
returnedClass.getName() + " collection type not supported for property: "
|
||||
+ StringHelper.qualify( entityName, property.getName() )
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new AnnotationException(
|
||||
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @ElementCollection: "
|
||||
+ StringHelper.qualify( entityName, property.getName() )
|
||||
);
|
||||
}
|
||||
result.setIsHibernateExtensionMapping( isHibernateExtensionMapping );
|
||||
|
||||
final CollectionType typeAnnotation = property.getAnnotation( CollectionType.class );
|
||||
|
||||
final CollectionBinder binder;
|
||||
if ( typeAnnotation != null ) {
|
||||
final String typeName = typeAnnotation.type();
|
||||
// see if it names a type-def
|
||||
final TypeDefinition typeDef = buildingContext.getMetadataCollector().getTypeDefinition( typeName );
|
||||
if ( typeDef != null ) {
|
||||
result.explicitType = typeDef.getTypeImplementorClass().getName();
|
||||
result.explicitTypeParameters.putAll( typeDef.getParameters() );
|
||||
binder = createBinderFromCustomTypeAnnotation( property, isIndexed, typeAnnotation, buildingContext );
|
||||
}
|
||||
else {
|
||||
result.explicitType = typeName;
|
||||
binder = createBinderFromProperty( property, isIndexed, buildingContext );
|
||||
}
|
||||
|
||||
binder.setIsHibernateExtensionMapping( isHibernateExtensionMapping );
|
||||
|
||||
if ( typeAnnotation != null ) {
|
||||
binder.explicitType = typeAnnotation.type();
|
||||
for ( Parameter param : typeAnnotation.parameters() ) {
|
||||
result.explicitTypeParameters.setProperty( param.name(), param.value() );
|
||||
}
|
||||
binder.explicitTypeParameters.setProperty( param.name(), param.value() );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return binder;
|
||||
}
|
||||
|
||||
private static CollectionBinder getBinderFromBasicCollectionType(Class<?> clazz, XProperty property,
|
||||
String entityName, boolean isIndexed) {
|
||||
if ( java.util.Set.class.equals( clazz) ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class) ) {
|
||||
throw new AnnotationException("Set does not support @CollectionId: "
|
||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
||||
private static CollectionBinder createBinderFromProperty(
|
||||
XProperty property,
|
||||
boolean isIndexed,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final CollectionClassification classification = determineCollectionClassification( property, null, isIndexed, buildingContext );
|
||||
return createBinder( property, classification, null, buildingContext );
|
||||
}
|
||||
return new SetBinder( false );
|
||||
|
||||
private static CollectionBinder createBinderFromCustomTypeAnnotation(
|
||||
XProperty property,
|
||||
boolean isIndexed,
|
||||
CollectionType typeAnnotation,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
final CollectionClassification classification = determineCollectionClassification( property, typeAnnotation, isIndexed, buildingContext );
|
||||
final SemanticsResolver semanticsResolver = (collectionType) -> new CustomCollectionTypeSemantics<>( collectionType, classification );
|
||||
return createBinder( property, classification, semanticsResolver, buildingContext );
|
||||
}
|
||||
else if ( java.util.SortedSet.class.equals( clazz ) ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
throw new AnnotationException( "SortedSet does not support @CollectionId: "
|
||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
||||
|
||||
private static CollectionBinder createBinder(
|
||||
XProperty property,
|
||||
CollectionClassification classification,
|
||||
SemanticsResolver semanticsResolver,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
|
||||
switch ( classification ) {
|
||||
case ARRAY: {
|
||||
if ( property.getElementClass().isPrimitive() ) {
|
||||
return new PrimitiveArrayBinder( semanticsResolver, buildingContext );
|
||||
}
|
||||
return new SetBinder( true );
|
||||
return new ArrayBinder( semanticsResolver, buildingContext );
|
||||
}
|
||||
else if ( Map.class.equals( clazz ) ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
throw new AnnotationException( "Map does not support @CollectionId: "
|
||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
||||
case BAG: {
|
||||
return new BagBinder( semanticsResolver, buildingContext );
|
||||
}
|
||||
return new MapBinder( false );
|
||||
case IDBAG: {
|
||||
return new IdBagBinder( semanticsResolver, buildingContext );
|
||||
}
|
||||
else if ( java.util.SortedMap.class.equals( clazz ) ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
throw new AnnotationException( "SortedMap does not support @CollectionId: "
|
||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
||||
case LIST: {
|
||||
return new ListBinder( semanticsResolver, buildingContext );
|
||||
}
|
||||
return new MapBinder( true );
|
||||
case MAP:
|
||||
case ORDERED_MAP: {
|
||||
return new MapBinder( semanticsResolver, false, buildingContext );
|
||||
}
|
||||
else if ( java.util.Collection.class.equals( clazz ) ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
return new IdBagBinder();
|
||||
case SORTED_MAP: {
|
||||
return new MapBinder( semanticsResolver, true, buildingContext );
|
||||
}
|
||||
else {
|
||||
return new BagBinder();
|
||||
case SET:
|
||||
case ORDERED_SET: {
|
||||
return new SetBinder( semanticsResolver, false, buildingContext );
|
||||
}
|
||||
case SORTED_SET: {
|
||||
return new SetBinder( semanticsResolver, true, buildingContext );
|
||||
}
|
||||
}
|
||||
else if ( List.class.equals( clazz ) ) {
|
||||
if ( isIndexed ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
|
||||
final XClass declaringClass = property.getDeclaringClass();
|
||||
|
||||
throw new AnnotationException(
|
||||
"List does not support @CollectionId and @OrderColumn (or @IndexColumn) at the same time: "
|
||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to determine proper CollectionBinder (`%s) : %s.%s",
|
||||
classification,
|
||||
declaringClass.getName(),
|
||||
property.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
return new ListBinder();
|
||||
|
||||
private static CollectionClassification determineCollectionClassification(
|
||||
XProperty property,
|
||||
CollectionType typeAnnotation,
|
||||
boolean isIndexed,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
if ( property.isArray() ) {
|
||||
return CollectionClassification.ARRAY;
|
||||
}
|
||||
else if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
return new IdBagBinder();
|
||||
|
||||
return determineCollectionClassification(
|
||||
determineSemanticJavaType( property, typeAnnotation, isIndexed, buildingContext ),
|
||||
property
|
||||
);
|
||||
}
|
||||
|
||||
private static CollectionClassification determineCollectionClassification(Class<?> semanticJavaType, XProperty property) {
|
||||
if ( semanticJavaType.isArray() ) {
|
||||
return CollectionClassification.ARRAY;
|
||||
}
|
||||
else if ( java.util.List.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
return CollectionClassification.LIST;
|
||||
}
|
||||
else if ( java.util.SortedSet.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
return CollectionClassification.SORTED_SET;
|
||||
}
|
||||
else if ( java.util.Set.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
return CollectionClassification.SET;
|
||||
}
|
||||
else if ( java.util.SortedMap.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
return CollectionClassification.SORTED_MAP;
|
||||
}
|
||||
else if ( java.util.Map.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
return CollectionClassification.MAP;
|
||||
}
|
||||
else if ( java.util.Collection.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
||||
return CollectionClassification.IDBAG;
|
||||
}
|
||||
else {
|
||||
return new BagBinder();
|
||||
return CollectionClassification.BAG;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> determineSemanticJavaType(XProperty property, CollectionType typeAnnotation, boolean isIndexed, MetadataBuildingContext buildingContext) {
|
||||
final Class<?> returnedJavaType = property.getCollectionClass();
|
||||
if ( typeAnnotation != null ) {
|
||||
final Class<?> requestedSemanticsJavaType = typeAnnotation.semantics();
|
||||
if ( requestedSemanticsJavaType != null && requestedSemanticsJavaType != void.class ) {
|
||||
return inferCollectionClassFromSubclass( requestedSemanticsJavaType, isIndexed, buildingContext );
|
||||
}
|
||||
}
|
||||
|
||||
if ( returnedJavaType == null ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: %s.%s",
|
||||
property.getDeclaringClass().getName(),
|
||||
property.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return inferCollectionClassFromSubclass( returnedJavaType, isIndexed, buildingContext );
|
||||
}
|
||||
|
||||
private static Class<?> inferCollectionClassFromSubclass(Class<?> clazz, boolean isIndexed, MetadataBuildingContext buildingContext) {
|
||||
if ( java.util.List.class.isAssignableFrom( clazz ) && !isIndexed ) {
|
||||
final MutableJpaCompliance jpaCompliance = buildingContext.getBootstrapContext().getJpaCompliance();
|
||||
return jpaCompliance.isJpaListComplianceEnabled()
|
||||
? java.util.List.class
|
||||
: java.util.Collection.class;
|
||||
}
|
||||
|
||||
private static Class<?> inferCollectionClassFromSubclass(Class<?> clazz) {
|
||||
for ( Class<?> priorityClass : INFERRED_CLASS_PRIORITY ) {
|
||||
if ( priorityClass.isAssignableFrom( clazz ) ) {
|
||||
return priorityClass;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -488,7 +529,8 @@ public abstract class CollectionBinder {
|
|||
|
||||
Persister persisterAnn = property.getAnnotation( Persister.class );
|
||||
if ( persisterAnn != null ) {
|
||||
collection.setCollectionPersisterClass( persisterAnn.impl() );
|
||||
//noinspection rawtypes
|
||||
collection.setCollectionPersisterClass( (Class) persisterAnn.impl() );
|
||||
}
|
||||
|
||||
applySortingAndOrdering( collection );
|
||||
|
@ -614,37 +656,32 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
|
||||
private void applySortingAndOrdering(Collection collection) {
|
||||
boolean hadOrderBy = false;
|
||||
boolean hadExplicitSort = false;
|
||||
final boolean hadExplicitSort;
|
||||
final Class<? extends Comparator<?>> comparatorClass;
|
||||
|
||||
Class<? extends Comparator<?>> comparatorClass = null;
|
||||
|
||||
if ( jpaOrderBy == null && sqlOrderBy == null ) {
|
||||
if ( naturalSort != null ) {
|
||||
if ( comparatorSort != null ) {
|
||||
throw buildIllegalSortCombination();
|
||||
}
|
||||
hadExplicitSort = true;
|
||||
comparatorClass = null;
|
||||
}
|
||||
else if ( comparatorSort != null ) {
|
||||
hadExplicitSort = true;
|
||||
comparatorClass = comparatorSort.value();
|
||||
}
|
||||
}
|
||||
else {
|
||||
hadExplicitSort = false;
|
||||
comparatorClass = null;
|
||||
}
|
||||
|
||||
boolean hadOrderBy = false;
|
||||
if ( jpaOrderBy != null || sqlOrderBy != null ) {
|
||||
if ( jpaOrderBy != null && sqlOrderBy != null ) {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
"Illegal combination of @%s and @%s on %s",
|
||||
jakarta.persistence.OrderBy.class.getName(),
|
||||
OrderBy.class.getName(),
|
||||
safeCollectionRole()
|
||||
)
|
||||
);
|
||||
throw buildIllegalOrderCombination();
|
||||
}
|
||||
|
||||
hadOrderBy = true;
|
||||
hadExplicitSort = false;
|
||||
|
||||
// we can only apply the sql-based order by up front. The jpa order by has to wait for second pass
|
||||
if ( sqlOrderBy != null ) {
|
||||
|
@ -652,7 +689,13 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
collection.setSorted( isSortedCollection || hadExplicitSort );
|
||||
final boolean isSorted = isSortedCollection || hadExplicitSort;
|
||||
|
||||
if ( isSorted && hadOrderBy ) {
|
||||
throw buildIllegalOrderAndSortCombination();
|
||||
}
|
||||
|
||||
collection.setSorted( isSorted );
|
||||
|
||||
if ( comparatorClass != null ) {
|
||||
try {
|
||||
|
@ -670,10 +713,36 @@ public abstract class CollectionBinder {
|
|||
}
|
||||
}
|
||||
|
||||
private AnnotationException buildIllegalOrderCombination() {
|
||||
return new AnnotationException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Illegal combination of ordering and sorting annotations (`%s`) - only one of `@%s` and `@%s` may be used",
|
||||
jakarta.persistence.OrderBy.class.getName(),
|
||||
OrderBy.class.getName(),
|
||||
safeCollectionRole()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private AnnotationException buildIllegalOrderAndSortCombination() {
|
||||
throw new AnnotationException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Illegal combination of ordering and sorting annotations (`%s`) - only one of `@%s`, `@%s`, `@%s` and `@%s` can be used",
|
||||
safeCollectionRole(),
|
||||
jakarta.persistence.OrderBy.class.getName(),
|
||||
OrderBy.class.getName(),
|
||||
SortComparator.class.getName(),
|
||||
SortNatural.class.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private AnnotationException buildIllegalSortCombination() {
|
||||
return new AnnotationException(
|
||||
String.format(
|
||||
"Illegal combination of annotations on %s. Only one of @%s and @%s can be used",
|
||||
"Illegal combination of sorting annotations (`%s`) - only one of `@%s` and `@%s` can be used",
|
||||
safeCollectionRole(),
|
||||
SortNatural.class.getName(),
|
||||
SortComparator.class.getName()
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.mapping.BasicValue;
|
|||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.IdentifierCollection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
|
@ -34,11 +35,12 @@ import jakarta.persistence.Column;
|
|||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class IdBagBinder extends BagBinder {
|
||||
public IdBagBinder() {
|
||||
public IdBagBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, buildingContext );
|
||||
}
|
||||
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new org.hibernate.mapping.IdentifierBag( getBuildingContext(), persistentClass );
|
||||
protected Collection createCollection(PersistentClass owner) {
|
||||
return new org.hibernate.mapping.IdentifierBag( getSemanticsResolver(), owner, getBuildingContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.hibernate.mapping.IndexBackref;
|
|||
import org.hibernate.mapping.List;
|
||||
import org.hibernate.mapping.OneToMany;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -41,13 +42,13 @@ import org.jboss.logging.Logger;
|
|||
public class ListBinder extends CollectionBinder {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, ListBinder.class.getName() );
|
||||
|
||||
public ListBinder() {
|
||||
super( false );
|
||||
public ListBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, false, buildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new List( getBuildingContext(), persistentClass );
|
||||
protected Collection createCollection(PersistentClass owner) {
|
||||
return new List( getSemanticsResolver(), owner, getBuildingContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,15 +9,6 @@ package org.hibernate.cfg.annotations;
|
|||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import jakarta.persistence.AttributeOverride;
|
||||
import jakarta.persistence.AttributeOverrides;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
import jakarta.persistence.InheritanceType;
|
||||
import jakarta.persistence.MapKeyClass;
|
||||
import jakarta.persistence.MapKeyColumn;
|
||||
import jakarta.persistence.MapKeyJoinColumn;
|
||||
import jakarta.persistence.MapKeyJoinColumns;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
|
@ -40,27 +31,32 @@ import org.hibernate.cfg.PropertyData;
|
|||
import org.hibernate.cfg.PropertyHolderBuilder;
|
||||
import org.hibernate.cfg.PropertyPreloadedData;
|
||||
import org.hibernate.cfg.SecondPass;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.DependantBasicValue;
|
||||
import org.hibernate.mapping.DependantValue;
|
||||
import org.hibernate.mapping.Formula;
|
||||
import org.hibernate.mapping.ManyToOne;
|
||||
import org.hibernate.mapping.OneToMany;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.sql.Template;
|
||||
|
||||
import jakarta.persistence.AttributeOverride;
|
||||
import jakarta.persistence.AttributeOverrides;
|
||||
import jakarta.persistence.ConstraintMode;
|
||||
import jakarta.persistence.InheritanceType;
|
||||
import jakarta.persistence.MapKeyClass;
|
||||
import jakarta.persistence.MapKeyColumn;
|
||||
import jakarta.persistence.MapKeyJoinColumn;
|
||||
import jakarta.persistence.MapKeyJoinColumns;
|
||||
|
||||
/**
|
||||
* Implementation to bind a Map
|
||||
|
@ -68,16 +64,16 @@ import org.hibernate.sql.Template;
|
|||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class MapBinder extends CollectionBinder {
|
||||
public MapBinder(boolean sorted) {
|
||||
super( sorted );
|
||||
public MapBinder(SemanticsResolver semanticsResolver, boolean sorted, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, sorted, buildingContext );
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new org.hibernate.mapping.Map( getBuildingContext(), persistentClass );
|
||||
protected Collection createCollection(PersistentClass owner) {
|
||||
return new org.hibernate.mapping.Map( getSemanticsResolver(), owner, getBuildingContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,16 +6,22 @@
|
|||
*/
|
||||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.PrimitiveArray;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class PrimitiveArrayBinder extends ArrayBinder {
|
||||
public PrimitiveArrayBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, buildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new PrimitiveArray( getBuildingContext(), persistentClass );
|
||||
protected Collection createCollection(PersistentClass owner) {
|
||||
return new PrimitiveArray( getSemanticsResolver(), owner, getBuildingContext() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
package org.hibernate.cfg.annotations;
|
||||
|
||||
import org.hibernate.annotations.OrderBy;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.SemanticsResolver;
|
||||
|
||||
/**
|
||||
* Bind a set.
|
||||
|
@ -16,13 +18,13 @@ import org.hibernate.mapping.PersistentClass;
|
|||
* @author Matthew Inger
|
||||
*/
|
||||
public class SetBinder extends CollectionBinder {
|
||||
public SetBinder(boolean sorted) {
|
||||
super( sorted );
|
||||
public SetBinder(SemanticsResolver semanticsResolver, boolean sorted, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, sorted, buildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection createCollection(PersistentClass persistentClass) {
|
||||
return new org.hibernate.mapping.Set( getBuildingContext(), persistentClass );
|
||||
return new org.hibernate.mapping.Set( getSemanticsResolver(), persistentClass, getBuildingContext() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,14 +13,12 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.collection.spi.BagSemantics;
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
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.Fetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.BagInitializerProducer;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
|
||||
|
@ -60,35 +58,6 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new BagInitializerProducer(
|
||||
attributeMapping,
|
||||
attributeMapping.getIdentifierDescriptor() == null ? null : fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIdentifierDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ID.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
),
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -99,30 +68,13 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
|||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( indexFetch == null ) {
|
||||
indexFetch = attributeMapping.getIdentifierDescriptor() == null ? null : fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIdentifierDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ID.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
|
||||
);
|
||||
}
|
||||
return new BagInitializerProducer(
|
||||
return InitializerProducerBuilder.createBagInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
indexFetch,
|
||||
elementFetch
|
||||
fetchParent,
|
||||
selected,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,13 +13,11 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||
import org.hibernate.collection.spi.MapSemantics;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.MapInitializerProducer;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
|
||||
|
@ -72,35 +70,6 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new MapInitializerProducer(
|
||||
attributeMapping,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
),
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -111,30 +80,14 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
|||
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
|
||||
);
|
||||
}
|
||||
return new MapInitializerProducer(
|
||||
return InitializerProducerBuilder.createMapInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
indexFetch,
|
||||
elementFetch
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,11 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.SetInitializerProducer;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
|
||||
/**
|
||||
|
@ -45,27 +43,6 @@ public abstract class AbstractSetSemantics<SE extends Set<E>,E> implements Colle
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new SetInitializerProducer(
|
||||
attributeMapping,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -76,16 +53,14 @@ public abstract class AbstractSetSemantics<SE extends Set<E>,E> implements Colle
|
|||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( elementFetch == null ) {
|
||||
return createInitializerProducer(
|
||||
assert indexFetch == null;
|
||||
return InitializerProducerBuilder.createSetInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
resultVariable,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
return new SetInitializerProducer( attributeMapping, elementFetch );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,20 +11,16 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -33,16 +29,17 @@ import org.hibernate.type.CollectionType;
|
|||
* @author Christian Beikov
|
||||
*/
|
||||
public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics<CE, E> {
|
||||
|
||||
private final CollectionType collectionType;
|
||||
private final CollectionClassification classification;
|
||||
|
||||
public CustomCollectionTypeSemantics(CollectionType collectionType) {
|
||||
public CustomCollectionTypeSemantics(CollectionType collectionType, CollectionClassification classification) {
|
||||
this.collectionType = collectionType;
|
||||
this.classification = classification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionClassification getCollectionClassification() {
|
||||
return CollectionClassification.BAG;
|
||||
return classification;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,11 +49,13 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
|||
|
||||
@Override
|
||||
public CE instantiateRaw(int anticipatedSize, CollectionPersister collectionDescriptor) {
|
||||
//noinspection unchecked
|
||||
return (CE) collectionType.instantiate( anticipatedSize );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> getElementIterator(CE rawCollection) {
|
||||
//noinspection unchecked
|
||||
return collectionType.getElementsIterator( rawCollection, null );
|
||||
}
|
||||
|
||||
|
@ -65,47 +64,6 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
|||
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,
|
||||
|
@ -116,42 +74,24 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
|||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( indexFetch == null ) {
|
||||
indexFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
return InitializerProducerBuilder.createCollectionTypeWrapperInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
classification,
|
||||
fetchParent,
|
||||
selected,
|
||||
null,
|
||||
indexFetch,
|
||||
elementFetch,
|
||||
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) {
|
||||
//noinspection unchecked
|
||||
return collectionType.instantiate( session, collectionDescriptor, key );
|
||||
}
|
||||
|
||||
|
@ -160,6 +100,7 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
|||
CE rawCollection,
|
||||
CollectionPersister collectionDescriptor,
|
||||
SharedSessionContractImplementor session) {
|
||||
//noinspection unchecked
|
||||
return collectionType.wrap( session, rawCollection );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,16 +12,14 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||
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.Fetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.ArrayInitializerProducer;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
|
||||
|
@ -93,35 +91,6 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new ArrayInitializerProducer(
|
||||
attributeMapping,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
),
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -132,30 +101,14 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
|||
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
|
||||
);
|
||||
}
|
||||
return new ArrayInitializerProducer(
|
||||
return InitializerProducerBuilder.createArrayInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
indexFetch,
|
||||
elementFetch
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,18 +12,16 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
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.Fetch;
|
||||
import org.hibernate.sql.results.graph.collection.internal.ListInitializerProducer;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
|
||||
/**
|
||||
|
@ -45,6 +43,7 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
return CollectionClassification.LIST;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Class<List> getCollectionJavaType() {
|
||||
return List.class;
|
||||
|
@ -67,72 +66,6 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
rawCollection.forEach( action );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new ListInitializerProducer(
|
||||
attributeMapping,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
),
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@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
|
||||
);
|
||||
}
|
||||
return new ListInitializerProducer(
|
||||
attributeMapping,
|
||||
indexFetch,
|
||||
elementFetch
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection<E> instantiateWrapper(
|
||||
Object key,
|
||||
|
@ -148,4 +81,17 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
SharedSessionContractImplementor session) {
|
||||
return new PersistentList<>( session, rawCollection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
return InitializerProducerBuilder.createListInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import java.util.Iterator;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
|
@ -36,38 +35,69 @@ public interface CollectionSemantics<CE, E> {
|
|||
*/
|
||||
CollectionClassification getCollectionClassification();
|
||||
|
||||
/**
|
||||
* The collection's Java type
|
||||
*/
|
||||
Class<?> getCollectionJavaType();
|
||||
|
||||
/**
|
||||
* Create a raw (unwrapped) version of the collection
|
||||
*/
|
||||
CE instantiateRaw(
|
||||
int anticipatedSize,
|
||||
CollectionPersister collectionDescriptor);
|
||||
|
||||
/**
|
||||
* Create a wrapper for the collection
|
||||
*/
|
||||
PersistentCollection<E> instantiateWrapper(
|
||||
Object key,
|
||||
CollectionPersister collectionDescriptor,
|
||||
SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Wrap a raw collection in wrapper
|
||||
*/
|
||||
PersistentCollection<E> wrap(
|
||||
CE rawCollection,
|
||||
CollectionPersister collectionDescriptor,
|
||||
SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Obtain an iterator over the collection elements
|
||||
*/
|
||||
Iterator<E> getElementIterator(CE rawCollection);
|
||||
|
||||
/**
|
||||
* Visit the elements of the collection
|
||||
*/
|
||||
void visitElements(CE rawCollection, Consumer<? super E> action);
|
||||
|
||||
/**
|
||||
* todo (6.0) : clean this contract up!
|
||||
* Create a producer for {@link org.hibernate.sql.results.graph.collection.CollectionInitializer}
|
||||
* instances for the given collection semantics
|
||||
*
|
||||
* @see InitializerProducerBuilder
|
||||
*/
|
||||
CollectionInitializerProducer createInitializerProducer(
|
||||
default CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState);
|
||||
DomainResultCreationState creationState) {
|
||||
return createInitializerProducer(
|
||||
navigablePath, attributeMapping, fetchParent, selected, resultVariable, null, null, creationState
|
||||
);
|
||||
}
|
||||
|
||||
CollectionInitializerProducer createInitializerProducer(
|
||||
/**
|
||||
* Create a producer for {@link org.hibernate.sql.results.graph.collection.CollectionInitializer}
|
||||
* instances for the given collection semantics
|
||||
*
|
||||
* @see InitializerProducerBuilder
|
||||
*/
|
||||
default CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
|
@ -75,5 +105,16 @@ public interface CollectionSemantics<CE, E> {
|
|||
String resultVariable,
|
||||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState);
|
||||
DomainResultCreationState creationState) {
|
||||
return InitializerProducerBuilder.createInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
getCollectionClassification(),
|
||||
fetchParent,
|
||||
selected,
|
||||
indexFetch,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* 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.spi;
|
||||
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
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.ArrayInitializerProducer;
|
||||
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.sql.results.graph.collection.internal.SetInitializerProducer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class InitializerProducerBuilder {
|
||||
public static CollectionInitializerProducer createInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
CollectionClassification classification,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
switch ( classification ) {
|
||||
case ARRAY: {
|
||||
return createArrayInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState );
|
||||
}
|
||||
case BAG:
|
||||
case IDBAG: {
|
||||
return createBagInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, elementFetch, creationState );
|
||||
}
|
||||
case LIST: {
|
||||
return createListInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState );
|
||||
}
|
||||
case MAP:
|
||||
case ORDERED_MAP:
|
||||
case SORTED_MAP: {
|
||||
return createMapInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState );
|
||||
}
|
||||
case SET:
|
||||
case ORDERED_SET:
|
||||
case SORTED_SET: {
|
||||
return createSetInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, elementFetch, creationState );
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException( "Unknown CollectionClassification : " + classification );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CollectionInitializerProducer createArrayInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
return new ArrayInitializerProducer( attributeMapping, indexFetch, elementFetch );
|
||||
}
|
||||
|
||||
public static CollectionInitializerProducer createBagInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
|
||||
final Fetch idBagIdFetch;
|
||||
if ( attributeMapping.getIdentifierDescriptor() != null ) {
|
||||
idBagIdFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIdentifierDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ID.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
idBagIdFetch = null;
|
||||
}
|
||||
|
||||
if ( elementFetch == null ) {
|
||||
elementFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
return new BagInitializerProducer( attributeMapping, idBagIdFetch, elementFetch );
|
||||
}
|
||||
|
||||
public static CollectionInitializerProducer createListInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
return new ListInitializerProducer( attributeMapping, indexFetch, elementFetch );
|
||||
}
|
||||
|
||||
public static CollectionInitializerProducer createMapInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
assert attributeMapping.getIndexDescriptor() != null;
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
return new MapInitializerProducer( attributeMapping, indexFetch, elementFetch );
|
||||
}
|
||||
|
||||
public static CollectionInitializerProducer createSetInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( elementFetch == null ) {
|
||||
elementFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
return new SetInitializerProducer( attributeMapping, elementFetch );
|
||||
}
|
||||
|
||||
public static CollectionInitializerProducer createCollectionTypeWrapperInitializerProducer(
|
||||
NavigablePath navigablePath,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
CollectionClassification classification,
|
||||
FetchParent fetchParent,
|
||||
boolean selected,
|
||||
Fetch indexFetch,
|
||||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
switch ( classification ) {
|
||||
case ARRAY: {
|
||||
return createArrayInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
indexFetch,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
case BAG:
|
||||
case IDBAG: {
|
||||
assert indexFetch == null;
|
||||
return createBagInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
case LIST: {
|
||||
return createListInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
indexFetch,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
case MAP:
|
||||
case ORDERED_MAP:
|
||||
case SORTED_MAP: {
|
||||
return createMapInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
indexFetch,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
case SET:
|
||||
case ORDERED_SET:
|
||||
case SORTED_SET: {
|
||||
return createSetInitializerProducer(
|
||||
navigablePath,
|
||||
attributeMapping,
|
||||
fetchParent,
|
||||
selected,
|
||||
elementFetch,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException( "Unknown CollectionClassification : " + classification );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InitializerProducerBuilder() {
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||
|
@ -29,7 +31,11 @@ public class Array extends List {
|
|||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
public Class getElementClass() throws MappingException {
|
||||
public Array(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public Class<?> getElementClass() throws MappingException {
|
||||
if ( elementClassName == null ) {
|
||||
final org.hibernate.type.Type elementType = getElement().getType();
|
||||
if ( isPrimitiveArray() ) {
|
||||
|
@ -51,7 +57,7 @@ public class Array extends List {
|
|||
}
|
||||
|
||||
@Override
|
||||
public CollectionSemantics getDefaultCollectionSemantics() {
|
||||
public CollectionSemantics<?,?> getDefaultCollectionSemantics() {
|
||||
return StandardArraySemantics.INSTANCE;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.collection.internal.StandardBagSemantics;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
|
@ -18,10 +20,20 @@ import org.hibernate.type.CollectionType;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public class Bag extends Collection {
|
||||
/**
|
||||
* hbm.xml binding
|
||||
*/
|
||||
public Bag(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation binding
|
||||
*/
|
||||
public Bag(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public CollectionType getDefaultCollectionType() {
|
||||
return new BagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() );
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.SortedMap;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -27,6 +29,8 @@ import org.hibernate.engine.spi.Mapping;
|
|||
import org.hibernate.internal.FilterConfiguration;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.type.CollectionType;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -63,18 +67,21 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
private String referencedPropertyName;
|
||||
private String mappedByProperty;
|
||||
private boolean sorted;
|
||||
private Comparator comparator;
|
||||
private Comparator<?> comparator;
|
||||
private String comparatorClassName;
|
||||
private boolean orphanDelete;
|
||||
private int batchSize = -1;
|
||||
private FetchMode fetchMode;
|
||||
private boolean embedded = true;
|
||||
private boolean optimisticLocked = true;
|
||||
private Class collectionPersisterClass;
|
||||
|
||||
private String typeName;
|
||||
private Properties typeParameters;
|
||||
private final List filters = new ArrayList();
|
||||
private final List manyToManyFilters = new ArrayList();
|
||||
private SemanticsResolver customSemanticsResolver;
|
||||
private Class<? extends CollectionPersister> collectionPersisterClass;
|
||||
|
||||
private final List<FilterConfiguration> filters = new ArrayList<>();
|
||||
private final List<FilterConfiguration> manyToManyFilters = new ArrayList<>();
|
||||
private final java.util.Set<String> synchronizedTables = new HashSet<>();
|
||||
|
||||
private String customSQLInsert;
|
||||
|
@ -92,11 +99,23 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
|
||||
private String loaderName;
|
||||
|
||||
/**
|
||||
* hbm.xml binding
|
||||
*/
|
||||
protected Collection(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||
this.buildingContext = buildingContext;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation binding
|
||||
*/
|
||||
protected Collection(SemanticsResolver customSemanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
this.customSemanticsResolver = customSemanticsResolver;
|
||||
this.owner = owner;
|
||||
this.buildingContext = buildingContext;
|
||||
}
|
||||
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
|
@ -142,13 +161,13 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
return sorted;
|
||||
}
|
||||
|
||||
public Comparator getComparator() {
|
||||
public Comparator<?> getComparator() {
|
||||
if ( comparator == null && comparatorClassName != null ) {
|
||||
try {
|
||||
final ClassLoaderService classLoaderService = getMetadata().getMetadataBuildingOptions()
|
||||
.getServiceRegistry()
|
||||
.getService( ClassLoaderService.class );
|
||||
setComparator( (Comparator) classLoaderService.classForName( comparatorClassName ).newInstance() );
|
||||
setComparator( (Comparator<?>) classLoaderService.classForName( comparatorClassName ).getConstructor().newInstance() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException(
|
||||
|
@ -202,7 +221,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
return orderBy;
|
||||
}
|
||||
|
||||
public void setComparator(Comparator comparator) {
|
||||
public void setComparator(@SuppressWarnings("rawtypes") Comparator comparator) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
|
@ -296,11 +315,11 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
this.fetchMode = fetchMode;
|
||||
}
|
||||
|
||||
public void setCollectionPersisterClass(Class persister) {
|
||||
public void setCollectionPersisterClass(Class<? extends CollectionPersister> persister) {
|
||||
this.collectionPersisterClass = persister;
|
||||
}
|
||||
|
||||
public Class getCollectionPersisterClass() {
|
||||
public Class<? extends CollectionPersister> getCollectionPersisterClass() {
|
||||
return collectionPersisterClass;
|
||||
}
|
||||
|
||||
|
@ -328,7 +347,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
checkColumnDuplication();
|
||||
}
|
||||
|
||||
private void checkColumnDuplication(java.util.Set distinctColumns, Value value)
|
||||
private void checkColumnDuplication(java.util.Set<String> distinctColumns, Value value)
|
||||
throws MappingException {
|
||||
final boolean[] insertability = value.getColumnInsertability();
|
||||
final boolean[] updatability = value.getColumnUpdateability();
|
||||
|
@ -354,7 +373,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
}
|
||||
|
||||
private void checkColumnDuplication() throws MappingException {
|
||||
HashSet cols = new HashSet();
|
||||
HashSet<String> cols = new HashSet<>();
|
||||
checkColumnDuplication( cols, getKey() );
|
||||
if ( isIndexed() ) {
|
||||
checkColumnDuplication(
|
||||
|
@ -374,7 +393,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
}
|
||||
|
||||
public Iterator<Selectable> getColumnIterator() {
|
||||
return Collections.<Selectable>emptyList().iterator();
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -390,23 +409,78 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
return getCollectionType();
|
||||
}
|
||||
|
||||
private CollectionSemantics<?,?> cachedCollectionSemantics;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public CollectionSemantics getCollectionSemantics() {
|
||||
if ( cachedCollectionSemantics == null ) {
|
||||
cachedCollectionSemantics = resolveCollectionSemantics();
|
||||
}
|
||||
|
||||
return cachedCollectionSemantics;
|
||||
}
|
||||
|
||||
private CollectionSemantics<?, ?> resolveCollectionSemantics() {
|
||||
final CollectionType collectionType;
|
||||
if ( typeName == null ) {
|
||||
return getDefaultCollectionSemantics();
|
||||
collectionType = null;
|
||||
}
|
||||
else {
|
||||
final CollectionType collectionType = MappingHelper.customCollection(
|
||||
collectionType = MappingHelper.customCollection(
|
||||
typeName,
|
||||
typeParameters,
|
||||
role,
|
||||
referencedPropertyName,
|
||||
getMetadata()
|
||||
);
|
||||
return new CustomCollectionTypeSemantics( collectionType );
|
||||
}
|
||||
}
|
||||
|
||||
public CollectionSemantics getDefaultCollectionSemantics() {
|
||||
if ( customSemanticsResolver != null ) {
|
||||
return customSemanticsResolver.resolve( collectionType );
|
||||
}
|
||||
|
||||
if ( collectionType == null ) {
|
||||
return getDefaultCollectionSemantics();
|
||||
}
|
||||
|
||||
final Class<?> semanticJavaType = collectionType.getReturnedClass();
|
||||
final CollectionClassification classification;
|
||||
|
||||
if ( semanticJavaType.isArray() ) {
|
||||
classification = CollectionClassification.ARRAY;
|
||||
}
|
||||
else if ( List.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
classification = CollectionClassification.LIST;
|
||||
}
|
||||
else if ( SortedSet.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
classification = CollectionClassification.SORTED_SET;
|
||||
}
|
||||
else if ( Set.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
classification = CollectionClassification.SET;
|
||||
}
|
||||
else if ( SortedMap.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
classification = CollectionClassification.SORTED_MAP;
|
||||
}
|
||||
else if ( Map.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
classification = CollectionClassification.MAP;
|
||||
}
|
||||
else if ( Collection.class.isAssignableFrom( semanticJavaType ) ) {
|
||||
if ( isIdentified() ) {
|
||||
classification = CollectionClassification.IDBAG;
|
||||
}
|
||||
else {
|
||||
classification = CollectionClassification.BAG;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException( "Unexpected collection-semantics Java type : " + semanticJavaType );
|
||||
}
|
||||
|
||||
return new CustomCollectionTypeSemantics<>( collectionType, classification );
|
||||
|
||||
}
|
||||
|
||||
public CollectionSemantics<?,?> getDefaultCollectionSemantics() {
|
||||
throw new MappingException(
|
||||
"Unexpected org.hibernate.mapping.Collection impl ["
|
||||
+ this + "]; unknown CollectionSemantics"
|
||||
|
@ -598,7 +672,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
);
|
||||
}
|
||||
|
||||
public List getFilters() {
|
||||
public List<FilterConfiguration> getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
|
@ -620,7 +694,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
);
|
||||
}
|
||||
|
||||
public List getManyToManyFilters() {
|
||||
public List<FilterConfiguration> getManyToManyFilters() {
|
||||
return manyToManyFilters;
|
||||
}
|
||||
|
||||
|
@ -677,6 +751,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
this.typeParameters = parameterMap;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void setTypeParameters(java.util.Map parameterMap) {
|
||||
if ( parameterMap instanceof Properties ) {
|
||||
this.typeParameters = (Properties) parameterMap;
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.internal.FilterConfiguration;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface Filterable {
|
||||
public void addFilter(String name, String condition, boolean autoAliasInjection, java.util.Map<String,String> aliasTableMap, java.util.Map<String,String> aliasEntityMap);
|
||||
void addFilter(String name, String condition, boolean autoAliasInjection, java.util.Map<String,String> aliasTableMap, java.util.Map<String,String> aliasEntityMap);
|
||||
|
||||
public java.util.List<FilterConfiguration> getFilters();
|
||||
java.util.List<FilterConfiguration> getFilters();
|
||||
}
|
||||
|
|
|
@ -17,10 +17,21 @@ import org.hibernate.type.IdentifierBagType;
|
|||
* just the identifier column
|
||||
*/
|
||||
public class IdentifierBag extends IdentifierCollection {
|
||||
|
||||
/**
|
||||
* hbm.xml binding
|
||||
*/
|
||||
public IdentifierBag(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
/**
|
||||
* annotation binding
|
||||
*/
|
||||
public IdentifierBag(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public CollectionType getDefaultCollectionType() {
|
||||
return new IdentifierBagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() );
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.mapping;
|
|||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
|
||||
/**
|
||||
|
@ -23,6 +24,10 @@ public abstract class IdentifierCollection extends Collection {
|
|||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
public IdentifierCollection(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public KeyValue getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
package org.hibernate.mapping;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
||||
/**
|
||||
* Indexed collections include Lists, Maps, arrays and
|
||||
|
@ -27,6 +30,10 @@ public abstract class IndexedCollection extends Collection {
|
|||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
public IndexedCollection(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public Value getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.collection.internal.StandardListSemantics;
|
||||
|
@ -22,14 +24,24 @@ public class List extends IndexedCollection {
|
|||
|
||||
private int baseIndex;
|
||||
|
||||
public boolean isList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* hbm.xml binding
|
||||
*/
|
||||
public List(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
/**
|
||||
* annotation binding
|
||||
*/
|
||||
public List(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public boolean isList() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionSemantics getDefaultCollectionSemantics() {
|
||||
return StandardListSemantics.INSTANCE;
|
||||
|
|
|
@ -29,6 +29,10 @@ public class Map extends IndexedCollection {
|
|||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
public Map(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ public class PrimitiveArray extends Array {
|
|||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
public PrimitiveArray(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public boolean isPrimitiveArray() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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.mapping;
|
||||
|
||||
import org.hibernate.collection.spi.CollectionSemantics;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SemanticsResolver {
|
||||
CollectionSemantics<?, ?> resolve(org.hibernate.type.CollectionType explicitType);
|
||||
}
|
|
@ -26,10 +26,20 @@ import org.hibernate.type.SortedSetType;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public class Set extends Collection {
|
||||
/**
|
||||
* Used by hbm.xml binding
|
||||
*/
|
||||
public Set(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||
super( buildingContext, owner );
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by annotation binding
|
||||
*/
|
||||
public Set(SemanticsResolver semanticsResolver, PersistentClass persistentClass, MetadataBuildingContext buildingContext) {
|
||||
super( semanticsResolver, persistentClass, buildingContext );
|
||||
}
|
||||
|
||||
public void validate(Mapping mapping) throws MappingException {
|
||||
super.validate( mapping );
|
||||
//for backward compatibility, disable this:
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.cfg.Ejb3JoinColumn;
|
|||
import org.hibernate.cfg.InheritanceState;
|
||||
import org.hibernate.cfg.PropertyHolder;
|
||||
import org.hibernate.cfg.annotations.CollectionBinder;
|
||||
import org.hibernate.collection.internal.StandardBagSemantics;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Table;
|
||||
|
@ -55,7 +56,7 @@ public class CollectionBinderTest extends BaseUnitTestCase {
|
|||
|
||||
String expectMessage = "Association [abc] for entity [CollectionBinderTest] references unmapped class [List]";
|
||||
try {
|
||||
new CollectionBinder( false) {
|
||||
new CollectionBinder( (t) -> StandardBagSemantics.INSTANCE, false, buildingContext ) {
|
||||
|
||||
{
|
||||
final PropertyHolder propertyHolder = Mockito.mock(PropertyHolder.class);
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.collections;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.annotations.SortNatural;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderBy;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@JiraKey( "https://hibernate.atlassian.net/browse/HHH-9688" )
|
||||
@ServiceRegistry
|
||||
public class SortAndOrderTests {
|
||||
|
||||
@Test
|
||||
void test(ServiceRegistryScope scope) {
|
||||
final StandardServiceRegistry registry = scope.getRegistry();
|
||||
final MetadataSources sources = new MetadataSources( registry ).addAnnotatedClass( AnEntity.class );
|
||||
|
||||
try {
|
||||
sources.buildMetadata();
|
||||
fail( "Expecting to fail" );
|
||||
}
|
||||
catch (AnnotationException expected) {
|
||||
assertThat( expected ).hasMessageStartingWith( "Illegal combination of ordering and sorting annotations" );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "AnEntity" )
|
||||
@Table( name = "t_entity" )
|
||||
public static class AnEntity {
|
||||
@Id
|
||||
private Integer id;
|
||||
@Basic
|
||||
private String name;
|
||||
|
||||
@ElementCollection
|
||||
@SortNatural
|
||||
@OrderBy
|
||||
private Set<String> aliases;
|
||||
|
||||
private AnEntity() {
|
||||
// for use by Hibernate
|
||||
}
|
||||
|
||||
public AnEntity(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import org.hibernate.collection.internal.PersistentList;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
@ -4,11 +4,10 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
|
@ -17,9 +16,9 @@ import jakarta.persistence.JoinColumn;
|
|||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
|
@ -28,43 +27,41 @@ import org.hibernate.annotations.CollectionType;
|
|||
@Entity
|
||||
@Table(name = "UC_BSC_USER")
|
||||
public class User {
|
||||
@Id
|
||||
private Integer id;
|
||||
@NaturalId
|
||||
private String userName;
|
||||
private IMyList<Email> emailAddresses = new MyList<Email>();
|
||||
private Map sessionData = new HashMap();
|
||||
|
||||
User() {
|
||||
@OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true )
|
||||
@CollectionType( type = "org.hibernate.orm.test.mapping.type.collection.custom.basic.MyListType" )
|
||||
@JoinColumn( name = "userName" )
|
||||
@OrderColumn( name = "displayOrder" )
|
||||
private IMyList<Email> emailAddresses = new MyList<>();
|
||||
|
||||
private User() {
|
||||
// for use by Hibernate
|
||||
}
|
||||
public User(String name) {
|
||||
|
||||
public User(Integer id, String name) {
|
||||
this.id = id;
|
||||
userName = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
@OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true )
|
||||
@CollectionType( type = "org.hibernate.test.collection.custom.basic.MyListType" )
|
||||
@JoinColumn( name = "userName" )
|
||||
@OrderColumn( name = "displayOrder" )
|
||||
public List<Email> getEmailAddresses() {
|
||||
// does not work :(
|
||||
// public IMyList<Email> getEmailAddresses() {
|
||||
return emailAddresses;
|
||||
}
|
||||
public void setEmailAddresses(IMyList<Email> emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Map getSessionData() {
|
||||
return sessionData;
|
||||
}
|
||||
public void setSessionData(Map sessionData) {
|
||||
this.sessionData = sessionData;
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
|
@ -4,14 +4,19 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest {
|
||||
@Override
|
||||
protected String getBaseForMappings() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] { "collection/custom/basic/UserPermissions.hbm.xml" };
|
||||
return new String[] { "/org/hibernate/orm/test/mapping/type/collection/custom/basic/UserPermissions.hbm.xml" };
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.basic;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.basic;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
@ -29,7 +29,7 @@ public abstract class UserCollectionTypeTest extends BaseNonConfigCoreFunctional
|
|||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
User u = new User("max");
|
||||
User u = new User( 1, "max" );
|
||||
inTransaction(
|
||||
s -> {
|
||||
u.getEmailAddresses().add( new Email("max@hibernate.org") );
|
||||
|
@ -53,7 +53,7 @@ public abstract class UserCollectionTypeTest extends BaseNonConfigCoreFunctional
|
|||
|
||||
inTransaction(
|
||||
s -> {
|
||||
User u2 = s.get( User.class, u.getUserName() );
|
||||
User u2 = s.get( User.class, u.getId() );
|
||||
u2.getEmailAddresses().size();
|
||||
assertEquals( 2, MyListType.lastInstantiationRequest );
|
||||
|
|
@ -13,13 +13,14 @@
|
|||
This mapping is a basic example of how to write a UserCollectionType.
|
||||
-->
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.collection.custom.basic">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.mapping.type.collection.custom.basic" default-access="field">
|
||||
|
||||
<import class="Permission"/>
|
||||
|
||||
<class name="User" table="UC_BSC_USER">
|
||||
<id name="userName"/>
|
||||
<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.test.collection.custom.basic.MyListType">
|
||||
<id name="id"/>
|
||||
<property name="userName"/>
|
||||
<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.orm.test.mapping.type.collection.custom.basic.MyListType">
|
||||
<key column="userName"/>
|
||||
<list-index column="displayOrder" base="1"/>
|
||||
<one-to-many class="Email"/>
|
|
@ -1,4 +1,4 @@
|
|||
package org.hibernate.test.collection.custom.declaredtype;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A custom collection class that implements a simple method just for illustration.
|
||||
* We extend a java.util.Collection class which is required for annotations-based entities, but not xml-based.
|
||||
*
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public class HeadList<X> extends ArrayList<X> implements IHeadList<X> {
|
||||
|
||||
@Override
|
||||
public X head() {
|
||||
return isEmpty() ? null : get( 0 );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class HeadListType implements UserCollectionType {
|
||||
|
||||
@Override
|
||||
public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister) throws HibernateException {
|
||||
return new PersistentHeadList( session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection wrap(SharedSessionContractImplementor session, Object collection) {
|
||||
return new PersistentHeadList( session, (IHeadList) collection );
|
||||
}
|
||||
|
||||
public Iterator getElementsIterator(Object collection) {
|
||||
return ( (IHeadList) collection ).iterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object collection, Object entity) {
|
||||
return ( (IHeadList) collection ).contains( entity );
|
||||
}
|
||||
|
||||
public Object indexOf(Object collection, Object entity) {
|
||||
int l = ( (IHeadList) collection ).indexOf( entity );
|
||||
if ( l < 0 ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object replaceElements(
|
||||
Object original,
|
||||
Object target,
|
||||
CollectionPersister persister,
|
||||
Object owner,
|
||||
Map copyCache,
|
||||
SharedSessionContractImplementor session) throws HibernateException {
|
||||
IHeadList result = (IHeadList) target;
|
||||
result.clear();
|
||||
result.addAll( (HeadList) original );
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object instantiate(int anticipatedSize) {
|
||||
return new HeadList();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IHeadList<X> extends List<X> {
|
||||
X head();
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import org.hibernate.collection.internal.PersistentList;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PersistentHeadList extends PersistentList implements IHeadList {
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session) {
|
||||
super( session );
|
||||
}
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session, IHeadList list) {
|
||||
super( session, list );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object head() {
|
||||
return ( (IHeadList) list ).head();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "UC_BSC_USER")
|
||||
public class User {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String userName;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@CollectionType(type = "org.hibernate.orm.test.mapping.type.collection.custom.declaredtype.HeadListType")
|
||||
@JoinColumn(name = "userName")
|
||||
@OrderColumn(name = "displayOrder")
|
||||
private IHeadList<Email> emailAddresses = new HeadList<Email>();
|
||||
|
||||
private User() {
|
||||
}
|
||||
|
||||
public User(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.userName = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public IHeadList<Email> getEmailAddresses() { //can declare a custom interface type
|
||||
return emailAddresses;
|
||||
}
|
||||
|
||||
public void setEmailAddresses(IHeadList<Email> emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.collection.custom.declaredtype;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
|
@ -21,7 +21,7 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.collection.custom.declaredtype;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -29,6 +29,6 @@ package org.hibernate.test.collection.custom.declaredtype;
|
|||
public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest {
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] { "collection/custom/declaredtype/UserPermissions.hbm.xml" };
|
||||
return new String[] { "mapping/type/collection/custom/declaredtype/UserPermissions.hbm.xml" };
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Max Rydahl Andersen
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public abstract class UserCollectionTypeTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected String getCacheConcurrencyStrategy() {
|
||||
return "nonstrict-read-write";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
inTransaction(
|
||||
s -> {
|
||||
User u = new User( 1, "max" );
|
||||
u.getEmailAddresses().add( new Email("max@hibernate.org") );
|
||||
u.getEmailAddresses().add( new Email("max.andersen@jboss.com") );
|
||||
s.persist(u);
|
||||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
s -> {
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<User> criteria = criteriaBuilder.createQuery( User.class );
|
||||
criteria.from( User.class );
|
||||
User u2 = s.createQuery( criteria ).uniqueResult();
|
||||
// User u2 = (User) s.createCriteria(User.class).uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) );
|
||||
assertEquals( u2.getEmailAddresses().size(), 2 );
|
||||
assertNotNull( u2.getEmailAddresses().head());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,13 +7,14 @@
|
|||
This mapping is a basic example of how to write a UserCollectionType.
|
||||
-->
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.collection.custom.declaredtype">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.mapping.type.collection.custom.declaredtype" default-access="field">
|
||||
|
||||
<import class="Permission"/>
|
||||
|
||||
<class name="org.hibernate.test.collection.custom.declaredtype.UserCollectionTypeTest$User" table="UC_BSC_USER">
|
||||
<id name="userName"/>
|
||||
<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.test.collection.custom.declaredtype.UserCollectionTypeTest$HeadListType">
|
||||
<class name="org.hibernate.orm.test.mapping.type.collection.custom.declaredtype.User" table="UC_BSC_USER">
|
||||
<id name="id"/>
|
||||
<property name="userName"/>
|
||||
<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.orm.test.mapping.type.collection.custom.declaredtype.HeadListType">
|
||||
<key column="userName"/>
|
||||
<list-index column="displayOrder" base="1"/>
|
||||
<one-to-many class="Email"/>
|
|
@ -21,7 +21,7 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.collection.custom.declaredtype;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
|
|
@ -21,12 +21,13 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.collection.custom.declaredtype;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
@ -54,10 +55,9 @@ public class UserWithUnimplementedCollectionTest extends BaseCoreFunctionalTestC
|
|||
fail( "Expected exception" );
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertTrue( e instanceof AnnotationException );
|
||||
assertEquals(
|
||||
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: org.hibernate.test.collection.custom.declaredtype.UserWithUnimplementedCollection.emailAddresses",
|
||||
e.getMessage() );
|
||||
assertThat( e ).isInstanceOf( AnnotationException.class );
|
||||
assertThat( e ).hasMessageStartingWith( "Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements:" );
|
||||
assertThat( e ).hasMessageEndingWith( ".emailAddresses" );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity(name = "Email")
|
||||
public class Email {
|
||||
|
||||
private Long id;
|
||||
private String address;
|
||||
|
||||
Email() {
|
||||
}
|
||||
|
||||
public Email(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String type) {
|
||||
this.address = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if ( !( that instanceof Email ) ) {
|
||||
return false;
|
||||
}
|
||||
Email p = (Email) that;
|
||||
return this.address.equals( p.address );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return address.hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A custom collection class that has both List and Set interfaces, but only really implements set for persistence
|
||||
* (e.g. extends PersistentSet). Without setting the semantics on the CollectionType annotation, List semantics
|
||||
* would be inferred, and that would not match the implemented methods in PersistentSet and would fail. HeadSetList
|
||||
* is very much a toy collection type.
|
||||
*
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public class HeadSetList<X> extends ArrayList<X> implements IHeadSetList<X> {
|
||||
|
||||
@Override
|
||||
public X head() {
|
||||
return isEmpty() ? null : get( 0 );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class HeadSetListType implements UserCollectionType {
|
||||
|
||||
@Override
|
||||
public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister)
|
||||
throws HibernateException {
|
||||
return new PersistentHeadList( session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection wrap(SharedSessionContractImplementor session, Object collection) {
|
||||
return new PersistentHeadList( session, (IHeadSetList) collection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator getElementsIterator(Object collection) {
|
||||
return ( (IHeadSetList) collection ).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object collection, Object entity) {
|
||||
return ( (IHeadSetList) collection ).contains( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object indexOf(Object collection, Object entity) {
|
||||
int l = ( (IHeadSetList) collection ).indexOf( entity );
|
||||
if ( l < 0 ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object replaceElements(
|
||||
Object original,
|
||||
Object target,
|
||||
CollectionPersister persister,
|
||||
Object owner,
|
||||
Map copyCache,
|
||||
SharedSessionContractImplementor session) throws HibernateException {
|
||||
IHeadSetList result = (IHeadSetList) target;
|
||||
result.clear();
|
||||
result.addAll( (HeadSetList) original );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiate(int anticipatedSize) {
|
||||
return new HeadSetList();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface IHeadSetList<X> extends Set<X>, List<X> {
|
||||
|
||||
X head();
|
||||
|
||||
@Override
|
||||
default Spliterator<X> spliterator() {
|
||||
return Spliterators.spliterator( this, Spliterator.DISTINCT );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.hibernate.collection.internal.PersistentSet;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PersistentHeadList extends PersistentSet implements IHeadSetList {
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session) {
|
||||
super( session );
|
||||
}
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session, IHeadSetList list) {
|
||||
super( session, list );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object head() {
|
||||
return ( (IHeadSetList) set ).head();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection c) {
|
||||
return set.addAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int index) {
|
||||
Iterator iterator = iterator();
|
||||
Object next = null;
|
||||
for ( int i = 0; i <= index; i++ ) {
|
||||
next = iterator.next();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object set(int index, Object element) {
|
||||
remove( index );
|
||||
return add( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Object element) {
|
||||
add( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int index) {
|
||||
return remove( get( index ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator() {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator(int index) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List subList(int fromIndex, int toIndex) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity(name = "User")
|
||||
@Table(name = "UC_BSC_USER")
|
||||
public class User {
|
||||
|
||||
private String userName;
|
||||
|
||||
private IHeadSetList<Email> emailAddresses = new HeadSetList<Email>();
|
||||
|
||||
private Map sessionData = new HashMap();
|
||||
|
||||
User() {
|
||||
|
||||
}
|
||||
|
||||
public User(String name) {
|
||||
userName = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@CollectionType(type = "org.hibernate.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics.HeadSetListType", semantics = Set.class)
|
||||
@JoinColumn(name = "userName")
|
||||
@OrderColumn(name = "displayOrder")
|
||||
public IHeadSetList<Email> getEmailAddresses() { // can declare a custom interface type
|
||||
return emailAddresses;
|
||||
}
|
||||
|
||||
public void setEmailAddresses(IHeadSetList<Email> emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Map getSessionData() {
|
||||
return sessionData;
|
||||
}
|
||||
|
||||
public void setSessionData(Map sessionData) {
|
||||
this.sessionData = sessionData;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Max Rydahl Andersen
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public class UserCollectionTypeTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{ User.class, Email.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConcurrencyStrategy() {
|
||||
return "nonstrict-read-write";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
User u = new User( "max" );
|
||||
u.getEmailAddresses().add( new Email( "max@hibernate.org" ) );
|
||||
u.getEmailAddresses().add( new Email( "max.andersen@jboss.com" ) );
|
||||
session.persist( u );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<User> criteria = criteriaBuilder.createQuery( User.class );
|
||||
criteria.from( User.class );
|
||||
User u2 = session.createQuery( criteria ).getSingleResult();
|
||||
// User u2 = (User) session.createCriteria( User.class ).uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) );
|
||||
assertEquals( u2.getEmailAddresses().size(), 2 );
|
||||
assertNotNull( u2.getEmailAddresses().head() );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -16,6 +16,7 @@ import jakarta.persistence.JoinColumn;
|
|||
import jakarta.persistence.OrderColumn;
|
||||
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -23,11 +24,6 @@ import org.hibernate.annotations.CollectionType;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
//@TypeDef(
|
||||
// name = "DefaultableList",
|
||||
// typeClass = DefaultableListType.class,
|
||||
// parameters = @Parameter(name = "default", value = "Hello" )
|
||||
//)
|
||||
@jakarta.persistence.Entity
|
||||
public class Entity {
|
||||
private String name;
|
||||
|
@ -50,7 +46,10 @@ public class Entity {
|
|||
}
|
||||
|
||||
@ElementCollection( targetClass = String.class, fetch = FetchType.EAGER )
|
||||
@CollectionType( type = "DefaultableList" )
|
||||
@CollectionType(
|
||||
type = "org.hibernate.orm.test.mapping.type.collection.custom.parameterized.DefaultableListType",
|
||||
parameters = @Parameter(name = "default", value = "Hello" )
|
||||
)
|
||||
@JoinColumn( name = "ENT_ID" )
|
||||
@OrderColumn( name = "POS" )
|
||||
@Column(name = "VAL")
|
|
@ -9,9 +9,9 @@
|
|||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.collection.custom.parameterized" default-access="field">
|
||||
<hibernate-mapping package="org.hibernate.orm.test.mapping.type.collection.custom.parameterized" default-access="field">
|
||||
|
||||
<typedef name="DefaultableList" class="org.hibernate.test.collection.custom.parameterized.DefaultableListType">
|
||||
<typedef name="DefaultableList" class="org.hibernate.orm.test.mapping.type.collection.custom.parameterized.DefaultableListType">
|
||||
<param name="default">Hello</param>
|
||||
</typedef>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
|
@ -4,13 +4,13 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParameterizedUserCollectionTypeHbmVariantTest extends ParameterizedUserCollectionTypeTest {
|
||||
public String[] getMappings() {
|
||||
return new String[] { "collection/custom/parameterized/Mapping.hbm.xml" };
|
||||
return new String[] { "mapping/type/collection/custom/parameterized/Mapping.hbm.xml" };
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
|
@ -4,7 +4,7 @@
|
|||
* 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.test.collection.custom.parameterized;
|
||||
package org.hibernate.orm.test.mapping.type.collection.custom.parameterized;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.collection.custom.declaredtype;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
import org.hibernate.collection.internal.PersistentList;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Max Rydahl Andersen
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public abstract class UserCollectionTypeTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected String getCacheConcurrencyStrategy() {
|
||||
return "nonstrict-read-write";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
inTransaction(
|
||||
s -> {
|
||||
User u = new User("max");
|
||||
u.getEmailAddresses().add( new Email("max@hibernate.org") );
|
||||
u.getEmailAddresses().add( new Email("max.andersen@jboss.com") );
|
||||
s.persist(u);
|
||||
}
|
||||
);
|
||||
|
||||
inTransaction(
|
||||
s -> {
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<User> criteria = criteriaBuilder.createQuery( User.class );
|
||||
criteria.from( User.class );
|
||||
User u2 = s.createQuery( criteria ).uniqueResult();
|
||||
// User u2 = (User) s.createCriteria(User.class).uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) );
|
||||
assertEquals( u2.getEmailAddresses().size(), 2 );
|
||||
assertNotNull( u2.getEmailAddresses().head());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom collection class that implements a simple method just for illustration.
|
||||
* We extend a java.util.Collection class which is required for annotations-based entities, but not xml-based.
|
||||
*
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public static class HeadList<X> extends ArrayList<X> implements IHeadList<X> {
|
||||
|
||||
@Override
|
||||
public X head() {
|
||||
return isEmpty() ? null : get( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
public static class HeadListType implements UserCollectionType {
|
||||
|
||||
@Override
|
||||
public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister) throws HibernateException {
|
||||
return new PersistentHeadList(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection wrap(SharedSessionContractImplementor session, Object collection) {
|
||||
return new PersistentHeadList( session, (IHeadList) collection );
|
||||
}
|
||||
|
||||
public Iterator getElementsIterator(Object collection) {
|
||||
return ( (IHeadList) collection ).iterator();
|
||||
}
|
||||
|
||||
public boolean contains(Object collection, Object entity) {
|
||||
return ( (IHeadList) collection ).contains(entity);
|
||||
}
|
||||
|
||||
public Object indexOf(Object collection, Object entity) {
|
||||
int l = ( (IHeadList) collection ).indexOf(entity);
|
||||
if(l<0) {
|
||||
return null;
|
||||
} else {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object replaceElements(
|
||||
Object original,
|
||||
Object target,
|
||||
CollectionPersister persister,
|
||||
Object owner,
|
||||
Map copyCache,
|
||||
SharedSessionContractImplementor session) throws HibernateException {
|
||||
IHeadList result = (IHeadList) target;
|
||||
result.clear();
|
||||
result.addAll( (HeadList) original );
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object instantiate(int anticipatedSize) {
|
||||
return new HeadList();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public interface IHeadList<X> extends List<X> {
|
||||
X head();
|
||||
}
|
||||
|
||||
public static class PersistentHeadList extends PersistentList implements IHeadList {
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session, IHeadList list) {
|
||||
super(session, list);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object head() {
|
||||
return ((IHeadList) list).head();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "UC_BSC_USER")
|
||||
//@TypeDef( name = "HeadListType", typeClass = HeadListType.class )
|
||||
public static class User {
|
||||
private String userName;
|
||||
private IHeadList<Email> emailAddresses = new HeadList<Email>();
|
||||
private Map sessionData = new HashMap();
|
||||
|
||||
User() {
|
||||
|
||||
}
|
||||
public User(String name) {
|
||||
userName = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
@OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true )
|
||||
@CollectionType( type = "HeadListType" )
|
||||
@JoinColumn( name = "userName" )
|
||||
@OrderColumn( name = "displayOrder" )
|
||||
public IHeadList<Email> getEmailAddresses() { //can declare a custom interface type
|
||||
return emailAddresses;
|
||||
}
|
||||
public void setEmailAddresses(IHeadList<Email> emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Map getSessionData() {
|
||||
return sessionData;
|
||||
}
|
||||
public void setSessionData(Map sessionData) {
|
||||
this.sessionData = sessionData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,355 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.collection.custom.declaredtype.explicitsemantics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.annotations.CollectionType;
|
||||
import org.hibernate.collection.internal.PersistentSet;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.usertype.UserCollectionType;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Max Rydahl Andersen
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public class UserCollectionTypeTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{ User.class, Email.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConcurrencyStrategy() {
|
||||
return "nonstrict-read-write";
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
User u = new User( "max" );
|
||||
u.getEmailAddresses().add( new Email( "max@hibernate.org" ) );
|
||||
u.getEmailAddresses().add( new Email( "max.andersen@jboss.com" ) );
|
||||
session.persist( u );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<User> criteria = criteriaBuilder.createQuery( User.class );
|
||||
criteria.from( User.class );
|
||||
User u2 = session.createQuery( criteria ).uniqueResult();
|
||||
// User u2 = (User) session.createCriteria( User.class ).uniqueResult();
|
||||
assertTrue( Hibernate.isInitialized( u2.getEmailAddresses() ) );
|
||||
assertEquals( u2.getEmailAddresses().size(), 2 );
|
||||
assertNotNull( u2.getEmailAddresses().head() );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity(name = "Email")
|
||||
public static class Email {
|
||||
|
||||
private Long id;
|
||||
private String address;
|
||||
|
||||
Email() {
|
||||
}
|
||||
|
||||
public Email(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
private void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String type) {
|
||||
this.address = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if ( !( that instanceof Email ) )
|
||||
return false;
|
||||
Email p = (Email) that;
|
||||
return this.address.equals( p.address );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return address.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "User")
|
||||
@Table(name = "UC_BSC_USER")
|
||||
// @TypeDef(name = "HeadSetListType", typeClass = HeadSetListType.class)
|
||||
public static class User {
|
||||
|
||||
private String userName;
|
||||
|
||||
private IHeadSetList<Email> emailAddresses = new HeadSetList<Email>();
|
||||
|
||||
private Map sessionData = new HashMap();
|
||||
|
||||
User() {
|
||||
|
||||
}
|
||||
|
||||
public User(String name) {
|
||||
userName = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@CollectionType(type = "HeadSetListType", semantics = Set.class)
|
||||
@JoinColumn(name = "userName")
|
||||
@OrderColumn(name = "displayOrder")
|
||||
public IHeadSetList<Email> getEmailAddresses() { // can declare a custom interface type
|
||||
return emailAddresses;
|
||||
}
|
||||
|
||||
public void setEmailAddresses(IHeadSetList<Email> emailAddresses) {
|
||||
this.emailAddresses = emailAddresses;
|
||||
}
|
||||
|
||||
@Transient
|
||||
public Map getSessionData() {
|
||||
return sessionData;
|
||||
}
|
||||
|
||||
public void setSessionData(Map sessionData) {
|
||||
this.sessionData = sessionData;
|
||||
}
|
||||
}
|
||||
|
||||
public static class HeadSetListType implements UserCollectionType {
|
||||
|
||||
@Override
|
||||
public PersistentCollection instantiate(SharedSessionContractImplementor session, CollectionPersister persister)
|
||||
throws HibernateException {
|
||||
return new PersistentHeadList( session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentCollection wrap(SharedSessionContractImplementor session, Object collection) {
|
||||
return new PersistentHeadList( session, (IHeadSetList) collection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator getElementsIterator(Object collection) {
|
||||
return ( (IHeadSetList) collection ).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object collection, Object entity) {
|
||||
return ( (IHeadSetList) collection ).contains( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object indexOf(Object collection, Object entity) {
|
||||
int l = ( (IHeadSetList) collection ).indexOf( entity );
|
||||
if ( l < 0 ) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object replaceElements(
|
||||
Object original,
|
||||
Object target,
|
||||
CollectionPersister persister,
|
||||
Object owner,
|
||||
Map copyCache,
|
||||
SharedSessionContractImplementor session) throws HibernateException {
|
||||
IHeadSetList result = (IHeadSetList) target;
|
||||
result.clear();
|
||||
result.addAll( (HeadSetList) original );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiate(int anticipatedSize) {
|
||||
return new HeadSetList();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IHeadSetList<X> extends Set<X>, List<X> {
|
||||
|
||||
X head();
|
||||
|
||||
@Override
|
||||
default Spliterator<X> spliterator() {
|
||||
return Spliterators.spliterator( this, Spliterator.DISTINCT );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom collection class that has both List and Set interfaces, but only really implements set for persistence
|
||||
* (e.g. extends PersistentSet). Without setting the semantics on the CollectionType annotation, List semantics
|
||||
* would be inferred, and that would not match the implemented methods in PersistentSet and would fail. HeadSetList
|
||||
* is very much a toy collection type.
|
||||
*
|
||||
* @author David Weinberg
|
||||
*/
|
||||
public static class HeadSetList<X> extends ArrayList<X> implements IHeadSetList<X> {
|
||||
|
||||
@Override
|
||||
public X head() {
|
||||
return isEmpty() ? null : get( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
public static class PersistentHeadList extends PersistentSet implements IHeadSetList {
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session) {
|
||||
super( session );
|
||||
}
|
||||
|
||||
public PersistentHeadList(SharedSessionContractImplementor session, IHeadSetList list) {
|
||||
super( session, list );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object head() {
|
||||
return ( (IHeadSetList) set ).head();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection c) {
|
||||
return set.addAll( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(int index) {
|
||||
Iterator iterator = iterator();
|
||||
Object next = null;
|
||||
for ( int i = 0; i <= index; i++ ) {
|
||||
next = iterator.next();
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object set(int index, Object element) {
|
||||
remove( index );
|
||||
return add( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, Object element) {
|
||||
add( element );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(int index) {
|
||||
return remove( get( index ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(Object o) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastIndexOf(Object o) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator() {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListIterator listIterator(int index) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List subList(int fromIndex, int toIndex) {
|
||||
throw new UnsupportedOperationException( "Toy class" );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue