clean up CollectionBinder and friends

This commit is contained in:
Gavin King 2022-11-02 11:13:55 +01:00
parent 38b4e8e01b
commit 3cd90d7615
16 changed files with 707 additions and 654 deletions

View File

@ -26,6 +26,7 @@ import jakarta.persistence.MappedSuperclass;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.Internal;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.ColumnTransformer;
import org.hibernate.annotations.ColumnTransformers;
@ -47,8 +48,6 @@ import org.hibernate.usertype.internal.AbstractTimeZoneStorageCompositeUserType;
import org.jboss.logging.Logger;
/**
* No idea.
*
* @author Emmanuel Bernard
*/
public abstract class AbstractPropertyHolder implements PropertyHolder {

View File

@ -35,7 +35,6 @@ import java.util.Map;
import static org.hibernate.cfg.BinderHelper.findReferencedColumnOwner;
import static org.hibernate.cfg.BinderHelper.getRelativePath;
import static org.hibernate.cfg.BinderHelper.isEmptyOrNullAnnotationValue;
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
import static org.hibernate.internal.util.StringHelper.isQuoted;
import static org.hibernate.internal.util.StringHelper.qualify;

View File

@ -1982,12 +1982,10 @@ public final class AnnotationBinder {
Class<? extends CompositeUserType<?>> compositeUserTypeClass,
MetadataBuildingContext buildingContext,
Map<XClass, InheritanceState> inheritanceStatePerClass) {
/*
* inSecondPass can only be used to apply right away the second pass of a composite-element
* Because it's a value type, there is no bidirectional association, hence second pass
* ordering does not matter
*/
Component comp = createComponent(
// inSecondPass can only be used to apply right away the second pass of a composite-element
// Because it's a value type, there is no bidirectional association, hence second pass
// ordering does not matter
final Component component = createComponent(
propertyHolder,
inferredData,
isComponentEmbedded,
@ -1996,17 +1994,16 @@ public final class AnnotationBinder {
buildingContext
);
String subpath = getPath( propertyHolder, inferredData );
final String subpath = getPath( propertyHolder, inferredData );
LOG.tracev( "Binding component with path: {0}", subpath );
PropertyHolder subHolder = buildPropertyHolder(
comp,
final PropertyHolder subHolder = buildPropertyHolder(
component,
subpath,
inferredData,
propertyHolder,
buildingContext
);
// propertyHolder here is the owner of the component property. Tell it we are about to start the component...
propertyHolder.startingProperty( inferredData.getProperty() );
@ -2026,7 +2023,7 @@ public final class AnnotationBinder {
.getService( ManagedBeanRegistry.class )
.getBean( compositeUserTypeClass )
.getBeanInstance();
comp.setTypeName( compositeUserTypeClass.getName() );
component.setTypeName( compositeUserTypeClass.getName() );
returnedClassOrElement = buildingContext.getBootstrapContext().getReflectionManager().toXClass( compositeUserType.embeddable() );
}
@ -2124,7 +2121,7 @@ public final class AnnotationBinder {
if ( isGlobalGeneratorNameGlobal( buildingContext ) ) {
buildGenerators( property, buildingContext );
SecondPass secondPass = new IdGeneratorResolverSecondPass(
(SimpleValue) comp.getProperty( property.getName() ).getValue(),
(SimpleValue) component.getProperty( property.getName() ).getValue(),
property,
generatorType,
generator,
@ -2141,7 +2138,7 @@ public final class AnnotationBinder {
Map<String, IdentifierGeneratorDefinition> localGenerators =
new HashMap<>( buildGenerators( property, buildingContext ) );
makeIdGenerator(
(SimpleValue) comp.getProperty( property.getName() ).getValue(),
(SimpleValue) component.getProperty( property.getName() ).getValue(),
property,
generatorType,
generator,
@ -2153,11 +2150,11 @@ public final class AnnotationBinder {
}
if ( compositeUserType != null ) {
comp.sortProperties();
final List<String> sortedPropertyNames = new ArrayList<>( comp.getPropertySpan() );
final List<Type> sortedPropertyTypes = new ArrayList<>( comp.getPropertySpan() );
component.sortProperties();
final List<String> sortedPropertyNames = new ArrayList<>( component.getPropertySpan() );
final List<Type> sortedPropertyTypes = new ArrayList<>( component.getPropertySpan() );
final PropertyAccessStrategy strategy = new PropertyAccessStrategyCompositeUserTypeImpl( compositeUserType, sortedPropertyNames, sortedPropertyTypes );
for ( Property property : comp.getProperties() ) {
for ( Property property : component.getProperties() ) {
sortedPropertyNames.add( property.getName() );
sortedPropertyTypes.add(
PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess(
@ -2169,7 +2166,7 @@ public final class AnnotationBinder {
property.setPropertyAccessStrategy( strategy );
}
}
return comp;
return component;
}
public static Component createComponent(

View File

@ -107,6 +107,10 @@ public class BinderHelper {
boolean.class.getName()
);
public static boolean isPrimitive(String elementTypeName) {
return PRIMITIVE_NAMES.contains( elementTypeName );
}
/**
* Here we address a fundamental problem: the {@code @JoinColumn}
* annotation specifies the referenced column in the target table

View File

@ -17,7 +17,8 @@ import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.usertype.UserCollectionType;
/**
* Bind an Array
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentArrayHolder primitive arrays},
* whose mapping model type is {@link org.hibernate.mapping.Array}.
*
* @author Anthony Patricio
*/

View File

@ -11,12 +11,12 @@ import java.util.function.Supplier;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.SemanticsResolver;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.usertype.UserCollectionType;
/**
* Bind a bag.
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentBag bags},
* whose mapping model type is {@link org.hibernate.mapping.Bag}.
*
* @author Matthew Inger
*/

View File

@ -89,7 +89,6 @@ import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedDiscriminatorColumn;
import org.hibernate.cfg.AnnotatedJoinColumns;
@ -1307,23 +1306,12 @@ public class EntityBinder {
private void bindhandleFilters() {
for ( Filter filter : filters ) {
final String filterName = filter.name();
String condition = filter.condition();
if ( isEmptyAnnotationValue( condition ) ) {
final FilterDefinition definition = context.getMetadataCollector().getFilterDefinition( filterName );
if ( definition == null ) {
throw new AnnotationException( "Entity '" + name
+ "' has a '@Filter' for an undefined filter named '" + filterName + "'" );
}
condition = definition.getDefaultFilterCondition();
if ( isEmpty( condition ) ) {
throw new AnnotationException( "Entity '" + name +
"' has a '@Filter' with no 'condition' and no default condition was given by the '@FilterDef' named '"
+ filterName + "'" );
}
condition = getDefaultFilterCondition(filter.name());
}
persistentClass.addFilter(
filterName,
filter.name(),
condition,
filter.deduceAliasInjectionPoints(),
toAliasTableMap( filter.aliases() ),
@ -1332,6 +1320,21 @@ public class EntityBinder {
}
}
private String getDefaultFilterCondition(String filterName) {
final FilterDefinition definition = context.getMetadataCollector().getFilterDefinition(filterName);
if ( definition == null ) {
throw new AnnotationException( "Entity '" + name
+ "' has a '@Filter' for an undefined filter named '" + filterName + "'" );
}
final String condition = definition.getDefaultFilterCondition();
if ( isEmpty( condition ) ) {
throw new AnnotationException( "Entity '" + name +
"' has a '@Filter' with no 'condition' and no default condition was given by the '@FilterDef' named '"
+ filterName + "'" );
}
return condition;
}
private void bindSynchronize() {
if ( annotatedClass.isAnnotationPresent( Synchronize.class ) ) {
final JdbcEnvironment jdbcEnvironment = context.getMetadataCollector().getDatabase().getJdbcEnvironment();

View File

@ -34,6 +34,9 @@ import jakarta.persistence.Column;
import static org.hibernate.cfg.BinderHelper.makeIdGenerator;
/**
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentIdentifierBag id bags}
* whose mapping model type is {@link org.hibernate.mapping.IdentifierBag}.
*
* @author Emmanuel Bernard
*/
public class IdBagBinder extends BagBinder {
@ -54,7 +57,8 @@ public class IdBagBinder extends BagBinder {
final CollectionId collectionIdAnn = property.getAnnotation( CollectionId.class );
if ( collectionIdAnn == null ) {
throw new MappingException( "idbag mapping missing @CollectionId" );
//TODO shouldn't this be an assertion?
throw new MappingException( "idbag mapping missing '@CollectionId' annotation" );
}
final PropertyData propertyData = new WrappedInferredData(

View File

@ -9,6 +9,7 @@ package org.hibernate.cfg.annotations;
import java.util.Map;
import java.util.function.Supplier;
import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.annotations.OrderBy;
import org.hibernate.boot.spi.MetadataBuildingContext;
@ -31,14 +32,13 @@ import org.jboss.logging.Logger;
import static org.hibernate.internal.util.StringHelper.qualify;
/**
* Bind a list to the underlying Hibernate configuration
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentList lists},
* whose mapping model type is {@link org.hibernate.mapping.List}.
*
* @author Matthew Inger
* @author Emmanuel Bernard
*/
public class ListBinder extends CollectionBinder {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, ListBinder.class.getName() );
public ListBinder(
Supplier<ManagedBean<? extends UserCollectionType>> customTypeBeanResolver,
MetadataBuildingContext buildingContext) {
@ -53,7 +53,7 @@ public class ListBinder extends CollectionBinder {
@Override
public void setSqlOrderBy(OrderBy orderByAnn) {
if ( orderByAnn != null ) {
LOG.orderByAnnotationIndexedCollection();
throw new AnnotationException( "A collection of type 'List' is annotated '@OrderBy'" );
}
}

View File

@ -28,7 +28,6 @@ import org.hibernate.cfg.CollectionPropertyHolder;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.PropertyData;
import org.hibernate.cfg.PropertyPreloadedData;
import org.hibernate.cfg.SecondPass;
import org.hibernate.engine.jdbc.Size;
@ -59,14 +58,15 @@ import jakarta.persistence.MapKeyColumn;
import jakarta.persistence.MapKeyJoinColumn;
import jakarta.persistence.MapKeyJoinColumns;
import static org.hibernate.cfg.BinderHelper.PRIMITIVE_NAMES;
import static org.hibernate.cfg.BinderHelper.findPropertyByName;
import static org.hibernate.cfg.BinderHelper.isPrimitive;
import static org.hibernate.cfg.PropertyHolderBuilder.buildPropertyHolder;
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
import static org.hibernate.internal.util.StringHelper.qualify;
/**
* Implementation to bind a Map
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentMap maps},
* whose mapping model type is {@link org.hibernate.mapping.Map}.
*
* @author Emmanuel Bernard
*/
@ -157,69 +157,79 @@ public class MapBinder extends CollectionBinder {
boolean isEmbedded,
AnnotatedColumns mapKeyColumns,
AnnotatedJoinColumns mapKeyManyToManyColumns) {
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
if ( mapKeyPropertyName != null ) {
//this is an EJB3 @MapKey
handleExplicitMapKey( elementType, persistentClasses, mapKeyPropertyName );
handleMapKeyProperty( elementType, persistentClasses, mapKeyPropertyName, map );
}
else {
//this is a true Map mapping
final String mapKeyType = getKeyType( property );
final PersistentClass collectionEntity = persistentClasses.get( mapKeyType );
final boolean isIndexOfEntities = collectionEntity != null;
final ManyToOne element;
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
if ( isIndexOfEntities ) {
element = handleCollectionKeyedByEntities( buildingContext, mapKeyType, map );
}
else {
element = null;
final XClass keyClass;
final AnnotatedClassType classType;
if ( PRIMITIVE_NAMES.contains( mapKeyType ) ) {
classType = AnnotatedClassType.NONE;
keyClass = null;
}
else {
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
keyClass = bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
// force in case of attribute override naming the key
classType = isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property )
? AnnotatedClassType.EMBEDDABLE
: buildingContext.getMetadataCollector().getClassType( keyClass );
}
handleMapKey( persistentClasses, property, isEmbedded, mapKeyColumns, mapKeyManyToManyColumns, map );
}
}
handleIndex(
property,
mapKeyColumns,
mapKeyType,
map,
keyClass,
classType,
buildCollectionPropertyHolder( property, map, keyClass ),
getAccessType( map )
);
}
//FIXME pass the Index Entity JoinColumns
if ( !collection.isOneToMany() ) {
//index column should not be null
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getJoinColumns() ) {
column.forceNotNull();
}
private void handleMapKey(
Map<String, PersistentClass> persistentClasses,
XProperty property,
boolean isEmbedded,
AnnotatedColumns mapKeyColumns,
AnnotatedJoinColumns mapKeyManyToManyColumns,
org.hibernate.mapping.Map map) {
final String mapKeyType = getKeyType( property );
final PersistentClass collectionEntity = persistentClasses.get( mapKeyType );
final boolean isKeyedByEntities = collectionEntity != null;
if ( isKeyedByEntities ) {
final ManyToOne element = handleCollectionKeyedByEntities( buildingContext, mapKeyType, map );
handleForeignKey( property, element );
// a map key column has no unique constraint, so pass 'unique=false' here
bindManyToManyInverseForeignKey( collectionEntity, mapKeyManyToManyColumns, element, false );
}
else {
final XClass keyClass = mapKeyClass( mapKeyType );
handleMapKey(
property,
mapKeyColumns,
mapKeyType,
map,
keyClass,
annotatedMapKeyType( property, isEmbedded, mapKeyType, keyClass ),
buildCollectionPropertyHolder( property, map, keyClass ),
accessType( property, map.getOwner() )
);
}
//FIXME pass the Index Entity JoinColumns
if ( !collection.isOneToMany() ) {
//index column should not be null
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getJoinColumns() ) {
column.forceNotNull();
}
}
}
if ( element != null ) {
handleForeignKey( property, element );
}
private AnnotatedClassType annotatedMapKeyType(
XProperty property,
boolean isEmbedded,
String mapKeyType,
XClass keyClass) {
if ( isPrimitive( mapKeyType ) ) {
return AnnotatedClassType.NONE;
}
else {
// force in case of attribute override naming the key
return isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property )
? AnnotatedClassType.EMBEDDABLE
: buildingContext.getMetadataCollector().getClassType( keyClass );
}
}
if ( isIndexOfEntities ) {
bindManyToManyInverseForeignKey(
collectionEntity,
mapKeyManyToManyColumns,
element,
false //a map key column has no unique constraint
);
}
private XClass mapKeyClass(String mapKeyType) {
if ( isPrimitive( mapKeyType ) ) {
return null;
}
else {
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
return bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
}
}
@ -232,10 +242,11 @@ public class MapBinder extends CollectionBinder {
return void.class.equals( target ) ? property.getMapKey().getName() : target.getName();
}
private void handleExplicitMapKey(
private void handleMapKeyProperty(
XClass elementType,
Map<String, PersistentClass> persistentClasses,
String mapKeyPropertyName) {
String mapKeyPropertyName,
org.hibernate.mapping.Map map) {
final PersistentClass associatedClass = persistentClasses.get( elementType.getName() );
if ( associatedClass == null ) {
throw new AnnotationException( "Association '" + safeCollectionRole()
@ -246,15 +257,14 @@ public class MapBinder extends CollectionBinder {
throw new AnnotationException( "Map key property '" + mapKeyPropertyName
+ "' not found in target entity '" + associatedClass.getEntityName() + "'" );
}
final org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
// HHH-11005 - if InheritanceType.JOINED then need to find class defining the column
final InheritanceState inheritanceState = inheritanceStatePerClass.get(elementType);
final InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType );
final PersistentClass targetEntity = InheritanceType.JOINED == inheritanceState.getType()
? mapProperty.getPersistentClass()
: associatedClass;
final Value indexValue = createFormulatedValue( mapProperty.getValue(), map, associatedClass, targetEntity );
map.setIndex( indexValue );
map.setMapKeyPropertyName(mapKeyPropertyName);
map.setMapKeyPropertyName( mapKeyPropertyName );
}
private CollectionPropertyHolder buildCollectionPropertyHolder(
@ -298,8 +308,7 @@ public class MapBinder extends CollectionBinder {
MetadataBuildingContext context,
String mapKeyType,
org.hibernate.mapping.Map map) {
final ManyToOne element;
element = new ManyToOne( context, map.getCollectionTable() );
final ManyToOne element = new ManyToOne( context, map.getCollectionTable() );
map.setIndex( element );
element.setReferencedEntityName( mapKeyType );
//element.setFetchMode( fetchMode );
@ -311,29 +320,7 @@ public class MapBinder extends CollectionBinder {
return element;
}
private static AccessType getAccessType(org.hibernate.mapping.Map map) {
final PersistentClass owner = map.getOwner();
final AccessType accessType;
// FIXME support @Access for collection of elements
// String accessType = access != null ? access.value() : null;
if ( owner.getIdentifierProperty() != null ) {
accessType = owner.getIdentifierProperty().getPropertyAccessorName().equals( "property" )
? AccessType.PROPERTY
: AccessType.FIELD;
}
else if ( owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0 ) {
Property prop = owner.getIdentifierMapper().getProperties().get(0);
accessType = prop.getPropertyAccessorName().equals( "property" )
? AccessType.PROPERTY
: AccessType.FIELD;
}
else {
throw new AssertionFailure( "Unable to guess collection property accessor name" );
}
return accessType;
}
private void handleIndex(
private void handleMapKey(
XProperty property,
AnnotatedColumns mapKeyColumns,
String mapKeyType,
@ -344,55 +331,74 @@ public class MapBinder extends CollectionBinder {
AccessType accessType) {
final Class<? extends CompositeUserType<?>> compositeUserType =
resolveCompositeUserType( property, keyClass, buildingContext );
if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) {
final EntityBinder entityBinder = new EntityBinder();
final PropertyData inferredData = isHibernateExtensionMapping()
? new PropertyPreloadedData( AccessType.PROPERTY, "index", keyClass)
// "key" is the JPA 2 prefix for map keys
: new PropertyPreloadedData( AccessType.PROPERTY, "key", keyClass);
//TODO be smart with isNullable
final Component component = AnnotationBinder.fillComponent(
holder,
inferredData,
accessType,
true,
entityBinder,
false,
false,
true,
null,
compositeUserType,
buildingContext,
inheritanceStatePerClass
);
map.setIndex( component );
handleCompositeMapKey( map, keyClass, holder, accessType, compositeUserType );
}
else {
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
elementBinder.setReturnedClassName( mapKeyType );
final AnnotatedColumns keyColumns = createElementColumnsIfNecessary(
collection,
mapKeyColumns,
Collection.DEFAULT_KEY_COLUMN_NAME,
Size.DEFAULT_LENGTH, //TODO: is this really necessary??!!
buildingContext
);
elementBinder.setColumns( keyColumns );
//do not call setType as it extracts the type from @Type
//the algorithm generally does not apply for map key anyway
elementBinder.setType(
property,
keyClass,
collection.getOwnerEntityName(),
holder.mapKeyAttributeConverterDescriptor( property, keyClass )
);
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );
map.setIndex( elementBinder.make() );
handleMapKey( property, mapKeyColumns, mapKeyType, map, keyClass, holder, accessType );
}
}
private void handleMapKey(
XProperty property,
AnnotatedColumns mapKeyColumns,
String mapKeyType,
org.hibernate.mapping.Map map, XClass keyClass,
CollectionPropertyHolder holder,
AccessType accessType) {
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
elementBinder.setReturnedClassName(mapKeyType);
final AnnotatedColumns keyColumns = createElementColumnsIfNecessary(
collection,
mapKeyColumns,
Collection.DEFAULT_KEY_COLUMN_NAME,
Size.DEFAULT_LENGTH, //TODO: is this really necessary??!!
buildingContext
);
elementBinder.setColumns( keyColumns );
//do not call setType as it extracts the type from @Type
//the algorithm generally does not apply for map key anyway
elementBinder.setType(
property,
keyClass,
collection.getOwnerEntityName(),
holder.mapKeyAttributeConverterDescriptor( property, keyClass )
);
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );
map.setIndex( elementBinder.make() );
}
private void handleCompositeMapKey(
org.hibernate.mapping.Map map,
XClass keyClass,
CollectionPropertyHolder holder,
AccessType accessType,
Class<? extends CompositeUserType<?>> compositeUserType) {
map.setIndex( AnnotationBinder.fillComponent(
holder,
propertyPreloadedData( keyClass ),
accessType,
//TODO be smart with isNullable
true,
new EntityBinder(),
false,
false,
true,
null,
compositeUserType,
buildingContext,
inheritanceStatePerClass
) );
}
private PropertyPreloadedData propertyPreloadedData(XClass keyClass) {
return isHibernateExtensionMapping()
? new PropertyPreloadedData(AccessType.PROPERTY, "index", keyClass)
// "key" is the JPA 2 prefix for map keys
: new PropertyPreloadedData(AccessType.PROPERTY, "key", keyClass);
}
private static Class<? extends CompositeUserType<?>> resolveCompositeUserType(
XProperty property,
XClass returnedClass,
@ -416,23 +422,22 @@ public class MapBinder extends CollectionBinder {
private jakarta.persistence.ForeignKey getMapKeyForeignKey(XProperty property) {
final MapKeyJoinColumns mapKeyJoinColumns = property.getAnnotation( MapKeyJoinColumns.class );
final MapKeyJoinColumn mapKeyJoinColumn = property.getAnnotation( MapKeyJoinColumn.class );
if ( mapKeyJoinColumns != null ) {
return mapKeyJoinColumns.foreignKey();
}
else {
final MapKeyJoinColumn mapKeyJoinColumn = property.getAnnotation( MapKeyJoinColumn.class );
if ( mapKeyJoinColumn != null ) {
return mapKeyJoinColumn.foreignKey();
}
else if ( mapKeyJoinColumn != null ) {
return mapKeyJoinColumn.foreignKey();
}
else {
return null;
}
return null;
}
private boolean mappingDefinedAttributeOverrideOnMapKey(XProperty property) {
if ( property.isAnnotationPresent( AttributeOverride.class ) ) {
return namedMapKey( property.getAnnotation( AttributeOverride.class ) );
}
if ( property.isAnnotationPresent( AttributeOverrides.class ) ) {
final AttributeOverrides annotations = property.getAnnotation( AttributeOverrides.class );
for ( AttributeOverride attributeOverride : annotations.value() ) {
@ -441,7 +446,6 @@ public class MapBinder extends CollectionBinder {
}
}
}
return false;
}
@ -454,94 +458,94 @@ public class MapBinder extends CollectionBinder {
Collection collection,
PersistentClass associatedClass,
PersistentClass targetPropertyPersistentClass) {
final Table mapKeyTable;
// HHH-11005 - only if we are OneToMany and location of map key property is at a different level, need to add a select
if ( !associatedClass.equals( targetPropertyPersistentClass ) ) {
mapKeyTable = targetPropertyPersistentClass.getTable();
}
else {
mapKeyTable = associatedClass.getTable();
}
if ( value instanceof Component ) {
Component component = (Component) value;
Component indexComponent = new Component( getBuildingContext(), collection );
indexComponent.setComponentClassName( component.getComponentClassName() );
for ( Property current : component.getProperties() ) {
Property newProperty = new Property();
newProperty.setCascade( current.getCascade() );
newProperty.setValueGenerationStrategy( current.getValueGenerationStrategy() );
newProperty.setInsertable( false );
newProperty.setUpdateable( false );
newProperty.setMetaAttributes( current.getMetaAttributes() );
newProperty.setName( current.getName() );
newProperty.setNaturalIdentifier( false );
//newProperty.setOptimisticLocked( false );
newProperty.setOptional( false );
newProperty.setPersistentClass( current.getPersistentClass() );
newProperty.setPropertyAccessorName( current.getPropertyAccessorName() );
newProperty.setSelectable( current.isSelectable() );
newProperty.setValue(
createFormulatedValue( current.getValue(), collection, associatedClass, associatedClass )
);
indexComponent.addProperty( newProperty );
}
return indexComponent;
}
else if ( value instanceof BasicValue ) {
final BasicValue sourceValue = (BasicValue) value;
final DependantBasicValue dependantBasicValue = new DependantBasicValue(
getBuildingContext(),
mapKeyTable,
sourceValue,
false,
false
);
final Selectable sourceValueColumn = sourceValue.getColumn();
if ( sourceValueColumn instanceof Column ) {
dependantBasicValue.addColumn( ( (Column) sourceValueColumn ).clone() );
}
else if ( sourceValueColumn instanceof Formula ) {
dependantBasicValue.addFormula( new Formula( ( (Formula) sourceValueColumn ).getFormula() ) );
}
else {
throw new AssertionFailure( "Unknown element column type : " + sourceValueColumn.getClass() );
}
return dependantBasicValue;
}
else if ( value instanceof SimpleValue ) {
SimpleValue sourceValue = (SimpleValue) value;
SimpleValue targetValue;
if ( value instanceof ManyToOne ) {
final ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
final ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable );
targetManyToOne.setFetchMode( FetchMode.DEFAULT );
targetManyToOne.setLazy( true );
//targetValue.setIgnoreNotFound( ); does not make sense for a map key
targetManyToOne.setReferencedEntityName( sourceManyToOne.getReferencedEntityName() );
targetValue = targetManyToOne;
}
else {
targetValue = new BasicValue( getBuildingContext(), mapKeyTable );
targetValue.copyTypeFrom( sourceValue );
}
for ( Selectable current : sourceValue.getSelectables() ) {
if ( current instanceof Column ) {
targetValue.addColumn( ( (Column) current ).clone() );
}
else if ( current instanceof Formula ) {
targetValue.addFormula( new Formula( ( (Formula) current ).getFormula() ) );
}
else {
throw new AssertionFailure( "Unknown element in column iterator: " + current.getClass() );
}
}
return targetValue;
return createIndexComponent( collection, associatedClass, (Component) value );
}
else {
throw new AssertionFailure( "Unknown type encountered for map key: " + value.getClass() );
// HHH-11005 - only if we are @OneToMany and location of map key property is
// at a different level, need to add a select
final Table mapKeyTable = !associatedClass.equals( targetPropertyPersistentClass )
? targetPropertyPersistentClass.getTable()
: associatedClass.getTable();
if ( value instanceof BasicValue ) {
return createDependantBasicValue( mapKeyTable, (BasicValue) value );
}
else if ( value instanceof SimpleValue ) {
return createTargetValue( mapKeyTable, (SimpleValue) value );
}
else {
throw new AssertionFailure( "Unknown type encountered for map key: " + value.getClass() );
}
}
}
private SimpleValue createTargetValue(Table mapKeyTable, SimpleValue sourceValue) {
final SimpleValue targetValue;
if ( sourceValue instanceof ManyToOne ) {
final ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
final ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable);
targetManyToOne.setFetchMode( FetchMode.DEFAULT );
targetManyToOne.setLazy( true );
//targetValue.setIgnoreNotFound( ); does not make sense for a map key
targetManyToOne.setReferencedEntityName( sourceManyToOne.getReferencedEntityName() );
targetValue = targetManyToOne;
}
else {
targetValue = new BasicValue( getBuildingContext(), mapKeyTable);
targetValue.copyTypeFrom( sourceValue );
}
for ( Selectable selectable : sourceValue.getSelectables() ) {
addSelectable( targetValue, selectable );
}
return targetValue;
}
private DependantBasicValue createDependantBasicValue(Table mapKeyTable, BasicValue sourceValue) {
final DependantBasicValue dependantBasicValue = new DependantBasicValue(
getBuildingContext(),
mapKeyTable,
sourceValue,
false,
false
);
addSelectable( dependantBasicValue, sourceValue.getColumn() );
return dependantBasicValue;
}
private static void addSelectable(SimpleValue targetValue, Selectable selectable) {
if ( selectable instanceof Column ) {
targetValue.addColumn( ( (Column) selectable).clone() );
}
else if ( selectable instanceof Formula ) {
targetValue.addFormula( new Formula( ( (Formula) selectable).getFormula() ) );
}
else {
throw new AssertionFailure( "Unknown element in column iterator: " + selectable.getClass() );
}
}
private Component createIndexComponent(Collection collection, PersistentClass associatedClass, Component component) {
final Component indexComponent = new Component( getBuildingContext(), collection);
indexComponent.setComponentClassName( component.getComponentClassName() );
for ( Property property : component.getProperties() ) {
final Property newProperty = new Property();
newProperty.setCascade( property.getCascade() );
newProperty.setValueGenerationStrategy( property.getValueGenerationStrategy() );
newProperty.setInsertable( false );
newProperty.setUpdateable( false );
newProperty.setMetaAttributes( property.getMetaAttributes() );
newProperty.setName( property.getName() );
newProperty.setNaturalIdentifier( false );
//newProperty.setOptimisticLocked( false );
newProperty.setOptional( false );
newProperty.setPersistentClass( property.getPersistentClass() );
newProperty.setPropertyAccessorName( property.getPropertyAccessorName() );
newProperty.setSelectable( property.isSelectable() );
newProperty.setValue(
createFormulatedValue( property.getValue(), collection, associatedClass, associatedClass)
);
indexComponent.addProperty( newProperty );
}
return indexComponent;
}
}

View File

@ -16,6 +16,9 @@ import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.usertype.UserCollectionType;
/**
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentArrayHolder primitive arrays},
* whose mapping model type is {@link org.hibernate.mapping.PrimitiveArray}.
*
* @author Emmanuel Bernard
*/
public class PrimitiveArrayBinder extends ArrayBinder {

View File

@ -16,7 +16,8 @@ import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.usertype.UserCollectionType;
/**
* Bind a set.
* A {@link CollectionBinder} for {@link org.hibernate.collection.spi.PersistentSet sets},
* whose mapping model type is {@link org.hibernate.mapping.Set}.
*
* @author Matthew Inger
*/

View File

@ -40,7 +40,7 @@ public class PersistentArrayHolder<E> extends AbstractPersistentCollection<E> {
protected Object array;
//just to help out during the load (ugly, i know)
private transient Class elementClass;
private transient Class<?> elementClass;
/**
* Constructs a PersistentCollection instance for holding an array.

View File

@ -839,13 +839,7 @@ public final class StringHelper {
final boolean isFirstExpressionNonEmpty = StringHelper.isNotEmpty( firstExpression );
final boolean isSecondExpressionNonEmpty = StringHelper.isNotEmpty( secondExpression );
if ( isFirstExpressionNonEmpty && isSecondExpressionNonEmpty ) {
final StringBuilder buffer = new StringBuilder();
buffer.append( "( " )
.append( firstExpression )
.append( " ) and ( ")
.append( secondExpression )
.append( " )" );
return buffer.toString();
return "( " + firstExpression + " ) and ( " + secondExpression + " )";
}
else if ( isFirstExpressionNonEmpty ) {
return firstExpression;

View File

@ -473,18 +473,12 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
return converterResolution;
}
final JdbcType jdbcType;
if ( explicitJdbcTypeAccess != null ) {
jdbcType = explicitJdbcTypeAccess.apply( typeConfiguration );
}
else {
jdbcType = null;
}
final JdbcType jdbcType = explicitJdbcTypeAccess != null
? explicitJdbcTypeAccess.apply( typeConfiguration )
: null;
if ( jtd == null ) {
if ( jdbcType != null ) {
jtd = jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, typeConfiguration );
}
if ( jtd == null && jdbcType != null ) {
jtd = jdbcType.getJdbcRecommendedJavaTypeMapping( null, null, typeConfiguration );
}
if ( jtd == null ) {