`@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.
|
* Names the type.
|
||||||
*
|
*
|
||||||
* Could name the implementation class (an implementation of {@link org.hibernate.type.CollectionType} or
|
* 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 org.hibernate.usertype.UserCollectionType}).
|
||||||
* {@link TypeDef @TypeDef}
|
|
||||||
*/
|
*/
|
||||||
String type();
|
String type();
|
||||||
|
|
||||||
|
|
|
@ -2028,7 +2028,6 @@ public final class AnnotationBinder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(
|
CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(
|
||||||
propertyHolder.getEntityName(),
|
|
||||||
property,
|
property,
|
||||||
!indexColumn.isImplicit(),
|
!indexColumn.isImplicit(),
|
||||||
// ugh
|
// ugh
|
||||||
|
@ -2060,7 +2059,6 @@ public final class AnnotationBinder {
|
||||||
boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
|
boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
|
||||||
collectionBinder.setIgnoreNotFound( ignoreNotFound );
|
collectionBinder.setIgnoreNotFound( ignoreNotFound );
|
||||||
collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
|
collectionBinder.setCollectionType( inferredData.getProperty().getElementClass() );
|
||||||
collectionBinder.setBuildingContext( context );
|
|
||||||
collectionBinder.setAccessType( inferredData.getDefaultAccess() );
|
collectionBinder.setAccessType( inferredData.getDefaultAccess() );
|
||||||
|
|
||||||
Ejb3Column[] elementColumns;
|
Ejb3Column[] elementColumns;
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg.annotations;
|
package org.hibernate.cfg.annotations;
|
||||||
|
|
||||||
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.mapping.Array;
|
import org.hibernate.mapping.Array;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind an Array
|
* Bind an Array
|
||||||
|
@ -16,11 +18,11 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
* @author Anthony Patricio
|
* @author Anthony Patricio
|
||||||
*/
|
*/
|
||||||
public class ArrayBinder extends ListBinder {
|
public class ArrayBinder extends ListBinder {
|
||||||
|
public ArrayBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||||
public ArrayBinder() {
|
super( semanticsResolver, buildingContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass owner) {
|
||||||
return new Array( getBuildingContext(), persistentClass );
|
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>.
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg.annotations;
|
package org.hibernate.cfg.annotations;
|
||||||
|
|
||||||
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a bag.
|
* Bind a bag.
|
||||||
|
@ -14,11 +17,11 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
* @author Matthew Inger
|
* @author Matthew Inger
|
||||||
*/
|
*/
|
||||||
public class BagBinder extends CollectionBinder {
|
public class BagBinder extends CollectionBinder {
|
||||||
public BagBinder() {
|
public BagBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext context) {
|
||||||
super( false );
|
super( semanticsResolver, false, context );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass owner) {
|
||||||
return new org.hibernate.mapping.Bag( getBuildingContext(), persistentClass );
|
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.PropertyInferredData;
|
||||||
import org.hibernate.cfg.PropertyPreloadedData;
|
import org.hibernate.cfg.PropertyPreloadedData;
|
||||||
import org.hibernate.cfg.SecondPass;
|
import org.hibernate.cfg.SecondPass;
|
||||||
|
import org.hibernate.collection.internal.CustomCollectionTypeSemantics;
|
||||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||||
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
|
import org.hibernate.jpa.spi.MutableJpaCompliance;
|
||||||
import org.hibernate.mapping.Any;
|
import org.hibernate.mapping.Any;
|
||||||
import org.hibernate.mapping.Backref;
|
import org.hibernate.mapping.Backref;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
|
@ -89,8 +91,10 @@ import org.hibernate.mapping.ManyToOne;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Selectable;
|
import org.hibernate.mapping.Selectable;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.EmbeddableInstantiator;
|
import org.hibernate.metamodel.EmbeddableInstantiator;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -134,7 +138,9 @@ public abstract class CollectionBinder {
|
||||||
java.util.Collection.class
|
java.util.Collection.class
|
||||||
);
|
);
|
||||||
|
|
||||||
private MetadataBuildingContext buildingContext;
|
private final MetadataBuildingContext buildingContext;
|
||||||
|
private final SemanticsResolver semanticsResolver;
|
||||||
|
private final boolean isSortedCollection;
|
||||||
|
|
||||||
protected Collection collection;
|
protected Collection collection;
|
||||||
protected String propertyName;
|
protected String propertyName;
|
||||||
|
@ -169,7 +175,6 @@ public abstract class CollectionBinder {
|
||||||
private AccessType accessType;
|
private AccessType accessType;
|
||||||
private boolean hibernateExtensionMapping;
|
private boolean hibernateExtensionMapping;
|
||||||
|
|
||||||
private boolean isSortedCollection;
|
|
||||||
private jakarta.persistence.OrderBy jpaOrderBy;
|
private jakarta.persistence.OrderBy jpaOrderBy;
|
||||||
private OrderBy sqlOrderBy;
|
private OrderBy sqlOrderBy;
|
||||||
private SortNatural naturalSort;
|
private SortNatural naturalSort;
|
||||||
|
@ -178,16 +183,18 @@ public abstract class CollectionBinder {
|
||||||
private String explicitType;
|
private String explicitType;
|
||||||
private final Properties explicitTypeParameters = new Properties();
|
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.isSortedCollection = isSortedCollection;
|
||||||
|
this.buildingContext = buildingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MetadataBuildingContext getBuildingContext() {
|
protected MetadataBuildingContext getBuildingContext() {
|
||||||
return buildingContext;
|
return buildingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBuildingContext(MetadataBuildingContext buildingContext) {
|
protected SemanticsResolver getSemanticsResolver() {
|
||||||
this.buildingContext = buildingContext;
|
return semanticsResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMap() {
|
public boolean isMap() {
|
||||||
|
@ -260,151 +267,185 @@ public abstract class CollectionBinder {
|
||||||
* collection binder factory
|
* collection binder factory
|
||||||
*/
|
*/
|
||||||
public static CollectionBinder getCollectionBinder(
|
public static CollectionBinder getCollectionBinder(
|
||||||
String entityName,
|
|
||||||
XProperty property,
|
XProperty property,
|
||||||
boolean isIndexed,
|
boolean isIndexed,
|
||||||
boolean isHibernateExtensionMapping,
|
boolean isHibernateExtensionMapping,
|
||||||
MetadataBuildingContext buildingContext) {
|
MetadataBuildingContext buildingContext) {
|
||||||
final CollectionBinder result;
|
final CollectionType typeAnnotation = property.getAnnotation( CollectionType.class );
|
||||||
|
|
||||||
if ( property.isArray() ) {
|
final CollectionBinder binder;
|
||||||
if ( property.getElementClass().isPrimitive() ) {
|
if ( typeAnnotation != null ) {
|
||||||
result = new PrimitiveArrayBinder();
|
binder = createBinderFromCustomTypeAnnotation( property, isIndexed, typeAnnotation, buildingContext );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = new ArrayBinder();
|
binder = createBinderFromProperty( property, isIndexed, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
|
binder.setIsHibernateExtensionMapping( isHibernateExtensionMapping );
|
||||||
|
|
||||||
|
if ( typeAnnotation != null ) {
|
||||||
|
binder.explicitType = typeAnnotation.type();
|
||||||
|
for ( Parameter param : typeAnnotation.parameters() ) {
|
||||||
|
binder.explicitTypeParameters.setProperty( param.name(), param.value() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( property.isCollection() ) {
|
|
||||||
//TODO consider using an XClass
|
|
||||||
final Class<?> returnedClass = property.getCollectionClass();
|
|
||||||
|
|
||||||
final CollectionBinder basicBinder = getBinderFromBasicCollectionType(
|
return binder;
|
||||||
returnedClass,
|
}
|
||||||
property,
|
|
||||||
entityName,
|
private static CollectionBinder createBinderFromProperty(
|
||||||
isIndexed
|
XProperty property,
|
||||||
);
|
boolean isIndexed,
|
||||||
if ( basicBinder != null ) {
|
MetadataBuildingContext buildingContext) {
|
||||||
result = basicBinder;
|
final CollectionClassification classification = determineCollectionClassification( property, null, isIndexed, buildingContext );
|
||||||
|
return createBinder( property, classification, null, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ArrayBinder( semanticsResolver, buildingContext );
|
||||||
}
|
}
|
||||||
else if ( property.isAnnotationPresent( CollectionType.class ) ) {
|
case BAG: {
|
||||||
Class<?> semanticsClass = property.getAnnotation( CollectionType.class ).semantics();
|
return new BagBinder( semanticsResolver, buildingContext );
|
||||||
|
}
|
||||||
|
case IDBAG: {
|
||||||
|
return new IdBagBinder( semanticsResolver, buildingContext );
|
||||||
|
}
|
||||||
|
case LIST: {
|
||||||
|
return new ListBinder( semanticsResolver, buildingContext );
|
||||||
|
}
|
||||||
|
case MAP:
|
||||||
|
case ORDERED_MAP: {
|
||||||
|
return new MapBinder( semanticsResolver, false, buildingContext );
|
||||||
|
}
|
||||||
|
case SORTED_MAP: {
|
||||||
|
return new MapBinder( semanticsResolver, true, buildingContext );
|
||||||
|
}
|
||||||
|
case SET:
|
||||||
|
case ORDERED_SET: {
|
||||||
|
return new SetBinder( semanticsResolver, false, buildingContext );
|
||||||
|
}
|
||||||
|
case SORTED_SET: {
|
||||||
|
return new SetBinder( semanticsResolver, true, buildingContext );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( semanticsClass != void.class ) {
|
final XClass declaringClass = property.getDeclaringClass();
|
||||||
result = getBinderFromBasicCollectionType( semanticsClass, property, entityName, isIndexed );
|
|
||||||
}
|
throw new AnnotationException(
|
||||||
else {
|
String.format(
|
||||||
final Class<?> inferredClass = inferCollectionClassFromSubclass( returnedClass );
|
Locale.ROOT,
|
||||||
result = inferredClass != null ? getBinderFromBasicCollectionType(
|
"Unable to determine proper CollectionBinder (`%s) : %s.%s",
|
||||||
inferredClass,
|
classification,
|
||||||
property,
|
declaringClass.getName(),
|
||||||
entityName,
|
property.getName()
|
||||||
isIndexed
|
)
|
||||||
) : null;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CollectionClassification determineCollectionClassification(
|
||||||
|
XProperty property,
|
||||||
|
CollectionType typeAnnotation,
|
||||||
|
boolean isIndexed,
|
||||||
|
MetadataBuildingContext buildingContext) {
|
||||||
|
if ( property.isArray() ) {
|
||||||
|
return CollectionClassification.ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
else {
|
||||||
result = null;
|
return CollectionClassification.BAG;
|
||||||
}
|
|
||||||
if ( result == null ) {
|
|
||||||
throw new AnnotationException(
|
|
||||||
returnedClass.getName() + " collection type not supported for property: "
|
|
||||||
+ StringHelper.qualify( entityName, property.getName() )
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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(
|
throw new AnnotationException(
|
||||||
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @ElementCollection: "
|
String.format(
|
||||||
+ StringHelper.qualify( entityName, property.getName() )
|
Locale.ROOT,
|
||||||
|
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: %s.%s",
|
||||||
|
property.getDeclaringClass().getName(),
|
||||||
|
property.getName()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
result.setIsHibernateExtensionMapping( isHibernateExtensionMapping );
|
|
||||||
|
|
||||||
final CollectionType typeAnnotation = property.getAnnotation( CollectionType.class );
|
return inferCollectionClassFromSubclass( returnedJavaType, isIndexed, buildingContext );
|
||||||
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() );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result.explicitType = typeName;
|
|
||||||
for ( Parameter param : typeAnnotation.parameters() ) {
|
|
||||||
result.explicitTypeParameters.setProperty( param.name(), param.value() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CollectionBinder getBinderFromBasicCollectionType(Class<?> clazz, XProperty property,
|
private static Class<?> inferCollectionClassFromSubclass(Class<?> clazz, boolean isIndexed, MetadataBuildingContext buildingContext) {
|
||||||
String entityName, boolean isIndexed) {
|
if ( java.util.List.class.isAssignableFrom( clazz ) && !isIndexed ) {
|
||||||
if ( java.util.Set.class.equals( clazz) ) {
|
final MutableJpaCompliance jpaCompliance = buildingContext.getBootstrapContext().getJpaCompliance();
|
||||||
if ( property.isAnnotationPresent( CollectionId.class) ) {
|
return jpaCompliance.isJpaListComplianceEnabled()
|
||||||
throw new AnnotationException("Set does not support @CollectionId: "
|
? java.util.List.class
|
||||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
: java.util.Collection.class;
|
||||||
}
|
|
||||||
return new SetBinder( false );
|
|
||||||
}
|
}
|
||||||
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() ) );
|
|
||||||
}
|
|
||||||
return new SetBinder( true );
|
|
||||||
}
|
|
||||||
else if ( Map.class.equals( clazz ) ) {
|
|
||||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
|
||||||
throw new AnnotationException( "Map does not support @CollectionId: "
|
|
||||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
|
||||||
}
|
|
||||||
return new MapBinder( false );
|
|
||||||
}
|
|
||||||
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() ) );
|
|
||||||
}
|
|
||||||
return new MapBinder( true );
|
|
||||||
}
|
|
||||||
else if ( java.util.Collection.class.equals( clazz ) ) {
|
|
||||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
|
||||||
return new IdBagBinder();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new BagBinder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( List.class.equals( clazz ) ) {
|
|
||||||
if ( isIndexed ) {
|
|
||||||
if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
|
||||||
throw new AnnotationException(
|
|
||||||
"List does not support @CollectionId and @OrderColumn (or @IndexColumn) at the same time: "
|
|
||||||
+ StringHelper.qualify( entityName, property.getName() ) );
|
|
||||||
}
|
|
||||||
return new ListBinder();
|
|
||||||
}
|
|
||||||
else if ( property.isAnnotationPresent( CollectionId.class ) ) {
|
|
||||||
return new IdBagBinder();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new BagBinder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Class<?> inferCollectionClassFromSubclass(Class<?> clazz) {
|
|
||||||
for ( Class<?> priorityClass : INFERRED_CLASS_PRIORITY ) {
|
for ( Class<?> priorityClass : INFERRED_CLASS_PRIORITY ) {
|
||||||
if ( priorityClass.isAssignableFrom( clazz ) ) {
|
if ( priorityClass.isAssignableFrom( clazz ) ) {
|
||||||
return priorityClass;
|
return priorityClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,7 +529,8 @@ public abstract class CollectionBinder {
|
||||||
|
|
||||||
Persister persisterAnn = property.getAnnotation( Persister.class );
|
Persister persisterAnn = property.getAnnotation( Persister.class );
|
||||||
if ( persisterAnn != null ) {
|
if ( persisterAnn != null ) {
|
||||||
collection.setCollectionPersisterClass( persisterAnn.impl() );
|
//noinspection rawtypes
|
||||||
|
collection.setCollectionPersisterClass( (Class) persisterAnn.impl() );
|
||||||
}
|
}
|
||||||
|
|
||||||
applySortingAndOrdering( collection );
|
applySortingAndOrdering( collection );
|
||||||
|
@ -614,37 +656,32 @@ public abstract class CollectionBinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applySortingAndOrdering(Collection collection) {
|
private void applySortingAndOrdering(Collection collection) {
|
||||||
boolean hadOrderBy = false;
|
final boolean hadExplicitSort;
|
||||||
boolean hadExplicitSort = false;
|
final Class<? extends Comparator<?>> comparatorClass;
|
||||||
|
|
||||||
Class<? extends Comparator<?>> comparatorClass = null;
|
if ( naturalSort != null ) {
|
||||||
|
if ( comparatorSort != null ) {
|
||||||
if ( jpaOrderBy == null && sqlOrderBy == null ) {
|
throw buildIllegalSortCombination();
|
||||||
if ( naturalSort != null ) {
|
|
||||||
if ( comparatorSort != null ) {
|
|
||||||
throw buildIllegalSortCombination();
|
|
||||||
}
|
|
||||||
hadExplicitSort = true;
|
|
||||||
}
|
|
||||||
else if ( comparatorSort != null ) {
|
|
||||||
hadExplicitSort = true;
|
|
||||||
comparatorClass = comparatorSort.value();
|
|
||||||
}
|
}
|
||||||
|
hadExplicitSort = true;
|
||||||
|
comparatorClass = null;
|
||||||
|
}
|
||||||
|
else if ( comparatorSort != null ) {
|
||||||
|
hadExplicitSort = true;
|
||||||
|
comparatorClass = comparatorSort.value();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
hadExplicitSort = false;
|
||||||
|
comparatorClass = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hadOrderBy = false;
|
||||||
|
if ( jpaOrderBy != null || sqlOrderBy != null ) {
|
||||||
if ( jpaOrderBy != null && sqlOrderBy != null ) {
|
if ( jpaOrderBy != null && sqlOrderBy != null ) {
|
||||||
throw new AnnotationException(
|
throw buildIllegalOrderCombination();
|
||||||
String.format(
|
|
||||||
"Illegal combination of @%s and @%s on %s",
|
|
||||||
jakarta.persistence.OrderBy.class.getName(),
|
|
||||||
OrderBy.class.getName(),
|
|
||||||
safeCollectionRole()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hadOrderBy = true;
|
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
|
// we can only apply the sql-based order by up front. The jpa order by has to wait for second pass
|
||||||
if ( sqlOrderBy != null ) {
|
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 ) {
|
if ( comparatorClass != null ) {
|
||||||
try {
|
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() {
|
private AnnotationException buildIllegalSortCombination() {
|
||||||
return new AnnotationException(
|
return new AnnotationException(
|
||||||
String.format(
|
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(),
|
safeCollectionRole(),
|
||||||
SortNatural.class.getName(),
|
SortNatural.class.getName(),
|
||||||
SortComparator.class.getName()
|
SortComparator.class.getName()
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.hibernate.mapping.BasicValue;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.IdentifierCollection;
|
import org.hibernate.mapping.IdentifierCollection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
|
@ -34,11 +35,12 @@ import jakarta.persistence.Column;
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
*/
|
*/
|
||||||
public class IdBagBinder extends BagBinder {
|
public class IdBagBinder extends BagBinder {
|
||||||
public IdBagBinder() {
|
public IdBagBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, buildingContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass owner) {
|
||||||
return new org.hibernate.mapping.IdentifierBag( getBuildingContext(), persistentClass );
|
return new org.hibernate.mapping.IdentifierBag( getSemanticsResolver(), owner, getBuildingContext() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.hibernate.mapping.IndexBackref;
|
||||||
import org.hibernate.mapping.List;
|
import org.hibernate.mapping.List;
|
||||||
import org.hibernate.mapping.OneToMany;
|
import org.hibernate.mapping.OneToMany;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -41,13 +42,13 @@ import org.jboss.logging.Logger;
|
||||||
public class ListBinder extends CollectionBinder {
|
public class ListBinder extends CollectionBinder {
|
||||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, ListBinder.class.getName() );
|
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, ListBinder.class.getName() );
|
||||||
|
|
||||||
public ListBinder() {
|
public ListBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||||
super( false );
|
super( semanticsResolver, false, buildingContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass owner) {
|
||||||
return new List( getBuildingContext(), persistentClass );
|
return new List( getSemanticsResolver(), owner, getBuildingContext() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,15 +9,6 @@ package org.hibernate.cfg.annotations;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
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.AnnotationException;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
|
@ -40,27 +31,32 @@ import org.hibernate.cfg.PropertyData;
|
||||||
import org.hibernate.cfg.PropertyHolderBuilder;
|
import org.hibernate.cfg.PropertyHolderBuilder;
|
||||||
import org.hibernate.cfg.PropertyPreloadedData;
|
import org.hibernate.cfg.PropertyPreloadedData;
|
||||||
import org.hibernate.cfg.SecondPass;
|
import org.hibernate.cfg.SecondPass;
|
||||||
import org.hibernate.dialect.Dialect;
|
|
||||||
import org.hibernate.engine.jdbc.Size;
|
import org.hibernate.engine.jdbc.Size;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.mapping.BasicValue;
|
import org.hibernate.mapping.BasicValue;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.DependantBasicValue;
|
import org.hibernate.mapping.DependantBasicValue;
|
||||||
import org.hibernate.mapping.DependantValue;
|
|
||||||
import org.hibernate.mapping.Formula;
|
import org.hibernate.mapping.Formula;
|
||||||
import org.hibernate.mapping.ManyToOne;
|
import org.hibernate.mapping.ManyToOne;
|
||||||
import org.hibernate.mapping.OneToMany;
|
import org.hibernate.mapping.OneToMany;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.mapping.Selectable;
|
import org.hibernate.mapping.Selectable;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
import org.hibernate.mapping.SimpleValue;
|
import org.hibernate.mapping.SimpleValue;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.mapping.ToOne;
|
|
||||||
import org.hibernate.mapping.Value;
|
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
|
* Implementation to bind a Map
|
||||||
|
@ -68,16 +64,16 @@ import org.hibernate.sql.Template;
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
*/
|
*/
|
||||||
public class MapBinder extends CollectionBinder {
|
public class MapBinder extends CollectionBinder {
|
||||||
public MapBinder(boolean sorted) {
|
public MapBinder(SemanticsResolver semanticsResolver, boolean sorted, MetadataBuildingContext buildingContext) {
|
||||||
super( sorted );
|
super( semanticsResolver, sorted, buildingContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMap() {
|
public boolean isMap() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass owner) {
|
||||||
return new org.hibernate.mapping.Map( getBuildingContext(), persistentClass );
|
return new org.hibernate.mapping.Map( getSemanticsResolver(), owner, getBuildingContext() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,16 +6,22 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.cfg.annotations;
|
package org.hibernate.cfg.annotations;
|
||||||
|
|
||||||
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.PrimitiveArray;
|
import org.hibernate.mapping.PrimitiveArray;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Emmanuel Bernard
|
* @author Emmanuel Bernard
|
||||||
*/
|
*/
|
||||||
public class PrimitiveArrayBinder extends ArrayBinder {
|
public class PrimitiveArrayBinder extends ArrayBinder {
|
||||||
|
public PrimitiveArrayBinder(SemanticsResolver semanticsResolver, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass owner) {
|
||||||
return new PrimitiveArray( getBuildingContext(), persistentClass );
|
return new PrimitiveArray( getSemanticsResolver(), owner, getBuildingContext() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,10 @@
|
||||||
package org.hibernate.cfg.annotations;
|
package org.hibernate.cfg.annotations;
|
||||||
|
|
||||||
import org.hibernate.annotations.OrderBy;
|
import org.hibernate.annotations.OrderBy;
|
||||||
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
|
import org.hibernate.mapping.SemanticsResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a set.
|
* Bind a set.
|
||||||
|
@ -16,13 +18,13 @@ import org.hibernate.mapping.PersistentClass;
|
||||||
* @author Matthew Inger
|
* @author Matthew Inger
|
||||||
*/
|
*/
|
||||||
public class SetBinder extends CollectionBinder {
|
public class SetBinder extends CollectionBinder {
|
||||||
public SetBinder(boolean sorted) {
|
public SetBinder(SemanticsResolver semanticsResolver, boolean sorted, MetadataBuildingContext buildingContext) {
|
||||||
super( sorted );
|
super( semanticsResolver, sorted, buildingContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Collection createCollection(PersistentClass persistentClass) {
|
protected Collection createCollection(PersistentClass persistentClass) {
|
||||||
return new org.hibernate.mapping.Set( getBuildingContext(), persistentClass );
|
return new org.hibernate.mapping.Set( getSemanticsResolver(), persistentClass, getBuildingContext() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -13,14 +13,12 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.collection.spi.BagSemantics;
|
import org.hibernate.collection.spi.BagSemantics;
|
||||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
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.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
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.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
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
|
@Override
|
||||||
public CollectionInitializerProducer createInitializerProducer(
|
public CollectionInitializerProducer createInitializerProducer(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -98,31 +67,14 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
Fetch indexFetch,
|
Fetch indexFetch,
|
||||||
Fetch elementFetch,
|
Fetch elementFetch,
|
||||||
DomainResultCreationState creationState){
|
DomainResultCreationState creationState) {
|
||||||
if ( indexFetch == null ) {
|
return InitializerProducerBuilder.createBagInitializerProducer(
|
||||||
indexFetch = attributeMapping.getIdentifierDescriptor() == null ? null : fetchParent.generateFetchableFetch(
|
navigablePath,
|
||||||
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(
|
|
||||||
attributeMapping,
|
attributeMapping,
|
||||||
indexFetch,
|
fetchParent,
|
||||||
elementFetch
|
selected,
|
||||||
|
elementFetch,
|
||||||
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,11 @@ import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||||
|
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||||
import org.hibernate.collection.spi.MapSemantics;
|
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.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
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.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
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
|
@Override
|
||||||
public CollectionInitializerProducer createInitializerProducer(
|
public CollectionInitializerProducer createInitializerProducer(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -110,31 +79,15 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
Fetch indexFetch,
|
Fetch indexFetch,
|
||||||
Fetch elementFetch,
|
Fetch elementFetch,
|
||||||
DomainResultCreationState creationState){
|
DomainResultCreationState creationState) {
|
||||||
if ( indexFetch == null ) {
|
return InitializerProducerBuilder.createMapInitializerProducer(
|
||||||
indexFetch = fetchParent.generateFetchableFetch(
|
navigablePath,
|
||||||
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,
|
attributeMapping,
|
||||||
|
fetchParent,
|
||||||
|
selected,
|
||||||
indexFetch,
|
indexFetch,
|
||||||
elementFetch
|
elementFetch,
|
||||||
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,11 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||||
import org.hibernate.collection.spi.CollectionSemantics;
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.query.NavigablePath;
|
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.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
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
|
@Override
|
||||||
public CollectionInitializerProducer createInitializerProducer(
|
public CollectionInitializerProducer createInitializerProducer(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -75,17 +52,15 @@ public abstract class AbstractSetSemantics<SE extends Set<E>,E> implements Colle
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
Fetch indexFetch,
|
Fetch indexFetch,
|
||||||
Fetch elementFetch,
|
Fetch elementFetch,
|
||||||
DomainResultCreationState creationState){
|
DomainResultCreationState creationState) {
|
||||||
if ( elementFetch == null ) {
|
assert indexFetch == null;
|
||||||
return createInitializerProducer(
|
return InitializerProducerBuilder.createSetInitializerProducer(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
attributeMapping,
|
attributeMapping,
|
||||||
fetchParent,
|
fetchParent,
|
||||||
selected,
|
selected,
|
||||||
resultVariable,
|
elementFetch,
|
||||||
creationState
|
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.CollectionInitializerProducer;
|
||||||
import org.hibernate.collection.spi.CollectionSemantics;
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
|
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.engine.FetchTiming;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.CollectionClassification;
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
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;
|
import org.hibernate.type.CollectionType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,16 +29,17 @@ import org.hibernate.type.CollectionType;
|
||||||
* @author Christian Beikov
|
* @author Christian Beikov
|
||||||
*/
|
*/
|
||||||
public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics<CE, E> {
|
public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics<CE, E> {
|
||||||
|
|
||||||
private final CollectionType collectionType;
|
private final CollectionType collectionType;
|
||||||
|
private final CollectionClassification classification;
|
||||||
|
|
||||||
public CustomCollectionTypeSemantics(CollectionType collectionType) {
|
public CustomCollectionTypeSemantics(CollectionType collectionType, CollectionClassification classification) {
|
||||||
this.collectionType = collectionType;
|
this.collectionType = collectionType;
|
||||||
|
this.classification = classification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionClassification getCollectionClassification() {
|
public CollectionClassification getCollectionClassification() {
|
||||||
return CollectionClassification.BAG;
|
return classification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,11 +49,13 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CE instantiateRaw(int anticipatedSize, CollectionPersister collectionDescriptor) {
|
public CE instantiateRaw(int anticipatedSize, CollectionPersister collectionDescriptor) {
|
||||||
|
//noinspection unchecked
|
||||||
return (CE) collectionType.instantiate( anticipatedSize );
|
return (CE) collectionType.instantiate( anticipatedSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<E> getElementIterator(CE rawCollection) {
|
public Iterator<E> getElementIterator(CE rawCollection) {
|
||||||
|
//noinspection unchecked
|
||||||
return collectionType.getElementsIterator( rawCollection, null );
|
return collectionType.getElementsIterator( rawCollection, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,47 +64,6 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
||||||
getElementIterator( rawCollection ).forEachRemaining( action );
|
getElementIterator( rawCollection ).forEachRemaining( action );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public CollectionInitializerProducer createInitializerProducer(
|
|
||||||
NavigablePath navigablePath,
|
|
||||||
PluralAttributeMapping attributeMapping,
|
|
||||||
FetchParent fetchParent,
|
|
||||||
boolean selected,
|
|
||||||
String resultVariable,
|
|
||||||
DomainResultCreationState creationState) {
|
|
||||||
final Fetch indexFetch;
|
|
||||||
if ( attributeMapping.getIndexDescriptor() == null ) {
|
|
||||||
indexFetch = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
indexFetch = fetchParent.generateFetchableFetch(
|
|
||||||
attributeMapping.getIndexDescriptor(),
|
|
||||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
|
||||||
FetchTiming.IMMEDIATE,
|
|
||||||
selected,
|
|
||||||
null,
|
|
||||||
creationState
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final Fetch elementFetch = fetchParent.generateFetchableFetch(
|
|
||||||
attributeMapping.getElementDescriptor(),
|
|
||||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
|
||||||
FetchTiming.IMMEDIATE,
|
|
||||||
selected,
|
|
||||||
null,
|
|
||||||
creationState
|
|
||||||
);
|
|
||||||
if ( indexFetch == null ) {
|
|
||||||
return new BagInitializerProducer( attributeMapping, null, elementFetch );
|
|
||||||
}
|
|
||||||
else if ( indexFetch.getResultJavaTypeDescriptor().getJavaTypeClass() == Integer.class ) {
|
|
||||||
return new ListInitializerProducer( attributeMapping, indexFetch, elementFetch );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new MapInitializerProducer( attributeMapping, indexFetch, elementFetch );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionInitializerProducer createInitializerProducer(
|
public CollectionInitializerProducer createInitializerProducer(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -116,35 +74,16 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
||||||
Fetch indexFetch,
|
Fetch indexFetch,
|
||||||
Fetch elementFetch,
|
Fetch elementFetch,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
if ( indexFetch == null ) {
|
return InitializerProducerBuilder.createCollectionTypeWrapperInitializerProducer(
|
||||||
indexFetch = fetchParent.generateFetchableFetch(
|
navigablePath,
|
||||||
attributeMapping.getIndexDescriptor(),
|
attributeMapping,
|
||||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
classification,
|
||||||
FetchTiming.IMMEDIATE,
|
fetchParent,
|
||||||
selected,
|
selected,
|
||||||
null,
|
indexFetch,
|
||||||
creationState
|
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
|
@Override
|
||||||
|
@ -152,6 +91,7 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
||||||
Object key,
|
Object key,
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
|
//noinspection unchecked
|
||||||
return collectionType.instantiate( session, collectionDescriptor, key );
|
return collectionType.instantiate( session, collectionDescriptor, key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +100,7 @@ public class CustomCollectionTypeSemantics<CE, E> implements CollectionSemantics
|
||||||
CE rawCollection,
|
CE rawCollection,
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
|
//noinspection unchecked
|
||||||
return collectionType.wrap( session, rawCollection );
|
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.CollectionInitializerProducer;
|
||||||
import org.hibernate.collection.spi.CollectionSemantics;
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
|
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.engine.FetchTiming;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.CollectionClassification;
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
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.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
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
|
@Override
|
||||||
public CollectionInitializerProducer createInitializerProducer(
|
public CollectionInitializerProducer createInitializerProducer(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -131,31 +100,15 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
Fetch indexFetch,
|
Fetch indexFetch,
|
||||||
Fetch elementFetch,
|
Fetch elementFetch,
|
||||||
DomainResultCreationState creationState){
|
DomainResultCreationState creationState) {
|
||||||
if ( indexFetch == null ) {
|
return InitializerProducerBuilder.createArrayInitializerProducer(
|
||||||
indexFetch = fetchParent.generateFetchableFetch(
|
navigablePath,
|
||||||
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,
|
attributeMapping,
|
||||||
|
fetchParent,
|
||||||
|
selected,
|
||||||
indexFetch,
|
indexFetch,
|
||||||
elementFetch
|
elementFetch,
|
||||||
|
creationState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,18 +12,16 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
import org.hibernate.collection.spi.CollectionInitializerProducer;
|
||||||
import org.hibernate.collection.spi.CollectionSemantics;
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
|
import org.hibernate.collection.spi.InitializerProducerBuilder;
|
||||||
import org.hibernate.collection.spi.PersistentCollection;
|
import org.hibernate.collection.spi.PersistentCollection;
|
||||||
import org.hibernate.engine.FetchTiming;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.metamodel.CollectionClassification;
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
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.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,6 +43,7 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
||||||
return CollectionClassification.LIST;
|
return CollectionClassification.LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
public Class<List> getCollectionJavaType() {
|
public Class<List> getCollectionJavaType() {
|
||||||
return List.class;
|
return List.class;
|
||||||
|
@ -67,72 +66,6 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
||||||
rawCollection.forEach( action );
|
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
|
@Override
|
||||||
public PersistentCollection<E> instantiateWrapper(
|
public PersistentCollection<E> instantiateWrapper(
|
||||||
Object key,
|
Object key,
|
||||||
|
@ -148,4 +81,17 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
return new PersistentList<>( session, rawCollection );
|
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 java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.metamodel.CollectionClassification;
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||||
|
@ -36,38 +35,69 @@ public interface CollectionSemantics<CE, E> {
|
||||||
*/
|
*/
|
||||||
CollectionClassification getCollectionClassification();
|
CollectionClassification getCollectionClassification();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The collection's Java type
|
||||||
|
*/
|
||||||
Class<?> getCollectionJavaType();
|
Class<?> getCollectionJavaType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a raw (unwrapped) version of the collection
|
||||||
|
*/
|
||||||
CE instantiateRaw(
|
CE instantiateRaw(
|
||||||
int anticipatedSize,
|
int anticipatedSize,
|
||||||
CollectionPersister collectionDescriptor);
|
CollectionPersister collectionDescriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a wrapper for the collection
|
||||||
|
*/
|
||||||
PersistentCollection<E> instantiateWrapper(
|
PersistentCollection<E> instantiateWrapper(
|
||||||
Object key,
|
Object key,
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
SharedSessionContractImplementor session);
|
SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap a raw collection in wrapper
|
||||||
|
*/
|
||||||
PersistentCollection<E> wrap(
|
PersistentCollection<E> wrap(
|
||||||
CE rawCollection,
|
CE rawCollection,
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
SharedSessionContractImplementor session);
|
SharedSessionContractImplementor session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain an iterator over the collection elements
|
||||||
|
*/
|
||||||
Iterator<E> getElementIterator(CE rawCollection);
|
Iterator<E> getElementIterator(CE rawCollection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit the elements of the collection
|
||||||
|
*/
|
||||||
void visitElements(CE rawCollection, Consumer<? super E> action);
|
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,
|
NavigablePath navigablePath,
|
||||||
PluralAttributeMapping attributeMapping,
|
PluralAttributeMapping attributeMapping,
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
boolean selected,
|
boolean selected,
|
||||||
String resultVariable,
|
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,
|
NavigablePath navigablePath,
|
||||||
PluralAttributeMapping attributeMapping,
|
PluralAttributeMapping attributeMapping,
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
|
@ -75,5 +105,16 @@ public interface CollectionSemantics<CE, E> {
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
Fetch indexFetch,
|
Fetch indexFetch,
|
||||||
Fetch elementFetch,
|
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;
|
package org.hibernate.mapping;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
|
||||||
|
@ -29,7 +31,11 @@ public class Array extends List {
|
||||||
super( buildingContext, owner );
|
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 ) {
|
if ( elementClassName == null ) {
|
||||||
final org.hibernate.type.Type elementType = getElement().getType();
|
final org.hibernate.type.Type elementType = getElement().getType();
|
||||||
if ( isPrimitiveArray() ) {
|
if ( isPrimitiveArray() ) {
|
||||||
|
@ -51,7 +57,7 @@ public class Array extends List {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionSemantics getDefaultCollectionSemantics() {
|
public CollectionSemantics<?,?> getDefaultCollectionSemantics() {
|
||||||
return StandardArraySemantics.INSTANCE;
|
return StandardArraySemantics.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.mapping;
|
package org.hibernate.mapping;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.collection.internal.StandardBagSemantics;
|
import org.hibernate.collection.internal.StandardBagSemantics;
|
||||||
import org.hibernate.collection.spi.CollectionSemantics;
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
|
@ -18,10 +20,20 @@ import org.hibernate.type.CollectionType;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class Bag extends Collection {
|
public class Bag extends Collection {
|
||||||
|
/**
|
||||||
|
* hbm.xml binding
|
||||||
|
*/
|
||||||
public Bag(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
public Bag(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation binding
|
||||||
|
*/
|
||||||
|
public Bag(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
public CollectionType getDefaultCollectionType() {
|
public CollectionType getDefaultCollectionType() {
|
||||||
return new BagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() );
|
return new BagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
import org.hibernate.FetchMode;
|
import org.hibernate.FetchMode;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
@ -27,6 +29,8 @@ import org.hibernate.engine.spi.Mapping;
|
||||||
import org.hibernate.internal.FilterConfiguration;
|
import org.hibernate.internal.FilterConfiguration;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
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.service.ServiceRegistry;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -63,18 +67,21 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
private String referencedPropertyName;
|
private String referencedPropertyName;
|
||||||
private String mappedByProperty;
|
private String mappedByProperty;
|
||||||
private boolean sorted;
|
private boolean sorted;
|
||||||
private Comparator comparator;
|
private Comparator<?> comparator;
|
||||||
private String comparatorClassName;
|
private String comparatorClassName;
|
||||||
private boolean orphanDelete;
|
private boolean orphanDelete;
|
||||||
private int batchSize = -1;
|
private int batchSize = -1;
|
||||||
private FetchMode fetchMode;
|
private FetchMode fetchMode;
|
||||||
private boolean embedded = true;
|
private boolean embedded = true;
|
||||||
private boolean optimisticLocked = true;
|
private boolean optimisticLocked = true;
|
||||||
private Class collectionPersisterClass;
|
|
||||||
private String typeName;
|
private String typeName;
|
||||||
private Properties typeParameters;
|
private Properties typeParameters;
|
||||||
private final List filters = new ArrayList();
|
private SemanticsResolver customSemanticsResolver;
|
||||||
private final List manyToManyFilters = new ArrayList();
|
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 final java.util.Set<String> synchronizedTables = new HashSet<>();
|
||||||
|
|
||||||
private String customSQLInsert;
|
private String customSQLInsert;
|
||||||
|
@ -92,11 +99,23 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
|
|
||||||
private String loaderName;
|
private String loaderName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hbm.xml binding
|
||||||
|
*/
|
||||||
protected Collection(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
protected Collection(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||||
this.buildingContext = buildingContext;
|
this.buildingContext = buildingContext;
|
||||||
this.owner = owner;
|
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() {
|
public MetadataBuildingContext getBuildingContext() {
|
||||||
return buildingContext;
|
return buildingContext;
|
||||||
}
|
}
|
||||||
|
@ -142,13 +161,13 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Comparator getComparator() {
|
public Comparator<?> getComparator() {
|
||||||
if ( comparator == null && comparatorClassName != null ) {
|
if ( comparator == null && comparatorClassName != null ) {
|
||||||
try {
|
try {
|
||||||
final ClassLoaderService classLoaderService = getMetadata().getMetadataBuildingOptions()
|
final ClassLoaderService classLoaderService = getMetadata().getMetadataBuildingOptions()
|
||||||
.getServiceRegistry()
|
.getServiceRegistry()
|
||||||
.getService( ClassLoaderService.class );
|
.getService( ClassLoaderService.class );
|
||||||
setComparator( (Comparator) classLoaderService.classForName( comparatorClassName ).newInstance() );
|
setComparator( (Comparator<?>) classLoaderService.classForName( comparatorClassName ).getConstructor().newInstance() );
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new MappingException(
|
throw new MappingException(
|
||||||
|
@ -202,7 +221,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
return orderBy;
|
return orderBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setComparator(Comparator comparator) {
|
public void setComparator(@SuppressWarnings("rawtypes") Comparator comparator) {
|
||||||
this.comparator = comparator;
|
this.comparator = comparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,11 +315,11 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
this.fetchMode = fetchMode;
|
this.fetchMode = fetchMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCollectionPersisterClass(Class persister) {
|
public void setCollectionPersisterClass(Class<? extends CollectionPersister> persister) {
|
||||||
this.collectionPersisterClass = persister;
|
this.collectionPersisterClass = persister;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class getCollectionPersisterClass() {
|
public Class<? extends CollectionPersister> getCollectionPersisterClass() {
|
||||||
return collectionPersisterClass;
|
return collectionPersisterClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +347,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
checkColumnDuplication();
|
checkColumnDuplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkColumnDuplication(java.util.Set distinctColumns, Value value)
|
private void checkColumnDuplication(java.util.Set<String> distinctColumns, Value value)
|
||||||
throws MappingException {
|
throws MappingException {
|
||||||
final boolean[] insertability = value.getColumnInsertability();
|
final boolean[] insertability = value.getColumnInsertability();
|
||||||
final boolean[] updatability = value.getColumnUpdateability();
|
final boolean[] updatability = value.getColumnUpdateability();
|
||||||
|
@ -354,7 +373,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkColumnDuplication() throws MappingException {
|
private void checkColumnDuplication() throws MappingException {
|
||||||
HashSet cols = new HashSet();
|
HashSet<String> cols = new HashSet<>();
|
||||||
checkColumnDuplication( cols, getKey() );
|
checkColumnDuplication( cols, getKey() );
|
||||||
if ( isIndexed() ) {
|
if ( isIndexed() ) {
|
||||||
checkColumnDuplication(
|
checkColumnDuplication(
|
||||||
|
@ -374,7 +393,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<Selectable> getColumnIterator() {
|
public Iterator<Selectable> getColumnIterator() {
|
||||||
return Collections.<Selectable>emptyList().iterator();
|
return Collections.emptyIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -390,23 +409,78 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
return getCollectionType();
|
return getCollectionType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CollectionSemantics<?,?> cachedCollectionSemantics;
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public CollectionSemantics getCollectionSemantics() {
|
public CollectionSemantics getCollectionSemantics() {
|
||||||
|
if ( cachedCollectionSemantics == null ) {
|
||||||
|
cachedCollectionSemantics = resolveCollectionSemantics();
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedCollectionSemantics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CollectionSemantics<?, ?> resolveCollectionSemantics() {
|
||||||
|
final CollectionType collectionType;
|
||||||
if ( typeName == null ) {
|
if ( typeName == null ) {
|
||||||
return getDefaultCollectionSemantics();
|
collectionType = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final CollectionType collectionType = MappingHelper.customCollection(
|
collectionType = MappingHelper.customCollection(
|
||||||
typeName,
|
typeName,
|
||||||
typeParameters,
|
typeParameters,
|
||||||
role,
|
role,
|
||||||
referencedPropertyName,
|
referencedPropertyName,
|
||||||
getMetadata()
|
getMetadata()
|
||||||
);
|
);
|
||||||
return new CustomCollectionTypeSemantics( collectionType );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
public CollectionSemantics<?,?> getDefaultCollectionSemantics() {
|
||||||
throw new MappingException(
|
throw new MappingException(
|
||||||
"Unexpected org.hibernate.mapping.Collection impl ["
|
"Unexpected org.hibernate.mapping.Collection impl ["
|
||||||
+ this + "]; unknown CollectionSemantics"
|
+ this + "]; unknown CollectionSemantics"
|
||||||
|
@ -598,7 +672,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List getFilters() {
|
public List<FilterConfiguration> getFilters() {
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,7 +694,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List getManyToManyFilters() {
|
public List<FilterConfiguration> getManyToManyFilters() {
|
||||||
return manyToManyFilters;
|
return manyToManyFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,6 +751,7 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
||||||
this.typeParameters = parameterMap;
|
this.typeParameters = parameterMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public void setTypeParameters(java.util.Map parameterMap) {
|
public void setTypeParameters(java.util.Map parameterMap) {
|
||||||
if ( parameterMap instanceof Properties ) {
|
if ( parameterMap instanceof Properties ) {
|
||||||
this.typeParameters = (Properties) parameterMap;
|
this.typeParameters = (Properties) parameterMap;
|
||||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.internal.FilterConfiguration;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface Filterable {
|
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
|
* just the identifier column
|
||||||
*/
|
*/
|
||||||
public class IdentifierBag extends IdentifierCollection {
|
public class IdentifierBag extends IdentifierCollection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hbm.xml binding
|
||||||
|
*/
|
||||||
public IdentifierBag(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
public IdentifierBag(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* annotation binding
|
||||||
|
*/
|
||||||
|
public IdentifierBag(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
public CollectionType getDefaultCollectionType() {
|
public CollectionType getDefaultCollectionType() {
|
||||||
return new IdentifierBagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() );
|
return new IdentifierBagType( getMetadata().getTypeConfiguration(), getRole(), getReferencedPropertyName() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.mapping;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,6 +24,10 @@ public abstract class IdentifierCollection extends Collection {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IdentifierCollection(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
public KeyValue getIdentifier() {
|
public KeyValue getIdentifier() {
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,13 @@
|
||||||
package org.hibernate.mapping;
|
package org.hibernate.mapping;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
|
import org.hibernate.collection.spi.CollectionSemantics;
|
||||||
import org.hibernate.engine.spi.Mapping;
|
import org.hibernate.engine.spi.Mapping;
|
||||||
|
import org.hibernate.type.CollectionType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indexed collections include Lists, Maps, arrays and
|
* Indexed collections include Lists, Maps, arrays and
|
||||||
|
@ -27,6 +30,10 @@ public abstract class IndexedCollection extends Collection {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IndexedCollection(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
public Value getIndex() {
|
public Value getIndex() {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.mapping;
|
package org.hibernate.mapping;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||||
import org.hibernate.collection.internal.StandardListSemantics;
|
import org.hibernate.collection.internal.StandardListSemantics;
|
||||||
|
@ -22,14 +24,24 @@ public class List extends IndexedCollection {
|
||||||
|
|
||||||
private int baseIndex;
|
private int baseIndex;
|
||||||
|
|
||||||
public boolean isList() {
|
/**
|
||||||
return true;
|
* hbm.xml binding
|
||||||
}
|
*/
|
||||||
|
|
||||||
public List(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
public List(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* annotation binding
|
||||||
|
*/
|
||||||
|
public List(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isList() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionSemantics getDefaultCollectionSemantics() {
|
public CollectionSemantics getDefaultCollectionSemantics() {
|
||||||
return StandardListSemantics.INSTANCE;
|
return StandardListSemantics.INSTANCE;
|
||||||
|
|
|
@ -28,7 +28,11 @@ public class Map extends IndexedCollection {
|
||||||
public Map(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
public Map(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isMap() {
|
public boolean isMap() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@ public class PrimitiveArray extends Array {
|
||||||
super( buildingContext, owner );
|
super( buildingContext, owner );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PrimitiveArray(SemanticsResolver semanticsResolver, PersistentClass owner, MetadataBuildingContext buildingContext) {
|
||||||
|
super( semanticsResolver, owner, buildingContext );
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPrimitiveArray() {
|
public boolean isPrimitiveArray() {
|
||||||
return true;
|
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
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class Set extends Collection {
|
public class Set extends Collection {
|
||||||
|
/**
|
||||||
|
* Used by hbm.xml binding
|
||||||
|
*/
|
||||||
public Set(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
public Set(MetadataBuildingContext buildingContext, PersistentClass owner) {
|
||||||
super( buildingContext, 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 {
|
public void validate(Mapping mapping) throws MappingException {
|
||||||
super.validate( mapping );
|
super.validate( mapping );
|
||||||
//for backward compatibility, disable this:
|
//for backward compatibility, disable this:
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.cfg.Ejb3JoinColumn;
|
||||||
import org.hibernate.cfg.InheritanceState;
|
import org.hibernate.cfg.InheritanceState;
|
||||||
import org.hibernate.cfg.PropertyHolder;
|
import org.hibernate.cfg.PropertyHolder;
|
||||||
import org.hibernate.cfg.annotations.CollectionBinder;
|
import org.hibernate.cfg.annotations.CollectionBinder;
|
||||||
|
import org.hibernate.collection.internal.StandardBagSemantics;
|
||||||
import org.hibernate.mapping.Collection;
|
import org.hibernate.mapping.Collection;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Table;
|
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]";
|
String expectMessage = "Association [abc] for entity [CollectionBinderTest] references unmapped class [List]";
|
||||||
try {
|
try {
|
||||||
new CollectionBinder( false) {
|
new CollectionBinder( (t) -> StandardBagSemantics.INSTANCE, false, buildingContext ) {
|
||||||
|
|
||||||
{
|
{
|
||||||
final PropertyHolder propertyHolder = Mockito.mock(PropertyHolder.class);
|
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.
|
* 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>.
|
* 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.Entity;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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;
|
import java.util.List;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.collection.internal.PersistentList;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
@ -4,11 +4,10 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.List;
|
||||||
import java.util.Map;
|
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.FetchType;
|
import jakarta.persistence.FetchType;
|
||||||
|
@ -17,9 +16,9 @@ import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.OrderColumn;
|
import jakarta.persistence.OrderColumn;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.persistence.Transient;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.CollectionType;
|
import org.hibernate.annotations.CollectionType;
|
||||||
|
import org.hibernate.annotations.NaturalId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
@ -28,43 +27,41 @@ import org.hibernate.annotations.CollectionType;
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "UC_BSC_USER")
|
@Table(name = "UC_BSC_USER")
|
||||||
public class User {
|
public class User {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@NaturalId
|
||||||
private String userName;
|
private String userName;
|
||||||
private IMyList<Email> emailAddresses = new MyList<Email>();
|
@OneToMany( fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true )
|
||||||
private Map sessionData = new HashMap();
|
@CollectionType( type = "org.hibernate.orm.test.mapping.type.collection.custom.basic.MyListType" )
|
||||||
|
@JoinColumn( name = "userName" )
|
||||||
User() {
|
@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;
|
userName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Id
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUserName() {
|
public String getUserName() {
|
||||||
return userName;
|
return userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserName(String userName) {
|
public void setUserName(String userName) {
|
||||||
this.userName = 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() {
|
public List<Email> getEmailAddresses() {
|
||||||
// does not work :(
|
|
||||||
// public IMyList<Email> getEmailAddresses() {
|
|
||||||
return emailAddresses;
|
return emailAddresses;
|
||||||
}
|
}
|
||||||
public void setEmailAddresses(IMyList<Email> emailAddresses) {
|
public void setEmailAddresses(IMyList<Email> emailAddresses) {
|
||||||
this.emailAddresses = 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.
|
* 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>.
|
* 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
|
* @author Steve Ebersole
|
|
@ -4,14 +4,19 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest {
|
public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest {
|
||||||
|
@Override
|
||||||
|
protected String getBaseForMappings() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getMappings() {
|
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.
|
* 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>.
|
* 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.CriteriaBuilder;
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
@ -29,7 +29,7 @@ public abstract class UserCollectionTypeTest extends BaseNonConfigCoreFunctional
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBasicOperation() {
|
public void testBasicOperation() {
|
||||||
User u = new User("max");
|
User u = new User( 1, "max" );
|
||||||
inTransaction(
|
inTransaction(
|
||||||
s -> {
|
s -> {
|
||||||
u.getEmailAddresses().add( new Email("max@hibernate.org") );
|
u.getEmailAddresses().add( new Email("max@hibernate.org") );
|
||||||
|
@ -53,7 +53,7 @@ public abstract class UserCollectionTypeTest extends BaseNonConfigCoreFunctional
|
||||||
|
|
||||||
inTransaction(
|
inTransaction(
|
||||||
s -> {
|
s -> {
|
||||||
User u2 = s.get( User.class, u.getUserName() );
|
User u2 = s.get( User.class, u.getId() );
|
||||||
u2.getEmailAddresses().size();
|
u2.getEmailAddresses().size();
|
||||||
assertEquals( 2, MyListType.lastInstantiationRequest );
|
assertEquals( 2, MyListType.lastInstantiationRequest );
|
||||||
|
|
|
@ -13,13 +13,14 @@
|
||||||
This mapping is a basic example of how to write a UserCollectionType.
|
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"/>
|
<import class="Permission"/>
|
||||||
|
|
||||||
<class name="User" table="UC_BSC_USER">
|
<class name="User" table="UC_BSC_USER">
|
||||||
<id name="userName"/>
|
<id name="id"/>
|
||||||
<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.test.collection.custom.basic.MyListType">
|
<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"/>
|
<key column="userName"/>
|
||||||
<list-index column="displayOrder" base="1"/>
|
<list-index column="displayOrder" base="1"/>
|
||||||
<one-to-many class="Email"/>
|
<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.Entity;
|
||||||
import jakarta.persistence.GeneratedValue;
|
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
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* 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
|
* @author Steve Ebersole
|
|
@ -21,7 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* 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
|
* @author Steve Ebersole
|
||||||
|
@ -29,6 +29,6 @@ package org.hibernate.test.collection.custom.declaredtype;
|
||||||
public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest {
|
public class UserCollectionTypeHbmVariantTest extends UserCollectionTypeTest {
|
||||||
@Override
|
@Override
|
||||||
public String[] getMappings() {
|
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.
|
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"/>
|
<import class="Permission"/>
|
||||||
|
|
||||||
<class name="org.hibernate.test.collection.custom.declaredtype.UserCollectionTypeTest$User" table="UC_BSC_USER">
|
<class name="org.hibernate.orm.test.mapping.type.collection.custom.declaredtype.User" table="UC_BSC_USER">
|
||||||
<id name="userName"/>
|
<id name="id"/>
|
||||||
<list name="emailAddresses" fetch="join" cascade="all, delete-orphan" collection-type="org.hibernate.test.collection.custom.declaredtype.UserCollectionTypeTest$HeadListType">
|
<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"/>
|
<key column="userName"/>
|
||||||
<list-index column="displayOrder" base="1"/>
|
<list-index column="displayOrder" base="1"/>
|
||||||
<one-to-many class="Email"/>
|
<one-to-many class="Email"/>
|
|
@ -21,7 +21,7 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* 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;
|
import org.hibernate.annotations.CollectionType;
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* 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.AnnotationException;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
@ -54,10 +55,9 @@ public class UserWithUnimplementedCollectionTest extends BaseCoreFunctionalTestC
|
||||||
fail( "Expected exception" );
|
fail( "Expected exception" );
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
assertTrue( e instanceof AnnotationException );
|
assertThat( e ).isInstanceOf( AnnotationException.class );
|
||||||
assertEquals(
|
assertThat( e ).hasMessageStartingWith( "Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements:" );
|
||||||
"Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: org.hibernate.test.collection.custom.declaredtype.UserWithUnimplementedCollection.emailAddresses",
|
assertThat( e ).hasMessageEndingWith( ".emailAddresses" );
|
||||||
e.getMessage() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
* 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>.
|
* 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;
|
import java.util.List;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.ArrayList;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -16,6 +16,7 @@ import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.OrderColumn;
|
import jakarta.persistence.OrderColumn;
|
||||||
|
|
||||||
import org.hibernate.annotations.CollectionType;
|
import org.hibernate.annotations.CollectionType;
|
||||||
|
import org.hibernate.annotations.Parameter;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,11 +24,6 @@ import org.hibernate.annotations.CollectionType;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
//@TypeDef(
|
|
||||||
// name = "DefaultableList",
|
|
||||||
// typeClass = DefaultableListType.class,
|
|
||||||
// parameters = @Parameter(name = "default", value = "Hello" )
|
|
||||||
//)
|
|
||||||
@jakarta.persistence.Entity
|
@jakarta.persistence.Entity
|
||||||
public class Entity {
|
public class Entity {
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -50,7 +46,10 @@ public class Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ElementCollection( targetClass = String.class, fetch = FetchType.EAGER )
|
@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" )
|
@JoinColumn( name = "ENT_ID" )
|
||||||
@OrderColumn( name = "POS" )
|
@OrderColumn( name = "POS" )
|
||||||
@Column(name = "VAL")
|
@Column(name = "VAL")
|
|
@ -9,9 +9,9 @@
|
||||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
"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>
|
<param name="default">Hello</param>
|
||||||
</typedef>
|
</typedef>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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
|
* @author Steve Ebersole
|
|
@ -4,13 +4,13 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ParameterizedUserCollectionTypeHbmVariantTest extends ParameterizedUserCollectionTypeTest {
|
public class ParameterizedUserCollectionTypeHbmVariantTest extends ParameterizedUserCollectionTypeTest {
|
||||||
public String[] getMappings() {
|
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.
|
* 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>.
|
* 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.Hibernate;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
|
@ -4,7 +4,7 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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;
|
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