introduce AnnotatedColumns

This commit is contained in:
Gavin King 2022-10-30 16:49:46 +01:00
parent 653bf987bd
commit ec336f3a23
22 changed files with 539 additions and 425 deletions

View File

@ -3275,9 +3275,9 @@ public class ModelBinder {
&& !collectionBinding.isInverse()
&& !collectionBinding.getKey().isNullable() ) {
// for non-inverse one-to-many, with a not-null fk, add a backref!
String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName();
PersistentClass referenced = getReferencedEntityBinding( entityName );
Backref prop = new Backref();
final String entityName = ( (OneToMany) collectionBinding.getElement() ).getReferencedEntityName();
final PersistentClass referenced = getReferencedEntityBinding( entityName );
final Backref prop = new Backref();
prop.setName( '_' + collectionBinding.getOwnerEntityName() + "." + pluralAttributeSource.getName() + "Backref" );
prop.setUpdateable( false );
prop.setSelectable( false );
@ -3298,13 +3298,13 @@ public class ModelBinder {
protected void bindCollectionKey() {
final PluralAttributeKeySource keySource = getPluralAttributeSource().getKeySource();
final String propRef = keySource.getReferencedPropertyName();
getCollectionBinding().setReferencedPropertyName( propRef );
final String referencedPropertyName = keySource.getReferencedPropertyName();
getCollectionBinding().setReferencedPropertyName( referencedPropertyName );
final PersistentClass owner = getCollectionBinding().getOwner();
final KeyValue keyVal = propRef == null
final KeyValue keyVal = referencedPropertyName == null
? owner.getIdentifier()
: (KeyValue) owner.getRecursiveProperty( propRef ).getValue();
: (KeyValue) owner.getRecursiveProperty( referencedPropertyName ).getValue();
final DependantValue key = new DependantValue(
mappingDocument,
getCollectionBinding().getCollectionTable(),

View File

@ -42,6 +42,7 @@ import static org.hibernate.cfg.BinderHelper.getPath;
import static org.hibernate.cfg.BinderHelper.getRelativePath;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.qualify;
/**
* A mapping to a column, logically representing a
@ -67,8 +68,9 @@ public class AnnotatedColumn {
private Column mappingColumn;
private boolean insertable = true;
private boolean updatable = true;
private String explicitTableName;
private String explicitTableName; // the JPA @Column annotation lets you specify a table name
protected Map<String, Join> joins;
@Deprecated // use AnnotatedColumns.propertyHolder
protected PropertyHolder propertyHolder;
private boolean isImplicit;
public String sqlType;
@ -81,7 +83,6 @@ public class AnnotatedColumn {
private boolean nullable = true;
private String formulaString;
private Formula formula;
private Table table;
private String readExpression;
private String writeExpression;
@ -91,8 +92,10 @@ public class AnnotatedColumn {
private String comment;
private String checkConstraint;
public void setTable(Table table) {
this.table = table;
private AnnotatedColumns parent;
void setParent(AnnotatedColumns parent) {
this.parent = parent;
}
public String getLogicalColumnName() {
@ -123,23 +126,16 @@ public class AnnotatedColumn {
return isNotEmpty( formulaString );
}
@SuppressWarnings("UnusedDeclaration")
public String getFormulaString() {
return formulaString;
}
@SuppressWarnings("UnusedDeclaration")
public String getExplicitTableName() {
return explicitTableName;
}
public void setExplicitTableName(String explicitTableName) {
if ( "``".equals( explicitTableName ) ) {
this.explicitTableName = "";
}
else {
this.explicitTableName = explicitTableName;
}
this.explicitTableName = "``".equals( explicitTableName ) ? "" : explicitTableName;
}
public void setFormula(String formula) {
@ -371,8 +367,8 @@ public class AnnotatedColumn {
public boolean isCollectionElement() {
// if the propertyHolder is a collection, assume the
// @Column refers to the element column
return !propertyHolder.isComponent()
&& !propertyHolder.isEntity();
return !getPropertyHolder().isComponent()
&& !getPropertyHolder().isEntity();
}
@Override
@ -426,9 +422,10 @@ public class AnnotatedColumn {
}
public PropertyHolder getPropertyHolder() {
return propertyHolder;
return propertyHolder; //TODO: change this to delegate to the parent
}
@Deprecated // use AnnotatedColumns.setPropertyHolder() instead
public void setPropertyHolder(PropertyHolder propertyHolder) {
this.propertyHolder = propertyHolder;
}
@ -437,12 +434,16 @@ public class AnnotatedColumn {
this.mappingColumn = mappingColumn;
}
//TODO: move this operation to AnnotatedColumns!!
public void linkWithValue(SimpleValue value) {
if ( formula != null ) {
value.addFormula( formula );
}
else {
table = value.getTable();
final Table table = value.getTable();
if ( parent != null ) {
parent.setTableInternal( table );
}
getMappingColumn().setValue( value );
value.addColumn( getMappingColumn(), insertable, updatable );
table.addColumn( getMappingColumn() );
@ -494,31 +495,25 @@ public class AnnotatedColumn {
* @throws AnnotationException missing secondary table
*/
public Table getTable() {
if ( table != null ) {
return table;
}
else if ( isSecondary() ) {
return getJoin().getTable();
}
else {
return propertyHolder.getTable();
}
return parent.getTable();
}
//TODO: move to AnnotatedColumns
public boolean isSecondary() {
if ( propertyHolder == null ) {
throw new AssertionFailure( "Should not call getTable() on column w/o persistent class defined" );
throw new AssertionFailure( "Should not call isSecondary() on column w/o persistent class defined" );
}
return isNotEmpty( explicitTableName )
&& !propertyHolder.getTable().getName().equals( explicitTableName );
&& !getPropertyHolder().getTable().getName().equals( explicitTableName );
}
//TODO: move to AnnotatedColumns
public Join getJoin() {
Join join = joins.get( explicitTableName );
if ( join == null ) {
// annotation binding seems to use logical and physical naming somewhat inconsistently...
final String physicalTableName = getBuildingContext().getMetadataCollector().getPhysicalTableName( explicitTableName );
final String physicalTableName = getBuildingContext().getMetadataCollector()
.getPhysicalTableName( explicitTableName );
if ( physicalTableName != null ) {
join = joins.get( physicalTableName );
}
@ -526,7 +521,7 @@ public class AnnotatedColumn {
if ( join == null ) {
throw new AnnotationException(
"Secondary table '" + explicitTableName + "' for property '" + propertyHolder.getClassName()
"Secondary table '" + explicitTableName + "' for property '" + getPropertyHolder().getClassName()
+ "' is not declared (use '@SecondaryTable' to declare the secondary table)"
);
}
@ -544,7 +539,7 @@ public class AnnotatedColumn {
mappingColumn.setNullable( false );
}
public static AnnotatedColumn[] buildFormulaFromAnnotation(
public static AnnotatedColumns buildFormulaFromAnnotation(
org.hibernate.annotations.Formula formulaAnn,
Comment commentAnn,
Nullability nullability,
@ -564,7 +559,7 @@ public class AnnotatedColumn {
);
}
public static AnnotatedColumn[] buildColumnFromNoAnnotation(
public static AnnotatedColumns buildColumnFromNoAnnotation(
Comment commentAnn,
Nullability nullability,
PropertyHolder propertyHolder,
@ -582,7 +577,7 @@ public class AnnotatedColumn {
);
}
public static AnnotatedColumn[] buildColumnFromAnnotation(
public static AnnotatedColumns buildColumnFromAnnotation(
jakarta.persistence.Column column,
Comment commentAnn,
Nullability nullability,
@ -602,7 +597,7 @@ public class AnnotatedColumn {
);
}
public static AnnotatedColumn[] buildColumnsFromAnnotations(
public static AnnotatedColumns buildColumnsFromAnnotations(
jakarta.persistence.Column[] columns,
Comment commentAnn,
Nullability nullability,
@ -623,7 +618,7 @@ public class AnnotatedColumn {
);
}
public static AnnotatedColumn[] buildColumnsFromAnnotations(
public static AnnotatedColumns buildColumnsFromAnnotations(
jakarta.persistence.Column[] columns,
Comment commentAnn,
Nullability nullability,
@ -645,7 +640,7 @@ public class AnnotatedColumn {
);
}
public static AnnotatedColumn[] buildColumnOrFormulaFromAnnotation(
public static AnnotatedColumns buildColumnOrFormulaFromAnnotation(
jakarta.persistence.Column column,
org.hibernate.annotations.Formula formulaAnn,
Comment commentAnn,
@ -667,7 +662,7 @@ public class AnnotatedColumn {
);
}
public static AnnotatedColumn[] buildColumnsOrFormulaFromAnnotation(
public static AnnotatedColumns buildColumnsOrFormulaFromAnnotation(
jakarta.persistence.Column[] columns,
org.hibernate.annotations.Formula formulaAnn,
Comment comment,
@ -685,10 +680,13 @@ public class AnnotatedColumn {
formulaColumn.setBuildingContext( context );
formulaColumn.setPropertyHolder( propertyHolder );
formulaColumn.bind();
return new AnnotatedColumn[] { formulaColumn };
final AnnotatedColumns result = new AnnotatedColumns();
result.setPropertyHolder( propertyHolder );
result.setColumns(new AnnotatedColumn[] {formulaColumn});
return result;
}
else {
jakarta.persistence.Column[] actualCols = overrideColumns( columns, propertyHolder, inferredData);
final jakarta.persistence.Column[] actualCols = overrideColumns( columns, propertyHolder, inferredData );
if ( actualCols == null ) {
return buildImplicitColumn(
inferredData,
@ -719,7 +717,7 @@ public class AnnotatedColumn {
PropertyHolder propertyHolder,
PropertyData inferredData ) {
final jakarta.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn(
StringHelper.qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
qualify( propertyHolder.getPath(), inferredData.getPropertyName() )
);
if ( overriddenCols != null ) {
//check for overridden first
@ -739,7 +737,7 @@ public class AnnotatedColumn {
}
}
private static AnnotatedColumn[] buildExplicitColumns(
private static AnnotatedColumns buildExplicitColumns(
Comment comment,
PropertyHolder propertyHolder,
PropertyData inferredData,
@ -775,7 +773,10 @@ public class AnnotatedColumn {
tableName
);
}
return columns;
final AnnotatedColumns result = new AnnotatedColumns();
result.setPropertyHolder(propertyHolder);
result.setColumns(columns);
return result;
}
private static AnnotatedColumn buildColumn(
@ -884,8 +885,8 @@ public class AnnotatedColumn {
if ( inferredData != null ) {
XProperty property = inferredData.getProperty();
if ( property != null ) {
if ( propertyHolder.isComponent() ) {
processColumnTransformerExpressions( propertyHolder.getOverriddenColumnTransformer( logicalColumnName ) );
if ( getPropertyHolder().isComponent() ) {
processColumnTransformerExpressions( getPropertyHolder().getOverriddenColumnTransformer( logicalColumnName ) );
}
processColumnTransformerExpressions( property.getAnnotation( ColumnTransformer.class ) );
ColumnTransformers annotations = property.getAnnotation( ColumnTransformers.class );
@ -909,7 +910,7 @@ public class AnnotatedColumn {
}
}
private static AnnotatedColumn[] buildImplicitColumn(
private static AnnotatedColumns buildImplicitColumn(
PropertyData inferredData,
String suffixForDefaultColumnName,
Map<String, Join> secondaryTables,
@ -917,8 +918,9 @@ public class AnnotatedColumn {
Comment comment,
Nullability nullability,
MetadataBuildingContext context) {
final AnnotatedColumn[] columns = new AnnotatedColumn[1];
columns[0] = bindImplicitColumn(
final AnnotatedColumns result = new AnnotatedColumns();
result.setPropertyHolder( propertyHolder );
final AnnotatedColumn column = bindImplicitColumn(
inferredData,
suffixForDefaultColumnName,
secondaryTables,
@ -927,7 +929,8 @@ public class AnnotatedColumn {
nullability,
context
);
return columns;
result.setColumns( new AnnotatedColumn[] { column } );
return result;
}
private static AnnotatedColumn bindImplicitColumn(
@ -968,9 +971,8 @@ public class AnnotatedColumn {
}
public static void checkPropertyConsistency(AnnotatedColumn[] columns, String propertyName) {
int nbrOfColumns = columns.length;
if ( nbrOfColumns > 1 ) {
for (int currentIndex = 1; currentIndex < nbrOfColumns; currentIndex++) {
if ( columns.length > 1 ) {
for (int currentIndex = 1; currentIndex < columns.length; currentIndex++) {
if ( !columns[currentIndex].isFormula() && !columns[currentIndex - 1].isFormula() ) {
if ( columns[currentIndex].isNullable() != columns[currentIndex - 1].isNullable() ) {
throw new AnnotationException(

View File

@ -0,0 +1,68 @@
package org.hibernate.cfg;
import org.hibernate.mapping.Table;
/**
* A list of columns that are mapped to a single Java property
* or field. This is a slightly uncomfortable abstraction here,
* because this concept is arguably missing from JPA (where
* there's no equivalent of the Hibernate-defined
* {@link org.hibernate.annotations.Columns} annotation) and
* so JPA lets each {@link jakarta.persistence.Column} specify
* its own {@link jakarta.persistence.Column#table table}.
* That leaves us having to enforce the requirement that every
* column mapped to a given property must belong to the same
* table.
*
* @author Gavin King
*/
public class AnnotatedColumns {
private AnnotatedColumn[] columns;
private Table table;
private PropertyHolder propertyHolder;
public void setColumns(AnnotatedColumn[] columns) {
this.columns = columns;
if ( columns != null ) {
for ( AnnotatedColumn column : columns ) {
column.setParent( this );
}
}
}
public AnnotatedColumn[] getColumns() {
return columns;
}
public PropertyHolder getPropertyHolder() {
return propertyHolder;
}
public void setPropertyHolder(PropertyHolder propertyHolder) {
this.propertyHolder = propertyHolder;
}
public Table getTable() {
if ( table != null ) {
return table;
}
else {
// all the columns have to be mapped to the same table
// even though at the annotation level it looks like
// they could each specify a different table
final AnnotatedColumn firstColumn = columns[0];
return firstColumn.isSecondary()
? firstColumn.getJoin().getTable()
: firstColumn.getPropertyHolder().getTable();
}
}
public void setTable(Table table) {
this.table = table;
}
@Deprecated
void setTableInternal(Table table) {
this.table = table;
}
}

View File

@ -549,6 +549,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
}
public void setParent(AnnotatedJoinColumns parent) {
super.setParent( parent );
this.parent = parent;
}
}

View File

@ -45,7 +45,7 @@ import static org.hibernate.internal.util.StringHelper.qualify;
*
* @author Gavin King
*/
public class AnnotatedJoinColumns {
public class AnnotatedJoinColumns extends AnnotatedColumns {
private AnnotatedJoinColumn[] columns;
private PropertyHolder propertyHolder;
@ -60,8 +60,6 @@ public class AnnotatedJoinColumns {
private boolean elementCollection;
private String manyToManyOwnerSideEntityName;
public AnnotatedJoinColumns() {}
public static AnnotatedJoinColumns buildJoinColumnsOrFormulas(
JoinColumnOrFormula[] joinColumnOrFormulas,
String mappedBy,
@ -204,7 +202,13 @@ public class AnnotatedJoinColumns {
return columns;
}
@Override
public void setColumns(AnnotatedColumn[] columns) {
throw new UnsupportedOperationException( "wrong sort of columns" );
}
public void setColumns(AnnotatedJoinColumn[] columns) {
super.setColumns( columns );
this.columns = columns;
if ( columns != null ) {
for ( AnnotatedJoinColumn column : columns ) {

View File

@ -1118,7 +1118,7 @@ public final class AnnotationBinder {
entityBinder,
context
).extractMetadata();
AnnotatedColumn[] columns = columnsBuilder.getColumns();
AnnotatedColumns columns = columnsBuilder.getColumns();
AnnotatedJoinColumns joinColumns = columnsBuilder.getJoinColumns();
final PropertyBinder propertyBinder = new PropertyBinder();
@ -1252,7 +1252,7 @@ public final class AnnotationBinder {
MetadataBuildingContext context,
Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty property,
AnnotatedColumn[] columns,
AnnotatedColumns columns,
PropertyBinder propertyBinder) {
if (isIdentifierMapper) {
throw new AnnotationException(
@ -1303,7 +1303,7 @@ public final class AnnotationBinder {
}
}
private static AnnotatedColumn[] bindBasic(
private static AnnotatedColumns bindBasic(
PropertyHolder propertyHolder,
Nullability nullability,
PropertyData inferredData,
@ -1315,14 +1315,14 @@ public final class AnnotationBinder {
Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty property,
ColumnsBuilder columnsBuilder,
AnnotatedColumn[] columns,
AnnotatedColumns columns,
XClass returnedClass,
PropertyBinder propertyBinder) {
// overrides from @MapsId or @IdClass if needed
final boolean isComposite;
final boolean isOverridden;
final AnnotatedColumn[] actualColumns;
final AnnotatedColumns actualColumns;
if ( propertyBinder.isId() || propertyHolder.isOrWithinEmbeddedId() || propertyHolder.isInIdClass() ) {
// the associated entity could be using an @IdClass making the overridden property a component
final PropertyData overridingProperty = getPropertyOverriddenByMapperOrMapsId(
@ -1450,7 +1450,7 @@ public final class AnnotationBinder {
Nullability nullability,
MetadataBuildingContext context,
XProperty property,
AnnotatedColumn[] columns,
AnnotatedColumns columns,
PropertyBinder propertyBinder,
boolean isOverridden) {
//provide the basic property mapping
@ -1469,12 +1469,12 @@ public final class AnnotationBinder {
//implicit type will check basic types and Serializable classes
if ( propertyBinder.isId() || !optional && nullability != Nullability.FORCED_NULL ) {
//force columns to not null
for ( AnnotatedColumn col : columns ) {
if ( propertyBinder.isId() && col.isFormula() ) {
for ( AnnotatedColumn column : columns.getColumns() ) {
if ( propertyBinder.isId() && column.isFormula() ) {
throw new CannotForceNonNullableException( "Identifier property '"
+ getPath( propertyHolder, inferrredData ) + "' cannot map to a '@Formula'" );
}
col.forceNotNull();
column.forceNotNull();
}
}
@ -1499,7 +1499,7 @@ public final class AnnotationBinder {
MetadataBuildingContext context,
Map<XClass, InheritanceState> inheritanceStatePerClass,
XProperty property,
AnnotatedColumn[] columns,
AnnotatedColumns columns,
XClass returnedClass,
PropertyBinder propertyBinder,
boolean isOverridden,
@ -1509,7 +1509,7 @@ public final class AnnotationBinder {
final AnnotatedJoinColumns actualColumns;
if ( isOverridden ) {
// careful: not always a @MapsId property, sometimes it's from an @IdClass
PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
propertyBinder.isId(), propertyHolder, property.getName(), context
);
referencedEntityName = mapsIdProperty.getClassOrElementName();
@ -1518,7 +1518,7 @@ public final class AnnotationBinder {
joinColumns.setBuildingContext( context );
joinColumns.setPropertyHolder( propertyHolder );
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns.getColumns() );
actualColumns = joinColumns;
}
else {
@ -1574,9 +1574,9 @@ public final class AnnotationBinder {
);
}
Cascade hibernateCascade = property.getAnnotation( Cascade.class );
OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
JoinTable assocTable = propertyHolder.getJoinTable(property);
final Cascade hibernateCascade = property.getAnnotation( Cascade.class );
final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
final JoinTable assocTable = propertyHolder.getJoinTable(property);
if ( assocTable != null ) {
Join join = propertyHolder.addJoin( assocTable, false );
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) {
@ -1600,7 +1600,7 @@ public final class AnnotationBinder {
private static void addIndexes(
boolean inSecondPass,
XProperty property,
AnnotatedColumn[] columns,
AnnotatedColumns columns,
AnnotatedJoinColumns joinColumns) {
//process indexes after everything: in second pass, many to one has to be done before indexes
final Index index = property.getAnnotation( Index.class );
@ -1613,7 +1613,7 @@ public final class AnnotationBinder {
}
else {
if ( columns != null ) {
for ( AnnotatedColumn column : columns ) {
for ( AnnotatedColumn column : columns.getColumns() ) {
column.addIndex( index, inSecondPass );
}
}
@ -1624,7 +1624,7 @@ public final class AnnotationBinder {
private static void addNaturalIds(
boolean inSecondPass,
XProperty property,
AnnotatedColumn[] columns,
AnnotatedColumns columns,
AnnotatedJoinColumns joinColumns) {
// Natural ID columns must reside in one single UniqueKey within the Table.
// For now, simply ensure consistent naming.
@ -1639,7 +1639,7 @@ public final class AnnotationBinder {
}
}
else {
for ( AnnotatedColumn column : columns) {
for ( AnnotatedColumn column : columns.getColumns() ) {
String keyName = "UK_" + Constraint.hashedName( column.getTable().getName() + "_NaturalID" );
column.addUniqueKey( keyName, inSecondPass );
}
@ -2254,8 +2254,8 @@ public final class AnnotationBinder {
binder.setAccessType( inferredData.getDefaultAccess() );
binder.setCascade( cascadeStrategy );
Property prop = binder.makeProperty();
//composite FK columns are in the same table so its OK
propertyHolder.addProperty( prop, columns.getColumns(), inferredData.getDeclaringClass() );
//composite FK columns are in the same table, so it's OK
propertyHolder.addProperty( prop, columns, inferredData.getDeclaringClass() );
}
public static HashMap<String, IdentifierGeneratorDefinition> buildGenerators(

View File

@ -1049,17 +1049,18 @@ public class BinderHelper {
EntityBinder entityBinder,
boolean optional,
MetadataBuildingContext context) {
final XProperty xProperty = inferredData.getProperty();
final AnnotatedJoinColumn[] columns = keyColumns.getColumns();
final XProperty property = inferredData.getProperty();
final Any value = new Any( context, columns[0].getTable(), true );
final Any value = new Any( context, keyColumns.getTable(), true );
value.setLazy( lazy );
value.setCascadeDeleteEnabled( cascadeOnDelete );
final BasicValueBinder discriminatorValueBinder =
new BasicValueBinder( BasicValueBinder.Kind.ANY_DISCRIMINATOR, context );
final AnnotatedColumn[] discriminatorColumns = buildColumnOrFormulaFromAnnotation(
// TODO: if there can be only one discriminator column,
// why are we making a whole array of them??
final AnnotatedColumns discriminatorColumns = buildColumnOrFormulaFromAnnotation(
discriminatorColumn,
discriminatorFormula,
null,
@ -1069,17 +1070,20 @@ public class BinderHelper {
entityBinder.getSecondaryTables(),
context
);
assert discriminatorColumns.length == 1;
discriminatorColumns[0].setTable( value.getTable() );
assert discriminatorColumns.getColumns().length == 1;
discriminatorColumns.setTable( value.getTable() );
discriminatorValueBinder.setColumns( discriminatorColumns );
discriminatorValueBinder.setReturnedClassName( inferredData.getTypeName() );
discriminatorValueBinder.setType( xProperty, xProperty.getType(), null, null );
discriminatorValueBinder.setType( property, property.getType(), null, null );
final BasicValue discriminatorDescriptor = discriminatorValueBinder.make();
value.setDiscriminator( discriminatorDescriptor );
discriminatorValueBinder.fillSimpleValue();
discriminatorColumns[0].linkWithValue( discriminatorDescriptor );
// TODO: this is nasty
final AnnotatedColumn firstDiscriminatorColumn = discriminatorColumns.getColumns()[0];
firstDiscriminatorColumn.linkWithValue( discriminatorDescriptor );
final JavaType<?> discriminatorJavaType = discriminatorDescriptor
.resolve()
@ -1095,26 +1099,23 @@ public class BinderHelper {
);
value.setDiscriminatorValueMappings( discriminatorValueMappings );
BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
final BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
final AnnotatedJoinColumn[] columns = keyColumns.getColumns();
assert columns.length == 1;
columns[0].setTable( value.getTable() );
keyValueBinder.setColumns(columns);
keyColumns.setTable( value.getTable() );
keyValueBinder.setColumns( keyColumns );
if ( !optional ) {
for ( AnnotatedJoinColumn column : columns) {
for ( AnnotatedJoinColumn column : columns ) {
column.setNullable( false );
}
}
keyValueBinder.setType( xProperty, xProperty.getType(), null, null );
keyValueBinder.setType( property, property.getType(), null, null );
final BasicValue keyDescriptor = keyValueBinder.make();
value.setKey( keyDescriptor );
keyValueBinder.fillSimpleValue();
AnnotatedColumn.checkPropertyConsistency(
columns,
propertyHolder.getEntityName() + "." + inferredData.getPropertyName()
);
final String path = qualify( propertyHolder.getEntityName(), inferredData.getPropertyName() );
AnnotatedColumn.checkPropertyConsistency( columns, path );
columns[0].linkWithValue( keyDescriptor );
return value;
}

View File

@ -12,6 +12,7 @@ import jakarta.persistence.Convert;
import jakarta.persistence.Converts;
import jakarta.persistence.JoinTable;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.XClass;
@ -181,12 +182,23 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
return persistentClass.getEntityName();
}
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) {
public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier
if ( columns != null && columns[0].isSecondary() ) {
//TODO move the getJoin() code here?
final Join join = columns[0].getJoin();
addPropertyToJoin( prop, declaringClass, join );
if ( columns != null ) {
final AnnotatedColumn firstColumn = columns.getColumns()[0];
if ( firstColumn.isSecondary() ) {
//TODO move the getJoin() code here?
for ( AnnotatedColumn column : columns.getColumns() ) {
if ( !column.isSecondary() || column.getJoin() != firstColumn.getJoin() ) {
//TODO: fix the error message
throw new AnnotationException("different columns mapped to different tables for a single property");
}
}
addPropertyToJoin( prop, declaringClass, firstColumn.getJoin() );
}
else {
addProperty( prop, declaringClass );
}
}
else {
addProperty( prop, declaringClass );

View File

@ -309,7 +309,7 @@ public class CollectionPropertyHolder extends AbstractPropertyHolder {
return collection.getOwner().getEntityName();
}
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) {
public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier
throw new AssertionFailure( "addProperty to a join table of a collection: does it make sense?" );
}

View File

@ -52,7 +52,7 @@ class ColumnsBuilder {
private final PropertyData inferredData;
private final EntityBinder entityBinder;
private final MetadataBuildingContext buildingContext;
private AnnotatedColumn[] columns;
private AnnotatedColumns columns;
private AnnotatedJoinColumns joinColumns;
public ColumnsBuilder(
@ -70,7 +70,7 @@ class ColumnsBuilder {
this.buildingContext = buildingContext;
}
public AnnotatedColumn[] getColumns() {
public AnnotatedColumns getColumns() {
return columns;
}
@ -158,8 +158,8 @@ class ColumnsBuilder {
if ( nullability == Nullability.FORCED_NOT_NULL ) {
//force columns to not null
for (AnnotatedColumn col : columns ) {
col.forceNotNull();
for ( AnnotatedColumn column : columns.getColumns() ) {
column.forceNotNull();
}
}
return this;
@ -291,13 +291,9 @@ class ColumnsBuilder {
}
}
AnnotatedColumn[] overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
final PropertyData overridingProperty = getPropertyOverriddenByMapperOrMapsId(
isId,
propertyHolder,
property.getName(),
buildingContext
);
AnnotatedColumns overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
final PropertyData overridingProperty =
getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), buildingContext );
return overridingProperty != null ? buildExplicitOrDefaultJoinColumn( overridingProperty ) : columns;
}
@ -305,10 +301,10 @@ class ColumnsBuilder {
* Useful to override a column either by {@code @MapsId} or by {@code @IdClass}
*/
//TODO: should we introduce an AnnotatedColumns type and return that here?
private AnnotatedColumn[] buildExplicitOrDefaultJoinColumn(PropertyData overridingProperty) {
private AnnotatedColumns buildExplicitOrDefaultJoinColumn(PropertyData overridingProperty) {
final AnnotatedJoinColumns columns = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty );
return columns == null
? buildDefaultJoinColumnsForToOne( overridingProperty.getProperty(), overridingProperty ).getColumns()
: columns.getColumns();
? buildDefaultJoinColumnsForToOne( overridingProperty.getProperty(), overridingProperty )
: columns;
}
}

View File

@ -251,12 +251,12 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
@Override
protected AttributeConversionInfo locateAttributeConversionInfo(String path) {
final String embeddedPath = StringHelper.qualifyConditionally( embeddedAttributeName, path );
AttributeConversionInfo fromParent = parent.locateAttributeConversionInfo( embeddedPath );
final AttributeConversionInfo fromParent = parent.locateAttributeConversionInfo( embeddedPath );
if ( fromParent != null ) {
return fromParent;
}
AttributeConversionInfo fromEmbedded = attributeConversionInfoMap.get( embeddedPath );
final AttributeConversionInfo fromEmbedded = attributeConversionInfoMap.get( embeddedPath );
if ( fromEmbedded != null ) {
return fromEmbedded;
}
@ -268,13 +268,13 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
return component.getComponentClassName();
}
public void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass) {
public void addProperty(Property property, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier
// Check table matches between the component and the columns
// if not, change the component table if no properties are set
// if a property is set already the core cannot support that
if (columns != null) {
Table table = columns[0].getTable();
if ( columns != null ) {
final Table table = columns.getTable();
if ( !table.equals( component.getTable() ) ) {
if ( component.getPropertySpan() == 0 ) {
component.setTable( table );
@ -288,12 +288,11 @@ public class ComponentPropertyHolder extends AbstractPropertyHolder {
}
}
}
addProperty( prop, declaringClass );
addProperty( property, declaringClass );
}
public Join addJoin(JoinTable joinTableAnn, boolean noDelayInPkColumnCreation) {
return parent.addJoin( joinTableAnn, noDelayInPkColumnCreation );
}
public String getClassName() {

View File

@ -59,16 +59,15 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
@Override
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
if ( columns != null ) {
for ( String column1 : columns ) {
addConstraintToColumn( column1 );
for ( String columnName : columns ) {
addConstraintToColumn( columnName );
}
}
if ( column != null ) {
this.table = column.getTable();
table = column.getTable();
final PropertyHolder propertyHolder = column.getPropertyHolder();
String entityName = ( propertyHolder.isComponent() ) ?
final String entityName = ( propertyHolder.isComponent() ) ?
propertyHolder.getPersistentClass().getEntityName() :
propertyHolder.getEntityName();
@ -77,8 +76,7 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
if ( property.getValue() instanceof Component ) {
final Component component = (Component) property.getValue();
List<Column> columns = new ArrayList<>();
final List<Column> columns = new ArrayList<>();
for ( Selectable selectable: component.getSelectables() ) {
if ( selectable instanceof Column ) {
columns.add( (Column) selectable );
@ -97,9 +95,7 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
private void addConstraintToColumn(final String columnName ) {
Column column = table.getColumn(
new Column(
buildingContext.getMetadataCollector().getPhysicalColumnName( table, columnName )
)
new Column( buildingContext.getMetadataCollector().getPhysicalColumnName( table, columnName ) )
);
if ( column == null ) {
throw new AnnotationException(
@ -117,13 +113,13 @@ public class IndexOrUniqueKeySecondPass implements SecondPass {
private void addConstraintToColumns(List<Column> columns) {
if ( unique ) {
UniqueKey uniqueKey = table.getOrCreateUniqueKey( indexName );
final UniqueKey uniqueKey = table.getOrCreateUniqueKey( indexName );
for ( Column column : columns ) {
uniqueKey.addColumn( column );
}
}
else {
Index index = table.getOrCreateIndex( indexName );
final Index index = table.getOrCreateIndex( indexName );
for ( Column column : columns ) {
index.addColumn( column );
}

View File

@ -35,7 +35,7 @@ public interface PropertyHolder {
void addProperty(Property prop, XClass declaringClass);
void addProperty(Property prop, AnnotatedColumn[] columns, XClass declaringClass);
void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass);
KeyValue getIdentifier();

View File

@ -142,7 +142,7 @@ public class ToOneBinder {
MetadataBuildingContext context) {
// All FK columns should be in the same table
final org.hibernate.mapping.ManyToOne value =
new org.hibernate.mapping.ManyToOne( context, joinColumns.getColumns()[0].getTable() );
new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() );
if ( unique ) {
// This is a @OneToOne mapped to a physical o.h.mapping.ManyToOne
value.markAsLogicalOneToOne();
@ -269,7 +269,7 @@ public class ToOneBinder {
propertyBinder.setInsertable( firstColumn.isInsertable() );
propertyBinder.setUpdatable( firstColumn.isUpdatable() );
}
propertyBinder.setColumns( columns.getColumns() );
propertyBinder.setColumns( columns );
propertyBinder.setAccessType( inferredData.getDefaultAccess() );
propertyBinder.setCascade( cascadeStrategy );
propertyBinder.setProperty( property );

View File

@ -55,6 +55,7 @@ import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass;
@ -153,7 +154,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
private TimeZoneStorageType timeZoneStorageType;
private Table table;
private AnnotatedColumn[] columns;
private AnnotatedColumns columns;
private BasicValue basicValue;
@ -274,7 +275,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
this.table = table;
}
public void setColumns(AnnotatedColumn[] columns) {
public void setColumns(AnnotatedColumns columns) {
this.columns = columns;
}
@ -1070,7 +1071,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
}
private void validate() {
AnnotatedColumn.checkPropertyConsistency( columns, propertyName );
AnnotatedColumn.checkPropertyConsistency( columns.getColumns(), propertyName );
}
public BasicValue make() {
@ -1083,7 +1084,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
LOG.debugf( "building BasicValue for %s", propertyName );
if ( table == null ) {
table = columns[0].getTable();
table = columns.getTable();
}
basicValue = new BasicValue( buildingContext, table );
@ -1125,18 +1126,19 @@ public class BasicValueBinder implements JdbcTypeIndicators {
public void linkWithValue() {
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
if ( !collector.isInSecondPass() && columns[0].isNameDeferred() && referencedEntityName != null ) {
final AnnotatedColumn firstColumn = columns.getColumns()[0];
if ( !collector.isInSecondPass() && firstColumn.isNameDeferred() && referencedEntityName != null ) {
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( buildingContext );
joinColumns.setPropertyHolder( columns[0].getPropertyHolder() );
joinColumns.setPropertyName( columns[0].getPropertyName() );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns );
joinColumns.setPropertyHolder( firstColumn.getPropertyHolder() );
joinColumns.setPropertyName( firstColumn.getPropertyName() );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns.getColumns() );
collector.addSecondPass(
new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, joinColumns, basicValue )
);
}
else {
for ( AnnotatedColumn column : columns ) {
for ( AnnotatedColumn column : columns.getColumns() ) {
column.linkWithValue( basicValue );
}
}

View File

@ -100,6 +100,7 @@ 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.AnnotatedJoinColumn;
import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.AnnotationBinder;
@ -173,6 +174,7 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.internal.util.collections.ArrayHelper.isEmpty;
/**
* Base class for binding different types of collections to Hibernate configuration objects.
@ -216,12 +218,12 @@ public abstract class CollectionBinder {
protected AnnotatedJoinColumns foreignJoinColumns;
private AnnotatedJoinColumns joinColumns;
private boolean isExplicitAssociationTable;
private AnnotatedColumn[] elementColumns;
private AnnotatedColumns elementColumns;
protected boolean isEmbedded;
protected XProperty property;
protected NotFoundAction notFoundAction;
private TableBinder tableBinder;
protected AnnotatedColumn[] mapKeyColumns;
protected AnnotatedColumns mapKeyColumns;
protected AnnotatedJoinColumns mapKeyManyToManyColumns;
protected Map<String, IdentifierGeneratorDefinition> localGenerators;
protected Map<XClass, InheritanceState> inheritanceStatePerClass;
@ -321,7 +323,7 @@ public abstract class CollectionBinder {
? inferredData
: new WrappedInferredData( inferredData, "element" );
final Comment comment = property.getAnnotation( Comment.class );
final AnnotatedColumn[] elementColumns = elementColumns(
final AnnotatedColumns elementColumns = elementColumns(
propertyHolder,
nullability,
entityBinder,
@ -419,6 +421,7 @@ public abstract class CollectionBinder {
if ( oneToManyAnn != null ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
if ( column.isSecondary() ) {
//TODO: fix the error message
throw new NotYetImplementedException( "Collections having FK in secondary table" );
}
}
@ -434,6 +437,7 @@ public abstract class CollectionBinder {
else if ( elementCollectionAnn != null ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) {
if ( column.isSecondary() ) {
//TODO: fix the error message
throw new NotYetImplementedException( "Collections having FK in secondary table" );
}
}
@ -487,7 +491,7 @@ public abstract class CollectionBinder {
}
}
private static AnnotatedColumn[] elementColumns(
private static AnnotatedColumns elementColumns(
PropertyHolder propertyHolder,
Nullability nullability,
EntityBinder entityBinder,
@ -553,7 +557,7 @@ public abstract class CollectionBinder {
? new jakarta.persistence.Column[] { new MapKeyColumnDelegator( property.getAnnotation( MapKeyColumn.class ) ) }
: null;
final AnnotatedColumn[] mapColumns = buildColumnsFromAnnotations(
final AnnotatedColumns mapColumns = buildColumnsFromAnnotations(
keyColumns,
comment,
Nullability.FORCED_NOT_NULL,
@ -1544,9 +1548,8 @@ public abstract class CollectionBinder {
foreignJoinColumns.setPersistentClass( associatedClass, joins, inheritanceStatePerClass );
for ( AnnotatedJoinColumn column : foreignJoinColumns.getColumns() ) {
column.setJoins( joins );
//TODO: this is lame, should get the table from foreignJoinColumns
collection.setCollectionTable( column.getTable() );
}
collection.setCollectionTable( foreignJoinColumns.getTable() );
if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
}
@ -1555,7 +1558,7 @@ public abstract class CollectionBinder {
handleWhere( false );
final PersistentClass targetEntity = persistentClasses.get( getElementType().getName() );
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled, buildingContext );
bindCollectionSecondPass( targetEntity, foreignJoinColumns, cascadeDeleteEnabled );
if ( !collection.isInverse() && !collection.getKey().isNullable() ) {
createOneToManyBackref( oneToMany );
@ -1838,12 +1841,11 @@ public abstract class CollectionBinder {
boolean cascadeDeleteEnabled,
boolean noConstraintByDefault,
XProperty property,
PropertyHolder propertyHolder,
MetadataBuildingContext buildingContext) {
PropertyHolder propertyHolder) {
// give a chance to override the referenced property name
// has to do that here because the referencedProperty creation happens in a FKSecondPass for ManyToOne yuk!
overrideReferencedPropertyName( collection, joinColumns, buildingContext );
overrideReferencedPropertyName( collection, joinColumns );
final String referencedPropertyName = collection.getReferencedPropertyName();
//binding key reference using column
@ -1955,15 +1957,12 @@ public abstract class CollectionBinder {
}
}
private void overrideReferencedPropertyName(
Collection collection,
AnnotatedJoinColumns joinColumns,
MetadataBuildingContext context) {
private void overrideReferencedPropertyName(Collection collection, AnnotatedJoinColumns joinColumns) {
if ( hasMappedBy() && joinColumns.getColumns().length > 0 ) {
final String entityName = joinColumns.getManyToManyOwnerSideEntityName() != null
? "inverse__" + joinColumns.getManyToManyOwnerSideEntityName()
: joinColumns.getPropertyHolder().getEntityName();
final InFlightMetadataCollector collector = context.getMetadataCollector();
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
final String referencedProperty = collector.getPropertyReferencedAssociation( entityName, mappedBy );
if ( referencedProperty != null ) {
collection.setReferencedPropertyName( referencedProperty );
@ -2021,7 +2020,7 @@ public abstract class CollectionBinder {
bindFilters( isCollectionOfEntities );
handleWhere( isCollectionOfEntities );
bindCollectionSecondPass( targetEntity, joinColumns, cascadeDeleteEnabled, buildingContext );
bindCollectionSecondPass( targetEntity, joinColumns, cascadeDeleteEnabled );
if ( isCollectionOfEntities ) {
final ManyToOne element = handleCollectionOfEntities(
@ -2033,7 +2032,7 @@ public abstract class CollectionBinder {
targetEntity,
hqlOrderBy
);
bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany, buildingContext );
bindManyToManyInverseForeignKey( targetEntity, inverseJoinColumns, element, oneToMany );
}
else if ( isManyToAny ) {
handleManyToAny(
@ -2052,7 +2051,6 @@ public abstract class CollectionBinder {
elementType,
property,
propertyHolder,
buildingContext,
hqlOrderBy
);
}
@ -2062,12 +2060,11 @@ public abstract class CollectionBinder {
private void handleElementCollection(
Collection collection,
AnnotatedColumn[] elementColumns,
AnnotatedColumns elementColumns,
boolean isEmbedded,
XClass elementType,
XProperty property,
PropertyHolder parentPropertyHolder,
MetadataBuildingContext buildingContext,
String hqlOrderBy) {
final XClass elementClass;
final AnnotatedClassType classType;
@ -2151,7 +2148,7 @@ public abstract class CollectionBinder {
false,
false,
true,
resolveCustomInstantiator(property, elementClass, buildingContext),
resolveCustomInstantiator( property, elementClass, buildingContext ),
compositeUserType,
buildingContext,
inheritanceStatePerClass
@ -2170,26 +2167,16 @@ public abstract class CollectionBinder {
holder.prepare( property );
final BasicValueBinder elementBinder =
new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext);
new BasicValueBinder( BasicValueBinder.Kind.COLLECTION_ELEMENT, buildingContext );
elementBinder.setReturnedClassName( elementType.getName() );
if ( elementColumns == null || elementColumns.length == 0 ) {
elementColumns = new AnnotatedColumn[1];
AnnotatedColumn column = new AnnotatedColumn();
column.setImplicit( false );
//not following the spec but more clean
column.setNullable( true );
column.setLogicalColumnName( Collection.DEFAULT_ELEMENT_COLUMN_NAME );
//TODO create an EMPTY_JOINS collection
column.setJoins( new HashMap<>() );
column.setBuildingContext(buildingContext);
column.bind();
elementColumns[0] = column;
}
//override the table
for (AnnotatedColumn column : elementColumns) {
column.setTable( collection.getCollectionTable() );
}
elementBinder.setColumns(elementColumns);
final AnnotatedColumns actualColumns = createElementColumnsIfNecessary(
collection,
elementColumns,
Collection.DEFAULT_ELEMENT_COLUMN_NAME,
null,
buildingContext
);
elementBinder.setColumns( actualColumns );
elementBinder.setType(
property,
elementClass,
@ -2206,6 +2193,34 @@ public abstract class CollectionBinder {
}
}
static AnnotatedColumns createElementColumnsIfNecessary(
Collection collection,
AnnotatedColumns elementColumns,
String defaultName,
Long defaultLength,
MetadataBuildingContext context) {
if ( elementColumns == null || isEmpty( elementColumns.getColumns() ) ) {
final AnnotatedColumn column = new AnnotatedColumn();
column.setLogicalColumnName( defaultName );
if ( defaultLength!=null ) {
column.setLength( defaultLength );
}
column.setImplicit( false );
//not following the spec but more clean
column.setNullable( true );
//TODO create an EMPTY_JOINS collection
column.setJoins( new HashMap<>() );
column.setBuildingContext( context );
column.bind();
final AnnotatedColumns result = new AnnotatedColumns();
result.setColumns( new AnnotatedColumn[] { column } );
elementColumns = result;
}
//override the table
elementColumns.setTable( collection.getCollectionTable() );
return elementColumns;
}
private ManyToOne handleCollectionOfEntities(
Collection collection,
XClass elementType,
@ -2214,7 +2229,7 @@ public abstract class CollectionBinder {
MetadataBuildingContext buildingContext,
PersistentClass collectionEntity,
String hqlOrderBy) {
ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() );
final ManyToOne element = new ManyToOne( buildingContext, collection.getCollectionTable() );
collection.setElement( element );
element.setReferencedEntityName( elementType.getName() );
//element.setFetchMode( fetchMode );
@ -2273,16 +2288,14 @@ public abstract class CollectionBinder {
buildingContext.getBootstrapContext().getReflectionManager()
);
XProperty prop = inferredData.getProperty();
final XProperty prop = inferredData.getProperty();
final jakarta.persistence.Column discriminatorColumnAnn = prop.getAnnotation( jakarta.persistence.Column.class );
final Formula discriminatorFormulaAnn = getOverridableAnnotation( prop, Formula.class, buildingContext);
//override the table
for ( AnnotatedColumn column : inverseJoinColumns.getColumns() ) {
column.setTable( collection.getCollectionTable() );
}
inverseJoinColumns.setTable( collection.getCollectionTable() );
ManyToAny anyAnn = property.getAnnotation( ManyToAny.class );
final ManyToAny anyAnn = property.getAnnotation( ManyToAny.class );
final Any any = buildAnyValue(
discriminatorColumnAnn,
discriminatorFormulaAnn,
@ -2486,8 +2499,7 @@ public abstract class CollectionBinder {
private void bindCollectionSecondPass(
PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns,
boolean cascadeDeleteEnabled,
MetadataBuildingContext context) {
boolean cascadeDeleteEnabled) {
if ( !hasMappedBy() ) {
createSyntheticPropertyReference(
@ -2497,7 +2509,7 @@ public abstract class CollectionBinder {
collection,
propertyName,
false,
context
buildingContext
);
}
@ -2505,10 +2517,9 @@ public abstract class CollectionBinder {
collection,
joinColumns,
cascadeDeleteEnabled,
context.getBuildingOptions().isNoConstraintByDefault(),
buildingContext.getBuildingOptions().isNoConstraintByDefault(),
property,
propertyHolder,
context
propertyHolder
);
if ( property.isAnnotationPresent( ElementCollection.class ) ) {
@ -2521,7 +2532,7 @@ public abstract class CollectionBinder {
joinColumns,
key,
false,
context
buildingContext
);
key.sortProperties();
}
@ -2545,8 +2556,7 @@ public abstract class CollectionBinder {
PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns,
SimpleValue value,
boolean unique,
MetadataBuildingContext context) {
boolean unique) {
if ( hasMappedBy() ) {
final Property property = targetEntity.getRecursiveProperty( mappedBy );
final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property );
@ -2554,12 +2564,12 @@ public abstract class CollectionBinder {
for ( Selectable selectable: mappedByColumns ) {
firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value );
}
final String referencedPropertyName = context.getMetadataCollector()
final String referencedPropertyName = buildingContext.getMetadataCollector()
.getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy );
if ( referencedPropertyName != null ) {
//TODO always a many to one?
( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName );
context.getMetadataCollector()
buildingContext.getMetadataCollector()
.addUniquePropertyReference( targetEntity.getEntityName(), referencedPropertyName );
}
( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null );
@ -2573,7 +2583,7 @@ public abstract class CollectionBinder {
value,
propertyName,
true,
context
buildingContext
);
if ( notFoundAction == NotFoundAction.IGNORE ) {
value.disableForeignKey();
@ -2584,7 +2594,7 @@ public abstract class CollectionBinder {
joinColumns,
value,
unique,
context
buildingContext
);
}
}
@ -2617,7 +2627,7 @@ public abstract class CollectionBinder {
this.isExplicitAssociationTable = explicitAssocTable;
}
public void setElementColumns(AnnotatedColumn[] elementColumns) {
public void setElementColumns(AnnotatedColumns elementColumns) {
this.elementColumns = elementColumns;
}
@ -2637,7 +2647,7 @@ public abstract class CollectionBinder {
this.notFoundAction = notFoundAction;
}
public void setMapKeyColumns(AnnotatedColumn[] mapKeyColumns) {
public void setMapKeyColumns(AnnotatedColumns mapKeyColumns) {
this.mapKeyColumns = mapKeyColumns;
}

View File

@ -789,7 +789,7 @@ public class EntityBinder {
}
discriminatorColumn.setJoins( secondaryTables );
discriminatorColumn.setPropertyHolder( propertyHolder );
BasicValue discriminatorColumnBinding = new BasicValue( context, rootClass.getTable() );
final BasicValue discriminatorColumnBinding = new BasicValue( context, rootClass.getTable() );
rootClass.setDiscriminator( discriminatorColumnBinding );
discriminatorColumn.linkWithValue( discriminatorColumnBinding );
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );

View File

@ -12,12 +12,9 @@ import java.util.function.Supplier;
import org.hibernate.MappingException;
import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.NotFoundAction;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.IdGeneratorResolverSecondPass;
import org.hibernate.cfg.PropertyData;
import org.hibernate.cfg.PropertyInferredData;
@ -71,7 +68,7 @@ public class IdBagBinder extends BagBinder {
"id"
);
final AnnotatedColumn[] idColumns = AnnotatedColumn.buildColumnsFromAnnotations(
final AnnotatedColumns idColumns = AnnotatedColumn.buildColumnsFromAnnotations(
new Column[] { collectionIdAnn.column() },
null,
Nullability.FORCED_NOT_NULL,
@ -82,7 +79,7 @@ public class IdBagBinder extends BagBinder {
);
//we need to make sure all id columns must be not-null.
for ( AnnotatedColumn idColumn:idColumns ) {
for ( AnnotatedColumn idColumn : idColumns.getColumns() ) {
idColumn.setNullable( false );
}

View File

@ -12,8 +12,9 @@ import java.util.function.Supplier;
import org.hibernate.MappingException;
import org.hibernate.annotations.OrderBy;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.PropertyHolderBuilder;
import org.hibernate.cfg.SecondPass;
@ -87,7 +88,9 @@ public class ListBinder extends CollectionBinder {
}
indexColumn.setPropertyHolder( valueHolder );
final BasicValueBinder valueBinder = new BasicValueBinder( BasicValueBinder.Kind.LIST_INDEX, buildingContext );
valueBinder.setColumns( new AnnotatedColumn[] { indexColumn } );
final AnnotatedColumns result = new AnnotatedColumns();
result.setColumns( new AnnotatedColumn[] { indexColumn } );
valueBinder.setColumns(result);
valueBinder.setReturnedClassName( Integer.class.getName() );
valueBinder.setType( property, getElementType(), null, null );
// valueBinder.setExplicitType( "integer" );
@ -95,7 +98,13 @@ public class ListBinder extends CollectionBinder {
indexColumn.linkWithValue( indexValue );
listValueMapping.setIndex( indexValue );
listValueMapping.setBaseIndex( indexColumn.getBase() );
if ( listValueMapping.isOneToMany() && !listValueMapping.getKey().isNullable() && !listValueMapping.isInverse() ) {
createBackref( listValueMapping );
}
private void createBackref(List listValueMapping) {
if ( listValueMapping.isOneToMany()
&& !listValueMapping.getKey().isNullable()
&& !listValueMapping.isInverse() ) {
final String entityName = ( (OneToMany) listValueMapping.getElement() ).getReferencedEntityName();
final PersistentClass referenced = buildingContext.getMetadataCollector().getEntityBinding( entityName );
final IndexBackref backref = new IndexBackref();

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.cfg.annotations;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
@ -22,11 +21,11 @@ import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.CollectionPropertyHolder;
import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.PropertyData;
@ -100,7 +99,6 @@ public class MapBinder extends CollectionBinder {
mapKeyPropertyName,
property,
isEmbedded,
buildingContext,
mapKeyColumns,
mapKeyManyToManyColumns,
inverseJoinColumns != null ? inverseJoinColumns.getPropertyName() : null
@ -123,7 +121,7 @@ public class MapBinder extends CollectionBinder {
if ( selectable.isFormula() ) {
throw new AssertionFailure( "Map key mapped by @MapKeyColumn is a Formula" );
}
Column column = (Column) selectable;
final Column column = (Column) selectable;
if ( !column.isNullable() ) {
final PersistentClass persistentClass = ( ( OneToMany ) map.getElement() ).getAssociatedClass();
// check if the index column has been mapped by the associated entity to a property;
@ -158,207 +156,62 @@ public class MapBinder extends CollectionBinder {
String mapKeyPropertyName,
XProperty property,
boolean isEmbedded,
MetadataBuildingContext buildingContext,
AnnotatedColumn[] mapKeyColumns,
AnnotatedColumns mapKeyColumns,
AnnotatedJoinColumns mapKeyManyToManyColumns,
String targetPropertyName) {
if ( mapKeyPropertyName != null ) {
//this is an EJB3 @MapKey
PersistentClass associatedClass = persistentClasses.get( elementType.getName() );
if ( associatedClass == null ) {
throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
}
Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName );
if ( mapProperty == null ) {
throw new AnnotationException( "Map key property '" + mapKeyPropertyName
+ "' not found in target entity '" + associatedClass.getEntityName() + "'" );
}
org.hibernate.mapping.Map map = (org.hibernate.mapping.Map) this.collection;
// HHH-11005 - if InheritanceType.JOINED then need to find class defining the column
InheritanceState inheritanceState = inheritanceStatePerClass.get( elementType );
PersistentClass targetPropertyPersistentClass = InheritanceType.JOINED.equals( inheritanceState.getType() ) ?
mapProperty.getPersistentClass() :
associatedClass;
Value indexValue = createFormulatedValue(
mapProperty.getValue(), map, targetPropertyName, associatedClass, targetPropertyPersistentClass, buildingContext
);
map.setIndex( indexValue );
map.setMapKeyPropertyName( mapKeyPropertyName );
handleExplicitMapKey( elementType, persistentClasses, mapKeyPropertyName );
}
else {
//this is a true Map mapping
//TODO ugly copy/paste from CollectionBinder.bindManyToManySecondPass
String mapKeyType;
Class<?> target = void.class;
/*
* target has priority over reflection for the map key type
* JPA 2 has priority
*/
if ( property.isAnnotationPresent( MapKeyClass.class ) ) {
target = property.getAnnotation( MapKeyClass.class ).value();
}
if ( !void.class.equals( target ) ) {
mapKeyType = target.getName();
}
else {
mapKeyType = property.getMapKey().getName();
}
PersistentClass collectionEntity = persistentClasses.get( mapKeyType );
boolean isIndexOfEntities = collectionEntity != null;
ManyToOne element = null;
org.hibernate.mapping.Map mapValue = (org.hibernate.mapping.Map) this.collection;
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 = new ManyToOne( buildingContext, mapValue.getCollectionTable() );
mapValue.setIndex( element );
element.setReferencedEntityName( mapKeyType );
//element.setFetchMode( fetchMode );
//element.setLazy( fetchMode != FetchMode.JOIN );
//make the second join non lazy
element.setFetchMode( FetchMode.JOIN );
element.setLazy( false );
//does not make sense for a map key element.setIgnoreNotFound( ignoreNotFound );
element = handleCollectionKeyedByEntities( buildingContext, mapKeyType, map );
}
else {
final XClass keyXClass;
AnnotatedClassType classType;
element = null;
final XClass keyClass;
final AnnotatedClassType classType;
if ( PRIMITIVE_NAMES.contains( mapKeyType ) ) {
classType = AnnotatedClassType.NONE;
keyXClass = null;
keyClass = null;
}
else {
final BootstrapContext bootstrapContext = buildingContext.getBootstrapContext();
final Class<Object> mapKeyClass = bootstrapContext.getClassLoaderAccess().classForName( mapKeyType );
keyXClass = bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
classType = buildingContext.getMetadataCollector().getClassType( keyXClass );
keyClass = bootstrapContext.getReflectionManager().toXClass( mapKeyClass );
// force in case of attribute override naming the key
if ( isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property ) ) {
classType = AnnotatedClassType.EMBEDDABLE;
}
classType = isEmbedded || mappingDefinedAttributeOverrideOnMapKey( property )
? AnnotatedClassType.EMBEDDABLE
: buildingContext.getMetadataCollector().getClassType( keyClass );
}
CollectionPropertyHolder holder = buildPropertyHolder(
mapValue,
qualify( mapValue.getRole(), "mapkey" ),
keyXClass,
handleIndex(
property,
propertyHolder,
buildingContext
mapKeyColumns,
mapKeyType,
map,
keyClass,
classType,
buildCollectionPropertyHolder( property, map, keyClass ),
getAccessType( map )
);
// 'propertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
propertyHolder.startingProperty( property );
holder.prepare( property );
PersistentClass owner = mapValue.getOwner();
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" );
}
final Class<? extends CompositeUserType<?>> compositeUserType = resolveCompositeUserType(
property,
keyXClass,
buildingContext
);
if ( AnnotatedClassType.EMBEDDABLE.equals( classType ) || compositeUserType != null ) {
EntityBinder entityBinder = new EntityBinder();
PropertyData inferredData = isHibernateExtensionMapping()
? new PropertyPreloadedData(AccessType.PROPERTY, "index", keyXClass)
: new PropertyPreloadedData(AccessType.PROPERTY, "key", keyXClass);
//"key" is the JPA 2 prefix for map keys
//TODO be smart with isNullable
Component component = AnnotationBinder.fillComponent(
holder,
inferredData,
accessType,
true,
entityBinder,
false,
false,
true,
null,
compositeUserType,
buildingContext,
inheritanceStatePerClass
);
mapValue.setIndex( component );
}
else {
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
elementBinder.setReturnedClassName( mapKeyType );
AnnotatedColumn[] elementColumns = mapKeyColumns;
if ( elementColumns == null || elementColumns.length == 0 ) {
elementColumns = new AnnotatedColumn[1];
AnnotatedColumn column = new AnnotatedColumn();
column.setImplicit( false );
column.setNullable( true );
column.setLength( Size.DEFAULT_LENGTH );
column.setLogicalColumnName( Collection.DEFAULT_KEY_COLUMN_NAME );
//TODO create an EMPTY_JOINS collection
column.setJoins( new HashMap<>() );
column.setBuildingContext( buildingContext );
column.bind();
elementColumns[0] = column;
}
//override the table
for (AnnotatedColumn column : elementColumns) {
column.setTable( mapValue.getCollectionTable() );
}
elementBinder.setColumns( elementColumns );
//do not call setType as it extracts the type from @Type
//the algorithm generally does not apply for map key anyway
elementBinder.setType(
property,
keyXClass,
this.collection.getOwnerEntityName(),
holder.mapKeyAttributeConverterDescriptor( property, keyXClass )
);
elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType( accessType );
mapValue.setIndex( elementBinder.make() );
}
}
//FIXME pass the Index Entity JoinColumns
if ( !collection.isOneToMany() ) {
//index column should not be null
for ( AnnotatedJoinColumn col : mapKeyManyToManyColumns.getColumns() ) {
col.forceNotNull();
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getColumns() ) {
column.forceNotNull();
}
}
if ( element != null ) {
final jakarta.persistence.ForeignKey foreignKey = getMapKeyForeignKey( property );
if ( foreignKey != null ) {
if ( foreignKey.value() == ConstraintMode.NO_CONSTRAINT
|| foreignKey.value() == ConstraintMode.PROVIDER_DEFAULT
&& getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) {
element.disableForeignKey();
}
else {
element.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
element.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
}
}
handleForeignKey( property, element );
}
if ( isIndexOfEntities ) {
@ -366,13 +219,185 @@ public class MapBinder extends CollectionBinder {
collectionEntity,
mapKeyManyToManyColumns,
element,
false, //a map key column has no unique constraint
buildingContext
false //a map key column has no unique constraint
);
}
}
}
private static String getKeyType(XProperty property) {
//target has priority over reflection for the map key type
//JPA 2 has priority
final Class<?> target = property.isAnnotationPresent( MapKeyClass.class )
? property.getAnnotation( MapKeyClass.class ).value()
: void.class;
return void.class.equals( target ) ? property.getMapKey().getName() : target.getName();
}
private void handleExplicitMapKey(
XClass elementType,
Map<String, PersistentClass> persistentClasses,
String mapKeyPropertyName) {
final PersistentClass associatedClass = persistentClasses.get( elementType.getName() );
if ( associatedClass == null ) {
throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
}
final Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName);
if ( mapProperty == null ) {
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 PersistentClass targetEntity = InheritanceType.JOINED == inheritanceState.getType()
? mapProperty.getPersistentClass()
: associatedClass;
final Value indexValue = createFormulatedValue( mapProperty.getValue(), map, associatedClass, targetEntity );
map.setIndex( indexValue );
map.setMapKeyPropertyName(mapKeyPropertyName);
}
private CollectionPropertyHolder buildCollectionPropertyHolder(
XProperty property,
org.hibernate.mapping.Map map,
XClass keyClass) {
final CollectionPropertyHolder holder = buildPropertyHolder(
map,
qualify( map.getRole(), "mapkey" ),
keyClass,
property,
propertyHolder,
buildingContext
);
// 'propertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty
propertyHolder.startingProperty(property);
holder.prepare(property);
return holder;
}
private void handleForeignKey(XProperty property, ManyToOne element) {
final jakarta.persistence.ForeignKey foreignKey = getMapKeyForeignKey( property );
if ( foreignKey != null ) {
final ConstraintMode constraintMode = foreignKey.value();
if ( constraintMode == ConstraintMode.NO_CONSTRAINT
|| constraintMode == ConstraintMode.PROVIDER_DEFAULT
&& getBuildingContext().getBuildingOptions().isNoConstraintByDefault() ) {
element.disableForeignKey();
}
else {
element.setForeignKeyName( nullIfEmpty( foreignKey.name() ) );
element.setForeignKeyDefinition( nullIfEmpty( foreignKey.foreignKeyDefinition() ) );
}
}
}
//similar to CollectionBinder.handleCollectionOfEntities()
private static ManyToOne handleCollectionKeyedByEntities(
MetadataBuildingContext context,
String mapKeyType,
org.hibernate.mapping.Map map) {
final ManyToOne element;
element = new ManyToOne(context, map.getCollectionTable() );
map.setIndex( element );
element.setReferencedEntityName(mapKeyType);
//element.setFetchMode( fetchMode );
//element.setLazy( fetchMode != FetchMode.JOIN );
//make the second join non lazy
element.setFetchMode( FetchMode.JOIN );
element.setLazy( false );
//does not make sense for a map key element.setIgnoreNotFound( ignoreNotFound );
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(
XProperty property,
AnnotatedColumns mapKeyColumns,
String mapKeyType,
org.hibernate.mapping.Map map,
XClass keyClass,
AnnotatedClassType classType,
CollectionPropertyHolder holder,
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 );
}
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() );
}
}
private static Class<? extends CompositeUserType<?>> resolveCompositeUserType(
XProperty property,
XClass returnedClass,
@ -429,13 +454,11 @@ public class MapBinder extends CollectionBinder {
return annotation.name().startsWith( "key." );
}
protected Value createFormulatedValue(
private Value createFormulatedValue(
Value value,
Collection collection,
String targetPropertyName,
PersistentClass associatedClass,
PersistentClass targetPropertyPersistentClass,
MetadataBuildingContext buildingContext) {
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 ) ) {
@ -464,14 +487,7 @@ public class MapBinder extends CollectionBinder {
newProperty.setPropertyAccessorName( current.getPropertyAccessorName() );
newProperty.setSelectable( current.isSelectable() );
newProperty.setValue(
createFormulatedValue(
current.getValue(),
collection,
targetPropertyName,
associatedClass,
associatedClass,
buildingContext
)
createFormulatedValue( current.getValue(), collection, associatedClass, associatedClass )
);
indexComponent.addProperty( newProperty );
}
@ -504,8 +520,8 @@ public class MapBinder extends CollectionBinder {
SimpleValue sourceValue = (SimpleValue) value;
SimpleValue targetValue;
if ( value instanceof ManyToOne ) {
ManyToOne sourceManyToOne = (ManyToOne) sourceValue;
ManyToOne targetManyToOne = new ManyToOne( getBuildingContext(), mapKeyTable );
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

View File

@ -23,6 +23,7 @@ import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.InheritanceState;
@ -66,7 +67,7 @@ public class PropertyBinder {
private boolean lazy;
private String lazyGroup;
private AccessType accessType;
private AnnotatedColumn[] columns;
private AnnotatedColumns columns;
private PropertyHolder holder;
private Value value;
private boolean insertable = true;
@ -128,9 +129,10 @@ public class PropertyBinder {
this.accessType = accessType;
}
public void setColumns(AnnotatedColumn[] columns) {
insertable = columns[0].isInsertable();
updatable = columns[0].isUpdatable();
public void setColumns(AnnotatedColumns columns) {
final AnnotatedColumn firstColumn = columns.getColumns()[0];
insertable = firstColumn.isInsertable();
updatable = firstColumn.isUpdatable();
//consistency is checked later when we know the property name
this.columns = columns;
}
@ -233,7 +235,7 @@ public class PropertyBinder {
private Property bind(Property prop) {
if ( isId ) {
final RootClass rootClass = ( RootClass ) holder.getPersistentClass();
final RootClass rootClass = (RootClass) holder.getPersistentClass();
//if an xToMany, it has to be wrapped today.
//FIXME this poses a problem as the PK is the class instead of the associated class which is not really compliant with the spec
if ( isXToMany || entityBinder.wrapIdsInEmbeddedComponents() ) {
@ -257,7 +259,7 @@ public class PropertyBinder {
}
else {
rootClass.setIdentifier( (KeyValue) getValue() );
if (embedded) {
if ( embedded ) {
rootClass.setEmbeddedIdentifier( true );
}
else {
@ -267,7 +269,7 @@ public class PropertyBinder {
inheritanceStatePerClass,
buildingContext
);
if (superclass != null) {
if ( superclass != null ) {
superclass.setDeclaredIdentifierProperty(prop);
}
else {
@ -355,7 +357,7 @@ public class PropertyBinder {
prop.setOptimisticLocked( ((Collection) value).isOptimisticLocked() );
}
else if ( property != null && property.isAnnotationPresent(OptimisticLock.class) ) {
OptimisticLock lockAnn = property.getAnnotation(OptimisticLock.class);
final OptimisticLock lockAnn = property.getAnnotation(OptimisticLock.class);
validateOptimisticLock(lockAnn);
prop.setOptimisticLocked( !lockAnn.excluded() );
}

View File

@ -274,7 +274,6 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
@Override
public void addColumn(Column incomingColumn, boolean isInsertable, boolean isUpdatable) {
super.addColumn( incomingColumn, isInsertable, isUpdatable );
checkSelectable( incomingColumn );
}