finally move context + joins from AnnotatedColumn

This commit is contained in:
Gavin King 2022-10-31 11:52:46 +01:00
parent 18003b92dc
commit e4c1d493e3
23 changed files with 650 additions and 697 deletions

View File

@ -6,10 +6,10 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.Check; import org.hibernate.annotations.Check;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
@ -65,13 +65,10 @@ public class AnnotatedColumn {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, AnnotatedColumn.class.getName()); private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, AnnotatedColumn.class.getName());
private MetadataBuildingContext context;
private Column mappingColumn; private Column mappingColumn;
private boolean insertable = true; private boolean insertable = true;
private boolean updatable = true; private boolean updatable = true;
private String explicitTableName; // the JPA @Column annotation lets you specify a table name private String explicitTableName; // the JPA @Column annotation lets you specify a table name
protected Map<String, Join> joins;
private boolean isImplicit; private boolean isImplicit;
public String sqlType; public String sqlType;
private Long length; private Long length;
@ -94,7 +91,12 @@ public class AnnotatedColumn {
private AnnotatedColumns parent; private AnnotatedColumns parent;
void setParent(AnnotatedColumns parent) { public AnnotatedColumns getParent() {
return parent;
}
public void setParent(AnnotatedColumns parent) {
parent.addColumn( this );
this.parent = parent; this.parent = parent;
} }
@ -154,14 +156,6 @@ public class AnnotatedColumn {
this.updatable = updatable; this.updatable = updatable;
} }
protected MetadataBuildingContext getBuildingContext() {
return context;
}
public void setBuildingContext(MetadataBuildingContext context) {
this.context = context;
}
public void setImplicit(boolean implicit) { public void setImplicit(boolean implicit) {
isImplicit = implicit; isImplicit = implicit;
} }
@ -337,21 +331,21 @@ public class AnnotatedColumn {
private String processColumnName(String columnName, boolean applyNamingStrategy) { private String processColumnName(String columnName, boolean applyNamingStrategy) {
if ( applyNamingStrategy ) { if ( applyNamingStrategy ) {
final Database database = context.getMetadataCollector().getDatabase(); final Database database = getBuildingContext().getMetadataCollector().getDatabase();
return context.getBuildingOptions().getPhysicalNamingStrategy() return getBuildingContext().getBuildingOptions().getPhysicalNamingStrategy()
.toPhysicalColumnName( database.toIdentifier( columnName ), database.getJdbcEnvironment() ) .toPhysicalColumnName( database.toIdentifier( columnName ), database.getJdbcEnvironment() )
.render( database.getDialect() ); .render( database.getDialect() );
} }
else { else {
return context.getObjectNameNormalizer().toDatabaseIdentifierText( columnName ); return getBuildingContext().getObjectNameNormalizer().toDatabaseIdentifierText( columnName );
} }
} }
private String inferColumnName(String propertyName) { private String inferColumnName(String propertyName) {
final Database database = context.getMetadataCollector().getDatabase(); final Database database = getBuildingContext().getMetadataCollector().getDatabase();
final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer(); final ObjectNameNormalizer normalizer = getBuildingContext().getObjectNameNormalizer();
final ImplicitNamingStrategy implicitNamingStrategy = context.getBuildingOptions().getImplicitNamingStrategy(); final ImplicitNamingStrategy implicitNamingStrategy = getBuildingContext().getBuildingOptions().getImplicitNamingStrategy();
Identifier implicitName = normalizer.normalizeIdentifierQuoting( Identifier implicitName = normalizer.normalizeIdentifierQuoting(
implicitNamingStrategy.determineBasicColumnName( implicitNamingStrategy.determineBasicColumnName(
@ -373,7 +367,7 @@ public class AnnotatedColumn {
@Override @Override
public MetadataBuildingContext getBuildingContext() { public MetadataBuildingContext getBuildingContext() {
return context; return AnnotatedColumn.this.getBuildingContext();
} }
} }
) )
@ -387,7 +381,7 @@ public class AnnotatedColumn {
); );
} }
return context.getBuildingOptions().getPhysicalNamingStrategy() return getBuildingContext().getBuildingOptions().getPhysicalNamingStrategy()
.toPhysicalColumnName( implicitName, database.getJdbcEnvironment() ) .toPhysicalColumnName( implicitName, database.getJdbcEnvironment() )
.render( database.getDialect() ); .render( database.getDialect() );
} }
@ -409,20 +403,14 @@ public class AnnotatedColumn {
} }
public void setNullable(boolean nullable) { public void setNullable(boolean nullable) {
this.nullable = nullable;
if ( mappingColumn != null ) { if ( mappingColumn != null ) {
mappingColumn.setNullable( nullable ); mappingColumn.setNullable( nullable );
} }
else {
this.nullable = nullable;
}
}
public void setJoins(Map<String, Join> joins) {
this.joins = joins;
} }
public PropertyHolder getPropertyHolder() { public PropertyHolder getPropertyHolder() {
return parent.getPropertyHolder(); return getParent().getPropertyHolder();
} }
protected void setMappingColumn(Column mappingColumn) { protected void setMappingColumn(Column mappingColumn) {
@ -436,8 +424,8 @@ public class AnnotatedColumn {
} }
else { else {
final Table table = value.getTable(); final Table table = value.getTable();
if ( parent != null ) { if ( getParent() != null ) {
parent.setTableInternal( table ); getParent().setTableInternal( table );
} }
getMappingColumn().setValue( value ); getMappingColumn().setValue( value );
value.addColumn( getMappingColumn(), insertable, updatable ); value.addColumn( getMappingColumn(), insertable, updatable );
@ -452,9 +440,9 @@ public class AnnotatedColumn {
logicalColumnName = this.logicalColumnName; logicalColumnName = this.logicalColumnName;
} }
else { else {
final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer(); final ObjectNameNormalizer normalizer = getBuildingContext().getObjectNameNormalizer();
final Database database = context.getMetadataCollector().getDatabase(); final Database database = getBuildingContext().getMetadataCollector().getDatabase();
final ImplicitNamingStrategy implicitNamingStrategy = context.getBuildingOptions() final ImplicitNamingStrategy implicitNamingStrategy = getBuildingContext().getBuildingOptions()
.getImplicitNamingStrategy(); .getImplicitNamingStrategy();
final Identifier implicitName = normalizer.normalizeIdentifierQuoting( final Identifier implicitName = normalizer.normalizeIdentifierQuoting(
@ -472,14 +460,14 @@ public class AnnotatedColumn {
@Override @Override
public MetadataBuildingContext getBuildingContext() { public MetadataBuildingContext getBuildingContext() {
return context; return AnnotatedColumn.this.getBuildingContext();
} }
} }
) )
); );
logicalColumnName = implicitName.render( database.getDialect() ); logicalColumnName = implicitName.render( database.getDialect() );
} }
context.getMetadataCollector().addColumnNameBinding( value.getTable(), logicalColumnName, getMappingColumn() ); getBuildingContext().getMetadataCollector().addColumnNameBinding( value.getTable(), logicalColumnName, getMappingColumn() );
} }
/** /**
@ -490,38 +478,17 @@ public class AnnotatedColumn {
* @throws AnnotationException missing secondary table * @throws AnnotationException missing secondary table
*/ */
public Table getTable() { public Table getTable() {
return parent.getTable(); return getParent().getTable();
} }
//TODO: move to AnnotatedColumns //TODO: move to AnnotatedColumns
public boolean isSecondary() { public boolean isSecondary() {
if ( getPropertyHolder() == null ) { return getParent().isSecondary();
throw new AssertionFailure( "Should not call isSecondary() on column w/o persistent class defined" );
}
return isNotEmpty( explicitTableName )
&& !getPropertyHolder().getTable().getName().equals( explicitTableName );
} }
//TODO: move to AnnotatedColumns //TODO: move to AnnotatedColumns
public Join getJoin() { public Join getJoin() {
Join join = joins.get( explicitTableName ); return getParent().getJoin();
if ( join == null ) {
// annotation binding seems to use logical and physical naming somewhat inconsistently...
final String physicalTableName = getBuildingContext().getMetadataCollector()
.getPhysicalTableName( explicitTableName );
if ( physicalTableName != null ) {
join = joins.get( physicalTableName );
}
}
if ( join == null ) {
throw new AnnotationException(
"Secondary table '" + explicitTableName + "' for property '" + getPropertyHolder().getClassName()
+ "' is not declared (use '@SecondaryTable' to declare the secondary table)"
);
}
return join;
} }
public void forceNotNull() { public void forceNotNull() {
@ -531,6 +498,7 @@ public class AnnotatedColumn {
"likely a formula" "likely a formula"
); );
} }
nullable = false;
mappingColumn.setNullable( false ); mappingColumn.setNullable( false );
} }
@ -669,16 +637,18 @@ public class AnnotatedColumn {
MetadataBuildingContext context) { MetadataBuildingContext context) {
if ( formulaAnn != null ) { if ( formulaAnn != null ) {
AnnotatedColumn formulaColumn = new AnnotatedColumn(); final AnnotatedColumns parent = new AnnotatedColumns();
parent.setPropertyHolder( propertyHolder );
parent.setBuildingContext( context );
parent.setJoins( secondaryTables ); //unnecessary
final AnnotatedColumn formulaColumn = new AnnotatedColumn();
formulaColumn.setFormula( formulaAnn.value() ); formulaColumn.setFormula( formulaAnn.value() );
formulaColumn.setImplicit( false ); formulaColumn.setImplicit( false );
formulaColumn.setBuildingContext( context ); // formulaColumn.setBuildingContext( context );
// formulaColumn.setPropertyHolder( propertyHolder ); // formulaColumn.setPropertyHolder( propertyHolder );
final AnnotatedColumns result = new AnnotatedColumns(); formulaColumn.setParent( parent );
result.setPropertyHolder( propertyHolder );
result.setColumns( new AnnotatedColumn[] {formulaColumn} );
formulaColumn.bind(); formulaColumn.bind();
return result; return parent;
} }
else { else {
final jakarta.persistence.Column[] actualColumns = overrideColumns( columns, propertyHolder, inferredData ); final jakarta.persistence.Column[] actualColumns = overrideColumns( columns, propertyHolder, inferredData );
@ -740,10 +710,11 @@ public class AnnotatedColumn {
Map<String, Join> secondaryTables, Map<String, Join> secondaryTables,
MetadataBuildingContext context, MetadataBuildingContext context,
jakarta.persistence.Column[] actualCols) { jakarta.persistence.Column[] actualCols) {
final int length = actualCols.length; final AnnotatedColumns parent = new AnnotatedColumns();
final AnnotatedColumn[] columns = new AnnotatedColumn[length]; parent.setPropertyHolder( propertyHolder );
for ( int index = 0; index < length; index++ ) { parent.setJoins( secondaryTables );
final jakarta.persistence.Column column = actualCols[index]; parent.setBuildingContext( context );
for ( jakarta.persistence.Column column : actualCols ) {
final Database database = context.getMetadataCollector().getDatabase(); final Database database = context.getMetadataCollector().getDatabase();
final String sqlType = getSqlType( context, column ); final String sqlType = getSqlType( context, column );
final String tableName = getTableName( column, database ); final String tableName = getTableName( column, database );
@ -752,24 +723,20 @@ public class AnnotatedColumn {
// .toIdentifier( column.table() ); // .toIdentifier( column.table() );
// final Identifier physicalName = physicalNamingStrategy.toPhysicalTableName( logicalName ); // final Identifier physicalName = physicalNamingStrategy.toPhysicalTableName( logicalName );
// tableName = physicalName.render( database.getDialect() ); // tableName = physicalName.render( database.getDialect() );
columns[index] = buildColumn( buildColumn(
comment, comment,
propertyHolder, propertyHolder,
inferredData, inferredData,
suffixForDefaultColumnName, suffixForDefaultColumnName,
secondaryTables, parent,
context, actualCols.length,
length,
database, database,
column, column,
sqlType, sqlType,
tableName tableName
); );
} }
final AnnotatedColumns result = new AnnotatedColumns(); return parent;
result.setPropertyHolder( propertyHolder );
result.setColumns( columns );
return result;
} }
private static String getTableName(jakarta.persistence.Column column, Database database) { private static String getTableName(jakarta.persistence.Column column, Database database) {
@ -787,42 +754,39 @@ public class AnnotatedColumn {
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
String suffixForDefaultColumnName, String suffixForDefaultColumnName,
Map<String, Join> secondaryTables, AnnotatedColumns parent,
MetadataBuildingContext context, int numberOfColumns,
int length,
Database database, Database database,
jakarta.persistence.Column col, jakarta.persistence.Column column,
String sqlType, String sqlType,
String tableName) { String tableName) {
final String columnName = getLogicalColumnName( inferredData, suffixForDefaultColumnName, database, column );
final AnnotatedColumn column = new AnnotatedColumn(); final AnnotatedColumn annotatedColumn = new AnnotatedColumn();
column.setLogicalColumnName( getLogicalColumnName( inferredData, suffixForDefaultColumnName, database, col ) ); annotatedColumn.setLogicalColumnName( columnName );
column.setImplicit( false ); annotatedColumn.setImplicit( false );
column.setSqlType(sqlType); annotatedColumn.setSqlType( sqlType );
column.setLength( (long) col.length() ); annotatedColumn.setLength( (long) column.length() );
column.setPrecision( col.precision() ); annotatedColumn.setPrecision( column.precision() );
column.setScale( col.scale() ); annotatedColumn.setScale( column.scale() );
// column.setPropertyHolder( propertyHolder ); // annotatedColumn.setPropertyHolder( propertyHolder );
column.setPropertyName( getRelativePath( propertyHolder, inferredData.getPropertyName() ) ); annotatedColumn.setPropertyName( getRelativePath( propertyHolder, inferredData.getPropertyName() ) );
column.setNullable( col.nullable() ); //TODO force to not null if available? This is a (bad) user choice. annotatedColumn.setNullable( column.nullable() ); //TODO force to not null if available? This is a (bad) user choice.
if ( comment != null ) { if ( comment != null ) {
column.setComment( comment.value() ); annotatedColumn.setComment( comment.value() );
} }
column.setUnique( col.unique() ); annotatedColumn.setUnique( column.unique() );
column.setInsertable( col.insertable() ); annotatedColumn.setInsertable( column.insertable() );
column.setUpdatable( col.updatable() ); annotatedColumn.setUpdatable( column.updatable() );
column.setExplicitTableName( tableName ); annotatedColumn.setExplicitTableName( tableName );
column.setJoins( secondaryTables ); // annotatedColumn.setJoins( secondaryTables );
column.setBuildingContext( context ); // annotatedColumn.setBuildingContext( context );
column.applyColumnDefault( inferredData, length ); annotatedColumn.setParent( parent );
column.applyGeneratedAs( inferredData, length ); annotatedColumn.applyColumnDefault( inferredData, numberOfColumns );
column.applyCheckConstraint( inferredData, length ); annotatedColumn.applyGeneratedAs( inferredData, numberOfColumns );
column.extractDataFromPropertyData( propertyHolder, inferredData ); annotatedColumn.applyCheckConstraint( inferredData, numberOfColumns );
AnnotatedColumns temp = new AnnotatedColumns(); annotatedColumn.extractDataFromPropertyData( propertyHolder, inferredData );
temp.setPropertyHolder( propertyHolder ); annotatedColumn.bind();
temp.setColumns( new AnnotatedColumn[] { column } ); return annotatedColumn;
column.bind();
return column;
} }
private static String getLogicalColumnName( private static String getLogicalColumnName(
@ -843,9 +807,10 @@ public class AnnotatedColumn {
} }
private void applyColumnDefault(PropertyData inferredData, int length) { private void applyColumnDefault(PropertyData inferredData, int length) {
final XProperty xProperty = inferredData.getProperty(); final XProperty property = inferredData.getProperty();
if ( xProperty != null ) { if ( property != null ) {
final ColumnDefault columnDefault = getOverridableAnnotation( xProperty, ColumnDefault.class, context ); final ColumnDefault columnDefault =
getOverridableAnnotation( property, ColumnDefault.class, getBuildingContext() );
if ( columnDefault != null ) { if ( columnDefault != null ) {
if ( length!=1 ) { if ( length!=1 ) {
throw new MappingException("@ColumnDefault may only be applied to single-column mappings"); throw new MappingException("@ColumnDefault may only be applied to single-column mappings");
@ -859,9 +824,10 @@ public class AnnotatedColumn {
} }
private void applyGeneratedAs(PropertyData inferredData, int length) { private void applyGeneratedAs(PropertyData inferredData, int length) {
final XProperty xProperty = inferredData.getProperty(); final XProperty property = inferredData.getProperty();
if ( xProperty != null ) { if ( property != null ) {
final GeneratedColumn generatedColumn = getOverridableAnnotation( xProperty, GeneratedColumn.class, context ); final GeneratedColumn generatedColumn =
getOverridableAnnotation( property, GeneratedColumn.class, getBuildingContext() );
if ( generatedColumn != null ) { if ( generatedColumn != null ) {
if (length!=1) { if (length!=1) {
throw new MappingException("@GeneratedColumn may only be applied to single-column mappings"); throw new MappingException("@GeneratedColumn may only be applied to single-column mappings");
@ -875,9 +841,9 @@ public class AnnotatedColumn {
} }
private void applyCheckConstraint(PropertyData inferredData, int length) { private void applyCheckConstraint(PropertyData inferredData, int length) {
final XProperty xProperty = inferredData.getProperty(); final XProperty property = inferredData.getProperty();
if ( xProperty != null ) { if ( property != null ) {
final Check check = getOverridableAnnotation( xProperty, Check.class, context ); final Check check = getOverridableAnnotation( property, Check.class, getBuildingContext() );
if ( check != null ) { if ( check != null ) {
if (length!=1) { if (length!=1) {
throw new MappingException("@Check may only be applied to single-column mappings (use a table-level @Check)"); throw new MappingException("@Check may only be applied to single-column mappings (use a table-level @Check)");
@ -928,29 +894,11 @@ public class AnnotatedColumn {
Comment comment, Comment comment,
Nullability nullability, Nullability nullability,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedColumns result = new AnnotatedColumns(); final AnnotatedColumns columns = new AnnotatedColumns();
result.setPropertyHolder( propertyHolder ); columns.setPropertyHolder( propertyHolder );
final AnnotatedColumn column = bindImplicitColumn( columns.setBuildingContext( context );
inferredData, columns.setJoins( secondaryTables );
suffixForDefaultColumnName, columns.setPropertyHolder( propertyHolder );
secondaryTables,
propertyHolder,
comment,
nullability,
context
);
result.setColumns( new AnnotatedColumn[] { column } );
return result;
}
private static AnnotatedColumn bindImplicitColumn(
PropertyData inferredData,
String suffixForDefaultColumnName,
Map<String, Join> secondaryTables,
PropertyHolder propertyHolder,
Comment comment,
Nullability nullability,
MetadataBuildingContext context) {
final AnnotatedColumn column = new AnnotatedColumn(); final AnnotatedColumn column = new AnnotatedColumn();
if ( comment != null ) { if ( comment != null ) {
column.setComment( comment.value() ); column.setComment( comment.value() );
@ -964,45 +912,45 @@ public class AnnotatedColumn {
final String propertyName = inferredData.getPropertyName(); final String propertyName = inferredData.getPropertyName();
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
column.setJoins( secondaryTables ); // column.setJoins( secondaryTables );
column.setBuildingContext( context ); // column.setBuildingContext( context );
// property name + suffix is an "explicit" column name // property name + suffix is an "explicit" column name
boolean implicit = isEmpty( suffixForDefaultColumnName ); final boolean implicit = isEmpty( suffixForDefaultColumnName );
if ( !implicit ) { if ( !implicit ) {
column.setLogicalColumnName( propertyName + suffixForDefaultColumnName ); column.setLogicalColumnName( propertyName + suffixForDefaultColumnName );
} }
column.setImplicit( implicit ); column.setImplicit( implicit );
column.setParent( columns );
column.applyColumnDefault( inferredData, 1 ); column.applyColumnDefault( inferredData, 1 );
column.applyGeneratedAs( inferredData, 1 ); column.applyGeneratedAs( inferredData, 1 );
column.applyCheckConstraint( inferredData, 1 ); column.applyCheckConstraint( inferredData, 1 );
column.extractDataFromPropertyData( propertyHolder, inferredData ); column.extractDataFromPropertyData( propertyHolder, inferredData );
AnnotatedColumns temp = new AnnotatedColumns();
temp.setPropertyHolder( propertyHolder );
temp.setColumns( new AnnotatedColumn[] { column } );
column.bind(); column.bind();
return column; return columns;
} }
public static void checkPropertyConsistency(AnnotatedColumn[] columns, String propertyName) { public static void checkPropertyConsistency(List<AnnotatedColumn> columns, String propertyName) {
if ( columns.length > 1 ) { if ( columns.size() > 1 ) {
for (int currentIndex = 1; currentIndex < columns.length; currentIndex++) { for ( int currentIndex = 1; currentIndex < columns.size(); currentIndex++ ) {
if ( !columns[currentIndex].isFormula() && !columns[currentIndex - 1].isFormula() ) { final AnnotatedColumn current = columns.get( currentIndex );
if ( columns[currentIndex].isNullable() != columns[currentIndex - 1].isNullable() ) { final AnnotatedColumn previous = columns.get( currentIndex - 1 );
if ( !current.isFormula() && !previous.isFormula() ) {
if ( current.isNullable() != previous.isNullable() ) {
throw new AnnotationException( throw new AnnotationException(
"Column mappings for property '" + propertyName + "' mix nullable with 'not null'" "Column mappings for property '" + propertyName + "' mix nullable with 'not null'"
); );
} }
if ( columns[currentIndex].isInsertable() != columns[currentIndex - 1].isInsertable() ) { if ( current.isInsertable() != previous.isInsertable() ) {
throw new AnnotationException( throw new AnnotationException(
"Column mappings for property '" + propertyName + "' mix insertable with 'insertable=false'" "Column mappings for property '" + propertyName + "' mix insertable with 'insertable=false'"
); );
} }
if ( columns[currentIndex].isUpdatable() != columns[currentIndex - 1].isUpdatable() ) { if ( current.isUpdatable() != previous.isUpdatable() ) {
throw new AnnotationException( throw new AnnotationException(
"Column mappings for property '" + propertyName + "' mix updatable with 'updatable=false'" "Column mappings for property '" + propertyName + "' mix updatable with 'updatable=false'"
); );
} }
if ( !columns[currentIndex].getTable().equals( columns[currentIndex - 1].getTable() ) ) { if ( !current.getExplicitTableName().equals( previous.getExplicitTableName() ) ) {
throw new AnnotationException( throw new AnnotationException(
"Column mappings for property '" + propertyName + "' mix distinct secondary tables" "Column mappings for property '" + propertyName + "' mix distinct secondary tables"
); );
@ -1020,23 +968,23 @@ public class AnnotatedColumn {
void addIndex(String indexName, boolean inSecondPass) { void addIndex(String indexName, boolean inSecondPass) {
final IndexOrUniqueKeySecondPass secondPass = final IndexOrUniqueKeySecondPass secondPass =
new IndexOrUniqueKeySecondPass( indexName, this, context, false ); new IndexOrUniqueKeySecondPass( indexName, this, getBuildingContext(), false );
if ( inSecondPass ) { if ( inSecondPass ) {
secondPass.doSecondPass( context.getMetadataCollector().getEntityBindingMap() ); secondPass.doSecondPass( getBuildingContext().getMetadataCollector().getEntityBindingMap() );
} }
else { else {
context.getMetadataCollector().addSecondPass( secondPass ); getBuildingContext().getMetadataCollector().addSecondPass( secondPass );
} }
} }
void addUniqueKey(String uniqueKeyName, boolean inSecondPass) { void addUniqueKey(String uniqueKeyName, boolean inSecondPass) {
final IndexOrUniqueKeySecondPass secondPass = final IndexOrUniqueKeySecondPass secondPass =
new IndexOrUniqueKeySecondPass( uniqueKeyName, this, context, true ); new IndexOrUniqueKeySecondPass( uniqueKeyName, this, getBuildingContext(), true );
if ( inSecondPass ) { if ( inSecondPass ) {
secondPass.doSecondPass( context.getMetadataCollector().getEntityBindingMap() ); secondPass.doSecondPass( getBuildingContext().getMetadataCollector().getEntityBindingMap() );
} }
else { else {
context.getMetadataCollector().addSecondPass( secondPass ); getBuildingContext().getMetadataCollector().addSecondPass( secondPass );
} }
} }
@ -1056,4 +1004,8 @@ public class AnnotatedColumn {
string.append( ")" ); string.append( ")" );
return string.toString(); return string.toString();
} }
MetadataBuildingContext getBuildingContext() {
return getParent().getBuildingContext();
}
} }

View File

@ -1,7 +1,19 @@
package org.hibernate.cfg; package org.hibernate.cfg;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.Join;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static java.util.Collections.unmodifiableList;
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
/** /**
* A list of columns that are mapped to a single Java property * A list of columns that are mapped to a single Java property
* or field. This is a slightly uncomfortable abstraction here, * or field. This is a slightly uncomfortable abstraction here,
@ -17,21 +29,14 @@ import org.hibernate.mapping.Table;
* @author Gavin King * @author Gavin King
*/ */
public class AnnotatedColumns { public class AnnotatedColumns {
private AnnotatedColumn[] columns; private final List<AnnotatedColumn> columns = new ArrayList<>();
private Table table; private Table table;
private PropertyHolder propertyHolder; private PropertyHolder propertyHolder;
private Map<String, Join> joins = Collections.emptyMap();
private MetadataBuildingContext buildingContext;
public void setColumns(AnnotatedColumn[] columns) { public List<AnnotatedColumn> getColumns() {
this.columns = columns; return unmodifiableList( columns );
if ( columns != null ) {
for ( AnnotatedColumn column : columns ) {
column.setParent( this );
}
}
}
public AnnotatedColumn[] getColumns() {
return columns;
} }
public PropertyHolder getPropertyHolder() { public PropertyHolder getPropertyHolder() {
@ -42,6 +47,49 @@ public class AnnotatedColumns {
this.propertyHolder = propertyHolder; this.propertyHolder = propertyHolder;
} }
public void setBuildingContext(MetadataBuildingContext buildingContext) {
this.buildingContext = buildingContext;
}
public MetadataBuildingContext getBuildingContext() {
return buildingContext;
}
public void setJoins(Map<String, Join> joins) {
this.joins = joins;
}
public Join getJoin() {
final AnnotatedColumn firstColumn = columns.get(0);
final String explicitTableName = firstColumn.getExplicitTableName();
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 );
if ( physicalTableName != null ) {
join = joins.get( physicalTableName );
}
}
if ( join == null ) {
throw new AnnotationException(
"Secondary table '" + explicitTableName + "' for property '" + getPropertyHolder().getClassName()
+ "' is not declared (use '@SecondaryTable' to declare the secondary table)"
);
}
return join;
}
public boolean isSecondary() {
if ( getPropertyHolder() == null ) {
throw new AssertionFailure( "Should not call isSecondary() on column w/o persistent class defined" );
}
final AnnotatedColumn firstColumn = columns.get(0);
final String explicitTableName = firstColumn.getExplicitTableName();
return isNotEmpty( explicitTableName )
&& !getPropertyHolder().getTable().getName().equals( explicitTableName );
}
public Table getTable() { public Table getTable() {
if ( table != null ) { if ( table != null ) {
return table; return table;
@ -50,10 +98,8 @@ public class AnnotatedColumns {
// all the columns have to be mapped to the same table // all the columns have to be mapped to the same table
// even though at the annotation level it looks like // even though at the annotation level it looks like
// they could each specify a different table // they could each specify a different table
final AnnotatedColumn firstColumn = columns[0]; final AnnotatedColumn firstColumn = columns.get(0);
return firstColumn.isSecondary() return firstColumn.isSecondary() ? getJoin().getTable() : getPropertyHolder().getTable();
? firstColumn.getJoin().getTable()
: firstColumn.getPropertyHolder().getTable();
} }
} }
@ -65,4 +111,8 @@ public class AnnotatedColumns {
void setTableInternal(Table table) { void setTableInternal(Table table) {
this.table = table; this.table = table;
} }
public void addColumn(AnnotatedColumn child) {
columns.add( child );
}
} }

View File

@ -49,9 +49,11 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn {
DiscriminatorColumn discriminatorColumn, DiscriminatorColumn discriminatorColumn,
DiscriminatorFormula discriminatorFormula, DiscriminatorFormula discriminatorFormula,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedColumns parent = new AnnotatedColumns();
parent.setBuildingContext( context );
final AnnotatedDiscriminatorColumn column = new AnnotatedDiscriminatorColumn(); final AnnotatedDiscriminatorColumn column = new AnnotatedDiscriminatorColumn();
column.setBuildingContext( context ); // column.setContext( context );
if ( discriminatorFormula != null ) { if ( discriminatorFormula != null ) {
column.setImplicit( false ); column.setImplicit( false );
column.setFormula( discriminatorFormula.value() ); column.setFormula( discriminatorFormula.value() );
} }
@ -69,31 +71,32 @@ public class AnnotatedDiscriminatorColumn extends AnnotatedColumn {
column.setImplicit( true ); column.setImplicit( true );
} }
setDiscriminatorType( type, discriminatorColumn, column ); setDiscriminatorType( type, discriminatorColumn, column );
column.setParent( parent );
column.bind(); column.bind();
return column; return column;
} }
private static void setDiscriminatorType( private static void setDiscriminatorType(
DiscriminatorType type, DiscriminatorType type,
DiscriminatorColumn discAnn, DiscriminatorColumn discriminatorColumn,
AnnotatedDiscriminatorColumn discriminatorColumn) { AnnotatedDiscriminatorColumn column) {
if ( type == null ) { if ( type == null ) {
discriminatorColumn.setDiscriminatorTypeName( "string" ); column.setDiscriminatorTypeName( "string" );
} }
else { else {
switch ( type ) { switch ( type ) {
case CHAR: case CHAR:
discriminatorColumn.setDiscriminatorTypeName( "character" ); column.setDiscriminatorTypeName( "character" );
discriminatorColumn.setImplicit( false ); column.setImplicit( false );
break; break;
case INTEGER: case INTEGER:
discriminatorColumn.setDiscriminatorTypeName( "integer" ); column.setDiscriminatorTypeName( "integer" );
discriminatorColumn.setImplicit( false ); column.setImplicit( false );
break; break;
case STRING: case STRING:
discriminatorColumn.setDiscriminatorTypeName( "string" ); column.setDiscriminatorTypeName( "string" );
if ( discAnn != null ) { if ( discriminatorColumn != null ) {
discriminatorColumn.setLength( (long) discAnn.length() ); column.setLength( (long) discriminatorColumn.length() );
} }
break; break;
default: default:

View File

@ -7,7 +7,6 @@
package org.hibernate.cfg; package org.hibernate.cfg;
import java.util.List; import java.util.List;
import java.util.Map;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import jakarta.persistence.PrimaryKeyJoinColumn; import jakarta.persistence.PrimaryKeyJoinColumn;
@ -54,7 +53,6 @@ import static org.hibernate.internal.util.StringHelper.unquote;
public class AnnotatedJoinColumn extends AnnotatedColumn { public class AnnotatedJoinColumn extends AnnotatedColumn {
private String referencedColumn; private String referencedColumn;
private AnnotatedJoinColumns parent;
// due to @AnnotationOverride overriding rules, // due to @AnnotationOverride overriding rules,
// we don't want the constructor to be public // we don't want the constructor to be public
@ -82,42 +80,32 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
static AnnotatedJoinColumn buildJoinColumn( static AnnotatedJoinColumn buildJoinColumn(
JoinColumn joinColumn, JoinColumn joinColumn,
String mappedBy, String mappedBy,
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName) {
MetadataBuildingContext buildingContext) {
final String path = qualify( propertyHolder.getPath(), propertyName ); final String path = qualify( propertyHolder.getPath(), propertyName );
final JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( path ); final JoinColumn[] overrides = propertyHolder.getOverriddenJoinColumn( path );
if ( overriddes != null ) { if ( overrides != null ) {
//TODO: relax this restriction //TODO: relax this restriction
throw new AnnotationException("Property '" + path throw new AnnotationException("Property '" + path
+ "' overrides mapping specified using '@JoinColumnOrFormula'"); + "' overrides mapping specified using '@JoinColumnOrFormula'");
} }
return buildJoinColumn( return buildJoinColumn( joinColumn, null, mappedBy, parent, propertyHolder, propertyName, "" );
joinColumn,
null,
mappedBy,
joins,
propertyHolder,
propertyName,
"",
buildingContext
);
} }
public static AnnotatedJoinColumn buildJoinFormula( public static AnnotatedJoinColumn buildJoinFormula(
JoinFormula joinFormula, JoinFormula joinFormula,
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName) {
MetadataBuildingContext buildingContext) {
final AnnotatedJoinColumn formulaColumn = new AnnotatedJoinColumn(); final AnnotatedJoinColumn formulaColumn = new AnnotatedJoinColumn();
formulaColumn.setFormula( joinFormula.value() ); formulaColumn.setFormula( joinFormula.value() );
formulaColumn.setReferencedColumn( joinFormula.referencedColumnName() ); formulaColumn.setReferencedColumn( joinFormula.referencedColumnName() );
formulaColumn.setBuildingContext( buildingContext ); // formulaColumn.setContext( buildingContext );
// formulaColumn.setPropertyHolder( propertyHolder ); // formulaColumn.setPropertyHolder( propertyHolder );
formulaColumn.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); formulaColumn.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
formulaColumn.setJoins( joins ); // formulaColumn.setJoins( joins );
formulaColumn.setParent( parent );
formulaColumn.bind(); formulaColumn.bind();
return formulaColumn; return formulaColumn;
} }
@ -126,11 +114,10 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
JoinColumn joinColumn, JoinColumn joinColumn,
Comment comment, Comment comment,
String mappedBy, String mappedBy,
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
String defaultColumnSuffix, String defaultColumnSuffix) {
MetadataBuildingContext context) {
if ( joinColumn != null ) { if ( joinColumn != null ) {
if ( !isEmptyOrNullAnnotationValue( mappedBy ) ) { if ( !isEmptyOrNullAnnotationValue( mappedBy ) ) {
throw new AnnotationException( throw new AnnotationException(
@ -138,44 +125,44 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
+ "' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'" + "' is 'mappedBy' a different entity and may not explicitly specify the '@JoinColumn'"
); );
} }
return explicitJoinColumn( joinColumn, comment, joins, propertyHolder, propertyName, defaultColumnSuffix, context ); return explicitJoinColumn( joinColumn, comment, parent, propertyHolder, propertyName, defaultColumnSuffix );
} }
else { else {
return implicitJoinColumn( joins, propertyHolder, propertyName, defaultColumnSuffix, context ); return implicitJoinColumn( parent, propertyHolder, propertyName, defaultColumnSuffix );
} }
} }
private static AnnotatedJoinColumn explicitJoinColumn( private static AnnotatedJoinColumn explicitJoinColumn(
JoinColumn joinColumn, JoinColumn joinColumn,
Comment comment, Comment comment,
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
String defaultColumnSuffix, String defaultColumnSuffix) {
MetadataBuildingContext context) {
final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
column.setComment( comment != null ? comment.value() : null ); column.setComment( comment != null ? comment.value() : null );
column.setBuildingContext( context ); // column.setContext( context );
column.setJoinAnnotation(joinColumn, null ); // column.setJoins( joins );
// column.setPropertyHolder( propertyHolder );
if ( isEmpty( column.getLogicalColumnName() ) && isNotEmpty( defaultColumnSuffix ) ) { if ( isEmpty( column.getLogicalColumnName() ) && isNotEmpty( defaultColumnSuffix ) ) {
column.setLogicalColumnName( propertyName + defaultColumnSuffix ); column.setLogicalColumnName( propertyName + defaultColumnSuffix );
} }
column.setJoins( joins );
// column.setPropertyHolder( propertyHolder );
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
column.setImplicit( false ); column.setImplicit( false );
column.setParent( parent );
column.applyJoinAnnotation( joinColumn, null );
column.bind(); column.bind();
return column; return column;
} }
private static AnnotatedJoinColumn implicitJoinColumn( private static AnnotatedJoinColumn implicitJoinColumn(
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
String defaultColumnSuffix, String defaultColumnSuffix) {
MetadataBuildingContext context) {
final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
column.setJoins( joins ); // column.setContext( context );
// column.setJoins( joins );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
// property name + suffix is an "explicit" column name // property name + suffix is an "explicit" column name
@ -186,14 +173,14 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
else { else {
column.setImplicit( true ); column.setImplicit( true );
} }
column.setBuildingContext( context ); column.setParent( parent );
column.bind(); column.bind();
return column; return column;
} }
// TODO default name still useful in association table // TODO default name still useful in association table
public void setJoinAnnotation(JoinColumn joinColumn, String defaultName) { public void applyJoinAnnotation(JoinColumn joinColumn, String defaultName) {
if ( joinColumn == null ) { if ( joinColumn == null ) {
setImplicit( true ); setImplicit( true );
} }
@ -233,21 +220,19 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
PrimaryKeyJoinColumn primaryKeyJoinColumn, PrimaryKeyJoinColumn primaryKeyJoinColumn,
JoinColumn joinColumn, JoinColumn joinColumn,
Value identifier, Value identifier,
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final String defaultColumnName = context.getMetadataCollector() final String defaultColumnName = context.getMetadataCollector()
.getLogicalColumnName( identifier.getTable(), identifier.getColumns().get(0).getQuotedName() ); .getLogicalColumnName( identifier.getTable(), identifier.getColumns().get(0).getQuotedName() );
return primaryKeyJoinColumn != null || joinColumn != null return primaryKeyJoinColumn != null || joinColumn != null
? explicitJoinColumn( primaryKeyJoinColumn, joinColumn, joins, propertyHolder, context, defaultColumnName ) ? explicitJoinColumn( primaryKeyJoinColumn, joinColumn, parent, context, defaultColumnName )
: implicitJoinColumn( joins, propertyHolder, context, defaultColumnName ); : implicitJoinColumn( parent, context, defaultColumnName );
} }
private static AnnotatedJoinColumn explicitJoinColumn( private static AnnotatedJoinColumn explicitJoinColumn(
PrimaryKeyJoinColumn primaryKeyJoinColumn, PrimaryKeyJoinColumn primaryKeyJoinColumn,
JoinColumn joinColumn, JoinColumn joinColumn,
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder,
MetadataBuildingContext context, MetadataBuildingContext context,
String defaultColumnName) { String defaultColumnName) {
final String columnName; final String columnName;
@ -267,34 +252,35 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
final String columnDef = columnDefinition.isEmpty() ? null final String columnDef = columnDefinition.isEmpty() ? null
: normalizer.toDatabaseIdentifierText( columnDefinition ); : normalizer.toDatabaseIdentifierText( columnDefinition );
final String logicalColumnName = columnName != null && columnName.isEmpty() final String logicalColumnName = columnName != null && columnName.isEmpty()
? normalizer.normalizeIdentifierQuotingAsString(defaultColumnName) ? normalizer.normalizeIdentifierQuotingAsString( defaultColumnName )
: normalizer.normalizeIdentifierQuotingAsString( columnName ); : normalizer.normalizeIdentifierQuotingAsString( columnName );
final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
column.setSqlType( columnDef ); column.setSqlType( columnDef );
column.setLogicalColumnName( logicalColumnName ); column.setLogicalColumnName( logicalColumnName );
column.setReferencedColumn( referencedColumnName ); column.setReferencedColumn( referencedColumnName );
// column.setPropertyHolder(propertyHolder); // column.setPropertyHolder(propertyHolder);
column.setJoins(joins); // column.setJoins(joins);
column.setBuildingContext(context); // column.setContext( context );
column.setImplicit( false ); column.setImplicit( false );
column.setNullable( false ); column.setNullable( false );
column.setParent( parent );
column.bind(); column.bind();
return column; return column;
} }
private static AnnotatedJoinColumn implicitJoinColumn( private static AnnotatedJoinColumn implicitJoinColumn(
Map<String, Join> joins, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder,
MetadataBuildingContext context, MetadataBuildingContext context,
String defaultColumnName ) { String defaultColumnName ) {
final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer(); final ObjectNameNormalizer normalizer = context.getObjectNameNormalizer();
column.setLogicalColumnName( normalizer.normalizeIdentifierQuotingAsString(defaultColumnName) ); column.setLogicalColumnName( normalizer.normalizeIdentifierQuotingAsString( defaultColumnName ) );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
column.setJoins(joins); // column.setJoins(joins);
column.setBuildingContext(context); // column.setContext( context );
column.setImplicit( true ); column.setImplicit( true );
column.setNullable( false ); column.setNullable( false );
column.setParent( parent );
column.bind(); column.bind();
return column; return column;
} }
@ -328,7 +314,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
SimpleValue value) { SimpleValue value) {
final String logicalReferencedColumn = getBuildingContext().getMetadataCollector() final String logicalReferencedColumn = getBuildingContext().getMetadataCollector()
.getLogicalColumnName( referencedEntity.getTable(), referencedColumn.getQuotedName() ); .getLogicalColumnName( referencedEntity.getTable(), referencedColumn.getQuotedName() );
final String columnName = parent.buildDefaultColumnName( referencedEntity, logicalReferencedColumn ); final String columnName = getParent().buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
//yuk side effect on an implicit column //yuk side effect on an implicit column
setLogicalColumnName( columnName ); setLogicalColumnName( columnName );
setReferencedColumn( logicalReferencedColumn ); setReferencedColumn( logicalReferencedColumn );
@ -347,7 +333,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
} }
public void addDefaultJoinColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) { public void addDefaultJoinColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) {
final String columnName = parent.buildDefaultColumnName( referencedEntity, logicalReferencedColumn ); final String columnName = getParent().buildDefaultColumnName( referencedEntity, logicalReferencedColumn );
getMappingColumn().setName( columnName ); getMappingColumn().setName( columnName );
setLogicalColumnName( columnName ); setLogicalColumnName( columnName );
} }
@ -373,7 +359,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
@Override @Override
protected void addColumnBinding(SimpleValue value) { protected void addColumnBinding(SimpleValue value) {
if ( isEmpty( parent.getMappedBy() ) ) { if ( isEmpty( getParent().getMappedBy() ) ) {
// was the column explicitly quoted in the mapping/annotation // was the column explicitly quoted in the mapping/annotation
// TODO: in metamodel, we need to better split global quoting and explicit quoting w/ respect to logical names // TODO: in metamodel, we need to better split global quoting and explicit quoting w/ respect to logical names
boolean isLogicalColumnQuoted = isQuoted( getLogicalColumnName() ); boolean isLogicalColumnQuoted = isQuoted( getLogicalColumnName() );
@ -407,12 +393,12 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
AnnotatedJoinColumns joinColumns, AnnotatedJoinColumns joinColumns,
PersistentClass referencedEntity, PersistentClass referencedEntity,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedJoinColumn[] columns = joinColumns.getColumns(); final List<AnnotatedJoinColumn> columns = joinColumns.getJoinColumns();
if ( columns.length == 0 ) { if ( columns.size() == 0 ) {
return NO_REFERENCE; //shortcut return NO_REFERENCE; //shortcut
} }
final AnnotatedJoinColumn firstColumn = columns[0]; final AnnotatedJoinColumn firstColumn = columns.get(0);
final Object columnOwner = findReferencedColumnOwner( referencedEntity, firstColumn, context ); final Object columnOwner = findReferencedColumnOwner( referencedEntity, firstColumn, context );
if ( columnOwner == null ) { if ( columnOwner == null ) {
try { try {
@ -441,7 +427,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
} }
if ( explicitColumnReference ) { if ( explicitColumnReference ) {
// if we got to here, all the columns belong to the PK // if we got to here, all the columns belong to the PK
return keyColumns.size() == columns.length return keyColumns.size() == columns.size()
// we have all the PK columns // we have all the PK columns
? PK_REFERENCE ? PK_REFERENCE
// we have a subset of the PK columns // we have a subset of the PK columns
@ -497,36 +483,36 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
} }
static AnnotatedJoinColumn buildImplicitJoinTableJoinColumn( static AnnotatedJoinColumn buildImplicitJoinTableJoinColumn(
Map<String, Join> secondaryTables, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName) {
MetadataBuildingContext context) {
final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
column.setImplicit( true ); column.setImplicit( true );
column.setNullable( false ); //I break the spec, but it's for good column.setNullable( false ); //I break the spec, but it's for good
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
column.setJoins( secondaryTables ); // column.setJoins( secondaryTables );
column.setBuildingContext( context ); // column.setContext( context );
column.setParent( parent );
column.bind(); column.bind();
return column; return column;
} }
static AnnotatedJoinColumn buildExplicitJoinTableJoinColumn( static AnnotatedJoinColumn buildExplicitJoinTableJoinColumn(
Map<String, Join> secondaryTables, AnnotatedJoinColumns parent,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
MetadataBuildingContext context,
JoinColumn joinColumn) { JoinColumn joinColumn) {
final AnnotatedJoinColumn column = new AnnotatedJoinColumn(); final AnnotatedJoinColumn column = new AnnotatedJoinColumn();
column.setImplicit( true ); column.setImplicit( true );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
column.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); column.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
column.setJoins( secondaryTables ); // column.setJoins( secondaryTables );
column.setBuildingContext( context ); // column.setContext( context );
column.setJoinAnnotation( joinColumn, propertyName );
column.setNullable( false ); //I break the spec, but it's for good column.setNullable( false ); //I break the spec, but it's for good
//done after the annotation to override it //done after the annotation to override it
column.setParent( parent );
column.applyJoinAnnotation( joinColumn, propertyName );
column.bind(); column.bind();
return column; return column;
} }
@ -548,8 +534,20 @@ public class AnnotatedJoinColumn extends AnnotatedColumn {
return string.toString(); return string.toString();
} }
@Override
public AnnotatedJoinColumns getParent() {
return (AnnotatedJoinColumns) super.getParent();
}
@Override
public void setParent(AnnotatedColumns parent) {
if ( !(parent instanceof AnnotatedJoinColumns) ) {
throw new UnsupportedOperationException("wrong kind of parent");
}
super.setParent( parent );
}
public void setParent(AnnotatedJoinColumns parent) { public void setParent(AnnotatedJoinColumns parent) {
super.setParent( parent ); super.setParent( parent );
this.parent = parent;
} }
} }

View File

@ -2,6 +2,7 @@ package org.hibernate.cfg;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.Comment; import org.hibernate.annotations.Comment;
import org.hibernate.annotations.JoinColumnOrFormula; import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinFormula; import org.hibernate.annotations.JoinFormula;
@ -25,6 +26,8 @@ import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SimpleValue;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -47,9 +50,8 @@ import static org.hibernate.internal.util.StringHelper.qualify;
*/ */
public class AnnotatedJoinColumns extends AnnotatedColumns { public class AnnotatedJoinColumns extends AnnotatedColumns {
private AnnotatedJoinColumn[] columns; private final List<AnnotatedJoinColumn> columns = new ArrayList<>();
private String propertyName; // this is really a .-separated property path private String propertyName; // this is really a .-separated property path
private MetadataBuildingContext buildingContext;
//TODO: do we really need to hang so many strings off this class? //TODO: do we really need to hang so many strings off this class?
private String mappedBy; private String mappedBy;
@ -66,22 +68,23 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedJoinColumn[] columns = new AnnotatedJoinColumn[joinColumnOrFormulas.length]; final AnnotatedJoinColumns parent = new AnnotatedJoinColumns();
for ( int i = 0; i < joinColumnOrFormulas.length; i++ ) { parent.setBuildingContext( context );
final JoinColumnOrFormula columnOrFormula = joinColumnOrFormulas[i]; parent.setJoins( joins );
parent.setPropertyHolder( propertyHolder );
parent.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
parent.setMappedBy( mappedBy );
for ( JoinColumnOrFormula columnOrFormula : joinColumnOrFormulas ) {
final JoinFormula formula = columnOrFormula.formula(); final JoinFormula formula = columnOrFormula.formula();
final JoinColumn column = columnOrFormula.column(); final JoinColumn column = columnOrFormula.column();
columns[i] = formula.value() != null && !formula.value().isEmpty() if ( !isEmptyOrNullAnnotationValue( formula.value() ) ) {
? AnnotatedJoinColumn.buildJoinFormula( formula, joins, propertyHolder, propertyName, context ) AnnotatedJoinColumn.buildJoinFormula( formula, parent, propertyHolder, propertyName );
: AnnotatedJoinColumn.buildJoinColumn( column, mappedBy, joins, propertyHolder, propertyName, context ); }
else {
AnnotatedJoinColumn.buildJoinColumn( column, mappedBy, parent, propertyHolder, propertyName );
}
} }
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); return parent;
joinColumns.setBuildingContext( context );
joinColumns.setPropertyHolder( propertyHolder );
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
joinColumns.setColumns( columns );
joinColumns.setMappedBy( mappedBy );
return joinColumns;
} }
public static AnnotatedJoinColumns buildJoinColumns( public static AnnotatedJoinColumns buildJoinColumns(
@ -116,47 +119,38 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
final String path = qualify( propertyHolder.getPath(), propertyName ); final String path = qualify( propertyHolder.getPath(), propertyName );
final JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( path ); final JoinColumn[] overriddes = propertyHolder.getOverriddenJoinColumn( path );
final JoinColumn[] actualColumns = overriddes == null ? joinColumns : overriddes; final JoinColumn[] actualColumns = overriddes == null ? joinColumns : overriddes;
final AnnotatedJoinColumns parent = new AnnotatedJoinColumns();
parent.setBuildingContext( context );
parent.setJoins( joins );
parent.setPropertyHolder( propertyHolder );
parent.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
parent.setMappedBy( mappedBy );
if ( actualColumns == null || actualColumns.length == 0 ) { if ( actualColumns == null || actualColumns.length == 0 ) {
final AnnotatedJoinColumn joinColumn = AnnotatedJoinColumn.buildJoinColumn( AnnotatedJoinColumn.buildJoinColumn(
null, null,
comment, comment,
mappedBy, mappedBy,
joins, parent,
propertyHolder, propertyHolder,
propertyName, propertyName,
defaultColumnSuffix, defaultColumnSuffix
context
); );
final AnnotatedJoinColumns annotatedJoinColumns = new AnnotatedJoinColumns();
annotatedJoinColumns.setBuildingContext( context );
annotatedJoinColumns.setPropertyHolder( propertyHolder );
annotatedJoinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
annotatedJoinColumns.setColumns( new AnnotatedJoinColumn[] { joinColumn } );
annotatedJoinColumns.setMappedBy( mappedBy );
return annotatedJoinColumns;
} }
else { else {
final AnnotatedJoinColumn[] result = new AnnotatedJoinColumn[actualColumns.length]; parent.setMappedBy( mappedBy );
for ( int index = 0; index < actualColumns.length; index++ ) { for ( JoinColumn actualColumn : actualColumns ) {
result[index] = AnnotatedJoinColumn.buildJoinColumn( AnnotatedJoinColumn.buildJoinColumn(
actualColumns[index], actualColumn,
comment, comment,
mappedBy, mappedBy,
joins, parent,
propertyHolder, propertyHolder,
propertyName, propertyName,
defaultColumnSuffix, defaultColumnSuffix
context
); );
} }
final AnnotatedJoinColumns annotatedJoinColumns = new AnnotatedJoinColumns();
annotatedJoinColumns.setBuildingContext( context );
annotatedJoinColumns.setPropertyHolder( propertyHolder );
annotatedJoinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
annotatedJoinColumns.setColumns( result );
annotatedJoinColumns.setMappedBy( mappedBy );
return annotatedJoinColumns;
} }
return parent;
} }
public static AnnotatedJoinColumns buildJoinTableJoinColumns( public static AnnotatedJoinColumns buildJoinTableJoinColumns(
@ -166,56 +160,39 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
String propertyName, String propertyName,
String mappedBy, String mappedBy,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedJoinColumn[] columns; final AnnotatedJoinColumns parent = new AnnotatedJoinColumns();
parent.setBuildingContext( context );
parent.setJoins( secondaryTables );
parent.setPropertyHolder( propertyHolder );
parent.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
parent.setMappedBy( mappedBy );
if ( joinColumns == null ) { if ( joinColumns == null ) {
columns = new AnnotatedJoinColumn[] { AnnotatedJoinColumn.buildImplicitJoinTableJoinColumn( AnnotatedJoinColumn.buildImplicitJoinTableJoinColumn( parent, propertyHolder, propertyName );
secondaryTables,
propertyHolder,
propertyName,
context
) };
} }
else { else {
columns = new AnnotatedJoinColumn[joinColumns.length]; for ( JoinColumn joinColumn : joinColumns ) {
int length = joinColumns.length; AnnotatedJoinColumn.buildExplicitJoinTableJoinColumn( parent, propertyHolder, propertyName, joinColumn );
for (int index = 0; index < length; index++) {
columns[index] = AnnotatedJoinColumn.buildExplicitJoinTableJoinColumn(
secondaryTables,
propertyHolder,
propertyName,
context,
joinColumns[index]
);
} }
} }
final AnnotatedJoinColumns annotatedJoinColumns = new AnnotatedJoinColumns(); return parent;
annotatedJoinColumns.setBuildingContext( context );
annotatedJoinColumns.setPropertyHolder( propertyHolder );
annotatedJoinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
annotatedJoinColumns.setColumns( columns );
annotatedJoinColumns.setMappedBy( mappedBy );
return annotatedJoinColumns;
} }
public AnnotatedJoinColumn[] getColumns() { public List<AnnotatedJoinColumn> getJoinColumns() {
return columns; return columns;
} }
@Override @Override
public void setColumns(AnnotatedColumn[] columns) { public void addColumn(AnnotatedColumn child) {
throw new UnsupportedOperationException( "wrong sort of columns" ); if ( !(child instanceof AnnotatedJoinColumn) ) {
} throw new AssertionFailure( "wrong sort of column" );
public void setColumns(AnnotatedJoinColumn[] columns) {
super.setColumns( columns );
this.columns = columns;
if ( columns != null ) {
for ( AnnotatedJoinColumn column : columns ) {
column.setParent( this );
}
} }
addColumn( (AnnotatedJoinColumn) child );
} }
public void addColumn(AnnotatedJoinColumn child) {
super.addColumn( child );
columns.add( child );
}
public String getMappedBy() { public String getMappedBy() {
return mappedBy; return mappedBy;
} }
@ -258,7 +235,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
final PropertyHolder propertyHolder = buildPropertyHolder( final PropertyHolder propertyHolder = buildPropertyHolder(
persistentClass, persistentClass,
joins, joins,
buildingContext, getBuildingContext(),
inheritanceStatePerClass inheritanceStatePerClass
); );
setPropertyHolder( propertyHolder ); setPropertyHolder( propertyHolder );
@ -267,10 +244,6 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
// } // }
} }
public void setBuildingContext(MetadataBuildingContext buildingContext) {
this.buildingContext = buildingContext;
}
public boolean isElementCollection() { public boolean isElementCollection() {
return elementCollection; return elementCollection;
} }
@ -294,7 +267,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
} }
String buildDefaultColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) { String buildDefaultColumnName(PersistentClass referencedEntity, String logicalReferencedColumn) {
final MetadataBuildingOptions options = buildingContext.getBuildingOptions(); final MetadataBuildingOptions options = getBuildingContext().getBuildingOptions();
final ImplicitNamingStrategy implicitNamingStrategy = options.getImplicitNamingStrategy(); final ImplicitNamingStrategy implicitNamingStrategy = options.getImplicitNamingStrategy();
final PhysicalNamingStrategy physicalNamingStrategy = options.getPhysicalNamingStrategy(); final PhysicalNamingStrategy physicalNamingStrategy = options.getPhysicalNamingStrategy();
@ -302,7 +275,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
boolean ownerSide = getPropertyName() != null; boolean ownerSide = getPropertyName() != null;
boolean isRefColumnQuoted = isQuoted( logicalReferencedColumn ); boolean isRefColumnQuoted = isQuoted( logicalReferencedColumn );
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector(); final InFlightMetadataCollector collector = getBuildingContext().getMetadataCollector();
final Database database = collector.getDatabase(); final Database database = collector.getDatabase();
Identifier columnIdentifier; Identifier columnIdentifier;
@ -350,7 +323,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
new ImplicitPrimaryKeyJoinColumnNameSource() { new ImplicitPrimaryKeyJoinColumnNameSource() {
@Override @Override
public MetadataBuildingContext getBuildingContext() { public MetadataBuildingContext getBuildingContext() {
return buildingContext; return AnnotatedJoinColumns.this.getBuildingContext();
} }
@Override @Override
@ -407,7 +380,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
private final Identifier referencedTableName; private final Identifier referencedTableName;
private final String logicalReferencedColumn; private final String logicalReferencedColumn;
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector(); final InFlightMetadataCollector collector = getBuildingContext().getMetadataCollector();
final Database database = collector.getDatabase(); final Database database = collector.getDatabase();
public UnownedImplicitJoinColumnNameSource(PersistentClass referencedEntity, String logicalReferencedColumn) { public UnownedImplicitJoinColumnNameSource(PersistentClass referencedEntity, String logicalReferencedColumn) {
@ -505,7 +478,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
@Override @Override
public MetadataBuildingContext getBuildingContext() { public MetadataBuildingContext getBuildingContext() {
return buildingContext; return AnnotatedJoinColumns.this.getBuildingContext();
} }
} }
@ -518,7 +491,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
private final Identifier referencedTableName; private final Identifier referencedTableName;
private final Identifier referencedColumnName; private final Identifier referencedColumnName;
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector(); final InFlightMetadataCollector collector = getBuildingContext().getMetadataCollector();
final Database database = collector.getDatabase(); final Database database = collector.getDatabase();
public OwnedImplicitJoinColumnNameSource(PersistentClass referencedEntity, String logicalTableName, String logicalReferencedColumn) { public OwnedImplicitJoinColumnNameSource(PersistentClass referencedEntity, String logicalTableName, String logicalReferencedColumn) {
@ -571,7 +544,7 @@ public class AnnotatedJoinColumns extends AnnotatedColumns {
@Override @Override
public MetadataBuildingContext getBuildingContext() { public MetadataBuildingContext getBuildingContext() {
return buildingContext; return AnnotatedJoinColumns.this.getBuildingContext();
} }
} }
} }

View File

@ -1510,16 +1510,23 @@ public final class AnnotationBinder {
if ( isOverridden ) { if ( isOverridden ) {
// careful: not always a @MapsId property, sometimes it's from an @IdClass // careful: not always a @MapsId property, sometimes it's from an @IdClass
final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId( final PropertyData mapsIdProperty = getPropertyOverriddenByMapperOrMapsId(
propertyBinder.isId(), propertyHolder, property.getName(), context propertyBinder.isId(),
propertyHolder,
property.getName(),
context
); );
referencedEntityName = mapsIdProperty.getClassOrElementName(); referencedEntityName = mapsIdProperty.getClassOrElementName();
propertyName = mapsIdProperty.getPropertyName(); propertyName = mapsIdProperty.getPropertyName();
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); final AnnotatedJoinColumns parent = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( context ); parent.setBuildingContext( context );
joinColumns.setPropertyHolder( propertyHolder ); parent.setPropertyHolder( propertyHolder );
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) ); parent.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns.getColumns() ); //TODO: resetting the parent here looks like a dangerous thing to do
actualColumns = joinColumns; // should we be cloning them first (the legacy code did not)
for ( AnnotatedColumn column : columns.getColumns() ) {
column.setParent( parent );
}
actualColumns = parent;
} }
else { else {
referencedEntityName = null; referencedEntityName = null;
@ -1579,7 +1586,7 @@ public final class AnnotationBinder {
final JoinTable assocTable = propertyHolder.getJoinTable(property); final JoinTable assocTable = propertyHolder.getJoinTable(property);
if ( assocTable != null ) { if ( assocTable != null ) {
Join join = propertyHolder.addJoin( assocTable, false ); Join join = propertyHolder.addJoin( assocTable, false );
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn joinColumn : joinColumns.getJoinColumns() ) {
joinColumn.setExplicitTableName( join.getTable().getName() ); joinColumn.setExplicitTableName( join.getTable().getName() );
} }
} }
@ -2247,7 +2254,7 @@ public final class AnnotationBinder {
binder.setUpdatable( false ); binder.setUpdatable( false );
} }
else { else {
final AnnotatedJoinColumn firstColumn = columns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = columns.getJoinColumns().get(0);
binder.setInsertable( firstColumn.isInsertable() ); binder.setInsertable( firstColumn.isInsertable() );
binder.setUpdatable( firstColumn.isUpdatable() ); binder.setUpdatable( firstColumn.isUpdatable() );
} }

View File

@ -172,18 +172,16 @@ public class BinderHelper {
// true when we do the reverse side of a @ManyToMany // true when we do the reverse side of a @ManyToMany
boolean inverse, boolean inverse,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final AnnotatedJoinColumn[] columns = joinColumns.getColumns();
// this work is not necessary for a primary key reference // this work is not necessary for a primary key reference
if ( checkReferencedColumnsType( joinColumns, targetEntity, context ) == NON_PK_REFERENCE ) { // && !firstColumn.isImplicit() if ( checkReferencedColumnsType( joinColumns, targetEntity, context ) == NON_PK_REFERENCE ) { // && !firstColumn.isImplicit()
// all the columns have to belong to the same table; // all the columns have to belong to the same table;
// figure out which table has the columns by looking // figure out which table has the columns by looking
// for a PersistentClass or Join in the hierarchy of // for a PersistentClass or Join in the hierarchy of
// the target entity which has the first column // the target entity which has the first column
final Object columnOwner = findReferencedColumnOwner( targetEntity, columns[0], context ); final Object columnOwner = findReferencedColumnOwner( targetEntity, joinColumns.getJoinColumns().get(0), context );
checkColumnInSameTable( joinColumns, targetEntity, associatedEntity, context, columnOwner ); checkColumnInSameTable( joinColumns, targetEntity, associatedEntity, context, columnOwner );
// find all properties mapped to each column // find all properties mapped to each column
final List<Property> properties = findPropertiesByColumns( columnOwner, columns, associatedEntity, context ); final List<Property> properties = findPropertiesByColumns( columnOwner, joinColumns, associatedEntity, context );
// create a Property along with the new synthetic // create a Property along with the new synthetic
// Component if necessary (or reuse the existing // Component if necessary (or reuse the existing
// Property that matches exactly) // Property that matches exactly)
@ -224,19 +222,19 @@ public class BinderHelper {
// we should only get called for owning side of association // we should only get called for owning side of association
throw new AssertionFailure("no need to create synthetic properties for unowned collections"); throw new AssertionFailure("no need to create synthetic properties for unowned collections");
} }
for ( AnnotatedJoinColumn column: joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column: joinColumns.getJoinColumns() ) {
final Object owner = findReferencedColumnOwner( targetEntity, column, context ); final Object owner = findReferencedColumnOwner( targetEntity, column, context );
if ( owner == null ) { if ( owner == null ) {
throw new AnnotationException( "A '@JoinColumn' for association " throw new AnnotationException( "A '@JoinColumn' for association "
+ associationMessage( associatedEntity, column ) + associationMessage( associatedEntity, joinColumns )
+ " references a column named '" + column.getReferencedColumn() + " references a column named '" + column.getReferencedColumn()
+ "' which is not mapped by the target entity '" + "' which is not mapped by the target entity '"
+ targetEntity.getEntityName() + "'" ); + targetEntity.getEntityName() + "'" );
} }
if ( owner != columnOwner) { if ( owner != columnOwner) {
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
throw new AnnotationException( "The '@JoinColumn's for association " throw new AnnotationException( "The '@JoinColumn's for association "
+ associationMessage( associatedEntity, column ) + associationMessage( associatedEntity, joinColumns )
+ " reference columns of different tables mapped by the target entity '" + " reference columns of different tables mapped by the target entity '"
+ targetEntity.getEntityName() + "' ('" + column.getReferencedColumn() + + targetEntity.getEntityName() + "' ('" + column.getReferencedColumn() +
"' belongs to a different table to '" + firstColumn.getReferencedColumn() + "'" ); "' belongs to a different table to '" + firstColumn.getReferencedColumn() + "'" );
@ -334,21 +332,21 @@ public class BinderHelper {
return syntheticPropertyName; return syntheticPropertyName;
} }
private static String associationMessage(PersistentClass associatedEntity, AnnotatedJoinColumn firstColumn) { private static String associationMessage(PersistentClass associatedEntity, AnnotatedJoinColumns joinColumns) {
StringBuilder message = new StringBuilder(); StringBuilder message = new StringBuilder();
if ( associatedEntity != null ) { if ( associatedEntity != null ) {
message.append( "'" ) message.append( "'" )
.append( associatedEntity.getEntityName() ) .append( associatedEntity.getEntityName() )
.append( "." ) .append( "." )
.append( firstColumn.getPropertyName() ) .append( joinColumns.getPropertyName() )
.append( "'" ); .append( "'" );
} }
else { else {
if ( firstColumn.getPropertyHolder() != null ) { if ( joinColumns.getPropertyHolder() != null ) {
message.append( "'" ) message.append( "'" )
.append( firstColumn.getPropertyHolder().getEntityName() ) .append( joinColumns.getPropertyHolder().getEntityName() )
.append( "." ) .append( "." )
.append( firstColumn.getPropertyName() ) .append( joinColumns.getPropertyName() )
.append( "'" ); .append( "'" );
} }
} }
@ -415,7 +413,7 @@ public class BinderHelper {
private static List<Property> findPropertiesByColumns( private static List<Property> findPropertiesByColumns(
Object columnOwner, Object columnOwner,
AnnotatedJoinColumn[] columns, AnnotatedJoinColumns columns,
PersistentClass associatedEntity, PersistentClass associatedEntity,
MetadataBuildingContext context) { MetadataBuildingContext context) {
@ -436,12 +434,12 @@ public class BinderHelper {
// Build the list of column names in the exact order they were // Build the list of column names in the exact order they were
// specified by the @JoinColumn annotations. // specified by the @JoinColumn annotations.
final List<Column> orderedColumns = new ArrayList<>( columns.length ); final List<Column> orderedColumns = new ArrayList<>( columns.getJoinColumns().size() );
final Map<Column, Set<Property>> columnsToProperty = new HashMap<>(); final Map<Column, Set<Property>> columnsToProperty = new HashMap<>();
final InFlightMetadataCollector collector = context.getMetadataCollector(); final InFlightMetadataCollector collector = context.getMetadataCollector();
for ( AnnotatedJoinColumn joinColumn : columns ) { for ( AnnotatedJoinColumn joinColumn : columns.getJoinColumns() ) {
if ( joinColumn.isReferenceImplicit() ) { if ( joinColumn.isReferenceImplicit() ) {
throw new AnnotationException("Association " + associationMessage( associatedEntity, joinColumn ) throw new AnnotationException("Association " + associationMessage( associatedEntity, columns )
+ " has a '@JoinColumn' which does not specify the 'referencedColumnName'" + " has a '@JoinColumn' which does not specify the 'referencedColumnName'"
+ " (when an association has multiple '@JoinColumn's, they must each specify their 'referencedColumnName')"); + " (when an association has multiple '@JoinColumn's, they must each specify their 'referencedColumnName')");
} }
@ -492,7 +490,7 @@ public class BinderHelper {
if ( properties.isEmpty() ) { if ( properties.isEmpty() ) {
// no property found which maps to this column // no property found which maps to this column
throw new AnnotationException( "Referenced column '" + column.getName() throw new AnnotationException( "Referenced column '" + column.getName()
+ "' in '@JoinColumn' for " + associationMessage( associatedEntity, columns[0] ) + "' in '@JoinColumn' for " + associationMessage( associatedEntity, columns )
+ " is not mapped by any property of the target entity" ); + " is not mapped by any property of the target entity" );
} }
for ( Property property : properties ) { for ( Property property : properties ) {
@ -503,7 +501,7 @@ public class BinderHelper {
throw new AnnotationException( "Referenced column '" + column.getName() throw new AnnotationException( "Referenced column '" + column.getName()
+ "' mapped by target property '" + property.getName() + "' mapped by target property '" + property.getName()
+ "' occurs out of order in the list of '@JoinColumn's for association " + "' occurs out of order in the list of '@JoinColumn's for association "
+ associationMessage( associatedEntity, columns[0] ) ); + associationMessage( associatedEntity, columns ) );
} }
lastPropertyColumnIndex++; lastPropertyColumnIndex++;
if ( lastPropertyColumnIndex == currentProperty.getColumnSpan() ) { if ( lastPropertyColumnIndex == currentProperty.getColumnSpan() ) {
@ -516,7 +514,7 @@ public class BinderHelper {
// we didn't use up all the columns of the previous property // we didn't use up all the columns of the previous property
throw new AnnotationException( "Target property '" + property.getName() + "' has " throw new AnnotationException( "Target property '" + property.getName() + "' has "
+ property.getColumnSpan() + " columns which must be referenced by a '@JoinColumn' for " + property.getColumnSpan() + " columns which must be referenced by a '@JoinColumn' for "
+ associationMessage( associatedEntity, columns[0] ) + associationMessage( associatedEntity, columns )
+ " (every column mapped by '" + property.getName() + " (every column mapped by '" + property.getName()
+ "' must occur exactly once as a 'referencedColumnName', and in the correct order)" ); + "' must occur exactly once as a 'referencedColumnName', and in the correct order)" );
} }
@ -524,7 +522,7 @@ public class BinderHelper {
// we already used up all the columns of this property // we already used up all the columns of this property
throw new AnnotationException( "Target property '" + property.getName() + "' has only " throw new AnnotationException( "Target property '" + property.getName() + "' has only "
+ property.getColumnSpan() + " columns which may be referenced by a '@JoinColumn' for " + property.getColumnSpan() + " columns which may be referenced by a '@JoinColumn' for "
+ associationMessage( associatedEntity, columns[0] ) + associationMessage( associatedEntity, columns )
+ " (each column mapped by '" + property.getName() + " (each column mapped by '" + property.getName()
+ "' may only occur once as a 'referencedColumnName')" ); + "' may only occur once as a 'referencedColumnName')" );
@ -1070,7 +1068,7 @@ public class BinderHelper {
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
context context
); );
assert discriminatorColumns.getColumns().length == 1; assert discriminatorColumns.getColumns().size() == 1;
discriminatorColumns.setTable( value.getTable() ); discriminatorColumns.setTable( value.getTable() );
discriminatorValueBinder.setColumns( discriminatorColumns ); discriminatorValueBinder.setColumns( discriminatorColumns );
@ -1082,7 +1080,7 @@ public class BinderHelper {
value.setDiscriminator( discriminatorDescriptor ); value.setDiscriminator( discriminatorDescriptor );
discriminatorValueBinder.fillSimpleValue(); discriminatorValueBinder.fillSimpleValue();
// TODO: this is nasty // TODO: this is nasty
final AnnotatedColumn firstDiscriminatorColumn = discriminatorColumns.getColumns()[0]; final AnnotatedColumn firstDiscriminatorColumn = discriminatorColumns.getColumns().get(0);
firstDiscriminatorColumn.linkWithValue( discriminatorDescriptor ); firstDiscriminatorColumn.linkWithValue( discriminatorDescriptor );
final JavaType<?> discriminatorJavaType = discriminatorDescriptor final JavaType<?> discriminatorJavaType = discriminatorDescriptor
@ -1100,8 +1098,8 @@ public class BinderHelper {
value.setDiscriminatorValueMappings( discriminatorValueMappings ); value.setDiscriminatorValueMappings( discriminatorValueMappings );
final BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context ); final BasicValueBinder keyValueBinder = new BasicValueBinder( BasicValueBinder.Kind.ANY_KEY, context );
final AnnotatedJoinColumn[] columns = keyColumns.getColumns(); final List<AnnotatedJoinColumn> columns = keyColumns.getJoinColumns();
assert columns.length == 1; assert columns.size() == 1;
keyColumns.setTable( value.getTable() ); keyColumns.setTable( value.getTable() );
keyValueBinder.setColumns( keyColumns ); keyValueBinder.setColumns( keyColumns );
if ( !optional ) { if ( !optional ) {
@ -1114,8 +1112,8 @@ public class BinderHelper {
value.setKey( keyDescriptor ); value.setKey( keyDescriptor );
keyValueBinder.fillSimpleValue(); keyValueBinder.fillSimpleValue();
final String path = qualify( propertyHolder.getEntityName(), inferredData.getPropertyName() ); final String path = qualify( propertyHolder.getEntityName(), inferredData.getPropertyName() );
AnnotatedColumn.checkPropertyConsistency( columns, path ); AnnotatedColumn.checkPropertyConsistency( keyColumns.getColumns(), path );
columns[0].linkWithValue( keyDescriptor ); columns.get(0).linkWithValue( keyDescriptor ); //TODO: nasty
return value; return value;
} }
@ -1175,23 +1173,22 @@ public class BinderHelper {
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
String propertyName, String propertyName,
MetadataBuildingContext buildingContext) { MetadataBuildingContext buildingContext) {
final XClass persistentXClass = buildingContext.getBootstrapContext().getReflectionManager() final XClass mappedClass = buildingContext.getBootstrapContext().getReflectionManager()
.toXClass( propertyHolder.getPersistentClass().getMappedClass() ); .toXClass( propertyHolder.getPersistentClass().getMappedClass() );
final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector(); final InFlightMetadataCollector metadataCollector = buildingContext.getMetadataCollector();
if ( propertyHolder.isInIdClass() ) { if ( propertyHolder.isInIdClass() ) {
PropertyData pd = metadataCollector.getPropertyAnnotatedWithIdAndToOne( persistentXClass, propertyName ); final PropertyData propertyData = metadataCollector.getPropertyAnnotatedWithIdAndToOne( mappedClass, propertyName );
if ( pd == null && buildingContext.getBuildingOptions().isSpecjProprietarySyntaxEnabled() ) { return propertyData == null && buildingContext.getBuildingOptions().isSpecjProprietarySyntaxEnabled()
pd = metadataCollector.getPropertyAnnotatedWithMapsId( persistentXClass, propertyName ); ? metadataCollector.getPropertyAnnotatedWithMapsId( mappedClass, propertyName )
} : propertyData;
return pd;
} }
else { else {
return metadataCollector.getPropertyAnnotatedWithMapsId( persistentXClass, isId ? "" : propertyName); return metadataCollector.getPropertyAnnotatedWithMapsId( mappedClass, isId ? "" : propertyName );
} }
} }
public static Map<String,String> toAliasTableMap(SqlFragmentAlias[] aliases){ public static Map<String,String> toAliasTableMap(SqlFragmentAlias[] aliases){
Map<String,String> ret = new HashMap<>(); final Map<String,String> ret = new HashMap<>();
for ( SqlFragmentAlias aliase : aliases ) { for ( SqlFragmentAlias aliase : aliases ) {
if ( isNotEmpty( aliase.table() ) ) { if ( isNotEmpty( aliase.table() ) ) {
ret.put( aliase.alias(), aliase.table() ); ret.put( aliase.alias(), aliase.table() );
@ -1201,13 +1198,13 @@ public class BinderHelper {
} }
public static Map<String,String> toAliasEntityMap(SqlFragmentAlias[] aliases){ public static Map<String,String> toAliasEntityMap(SqlFragmentAlias[] aliases){
Map<String,String> ret = new HashMap<>(); final Map<String,String> result = new HashMap<>();
for ( SqlFragmentAlias aliase : aliases ) { for ( SqlFragmentAlias aliase : aliases ) {
if ( aliase.entity() != void.class ) { if ( aliase.entity() != void.class ) {
ret.put( aliase.alias(), aliase.entity().getName() ); result.put( aliase.alias(), aliase.entity().getName() );
} }
} }
return ret; return result;
} }
public static boolean hasToOneAnnotation(XAnnotatedElement property) { public static boolean hasToOneAnnotation(XAnnotatedElement property) {
@ -1219,13 +1216,13 @@ public class BinderHelper {
XAnnotatedElement element, XAnnotatedElement element,
Class<T> annotationType, Class<T> annotationType,
MetadataBuildingContext context) { MetadataBuildingContext context) {
Dialect dialect = context.getMetadataCollector().getDatabase().getDialect(); final Dialect dialect = context.getMetadataCollector().getDatabase().getDialect();
Iterator<Annotation> annotations = final Iterator<Annotation> annotations =
Arrays.stream( element.getAnnotations() ) Arrays.stream( element.getAnnotations() )
.flatMap(annotation -> { .flatMap( annotation -> {
try { try {
Method value = annotation.annotationType().getDeclaredMethod("value"); final Method value = annotation.annotationType().getDeclaredMethod("value");
Class<?> returnType = value.getReturnType(); final Class<?> returnType = value.getReturnType();
if ( returnType.isArray() if ( returnType.isArray()
&& returnType.getComponentType().isAnnotationPresent(Repeatable.class) && returnType.getComponentType().isAnnotationPresent(Repeatable.class)
&& returnType.getComponentType().isAnnotationPresent(DialectOverride.OverridesAnnotation.class) ) { && returnType.getComponentType().isAnnotationPresent(DialectOverride.OverridesAnnotation.class) ) {
@ -1237,21 +1234,22 @@ public class BinderHelper {
throw new AssertionFailure("could not read @DialectOverride annotation", e); throw new AssertionFailure("could not read @DialectOverride annotation", e);
} }
return Stream.of(annotation); return Stream.of(annotation);
}).iterator(); } ).iterator();
while ( annotations.hasNext() ) { while ( annotations.hasNext() ) {
Annotation annotation = annotations.next(); final Annotation annotation = annotations.next();
Class<? extends Annotation> type = annotation.annotationType(); final Class<? extends Annotation> type = annotation.annotationType();
DialectOverride.OverridesAnnotation overridesAnnotation = type.getAnnotation(DialectOverride.OverridesAnnotation.class); final DialectOverride.OverridesAnnotation overridesAnnotation =
type.getAnnotation(DialectOverride.OverridesAnnotation.class);
if ( overridesAnnotation != null if ( overridesAnnotation != null
&& overridesAnnotation.value().equals(annotationType) ) { && overridesAnnotation.value().equals(annotationType) ) {
try { try {
//noinspection unchecked //noinspection unchecked
Class<? extends Dialect> overrideDialect = (Class<? extends Dialect>) final Class<? extends Dialect> overrideDialect = (Class<? extends Dialect>)
type.getDeclaredMethod("dialect").invoke(annotation); type.getDeclaredMethod("dialect").invoke(annotation);
if ( overrideDialect.isAssignableFrom( dialect.getClass() ) ) { if ( overrideDialect.isAssignableFrom( dialect.getClass() ) ) {
DialectOverride.Version before = (DialectOverride.Version) final DialectOverride.Version before = (DialectOverride.Version)
type.getDeclaredMethod("before").invoke(annotation); type.getDeclaredMethod("before").invoke(annotation);
DialectOverride.Version sameOrAfter = (DialectOverride.Version) final DialectOverride.Version sameOrAfter = (DialectOverride.Version)
type.getDeclaredMethod("sameOrAfter").invoke(annotation); type.getDeclaredMethod("sameOrAfter").invoke(annotation);
if ( dialect.getVersion().isBefore( before.major(), before.minor() ) if ( dialect.getVersion().isBefore( before.major(), before.minor() )
&& dialect.getVersion().isSameOrAfter( sameOrAfter.major(), sameOrAfter.minor() ) ) { && dialect.getVersion().isSameOrAfter( sameOrAfter.major(), sameOrAfter.minor() ) ) {
@ -1306,8 +1304,8 @@ public class BinderHelper {
Cascade hibernateCascadeAnnotation, Cascade hibernateCascadeAnnotation,
boolean orphanRemoval, boolean orphanRemoval,
boolean forcePersist) { boolean forcePersist) {
EnumSet<CascadeType> cascadeTypes = convertToHibernateCascadeType( ejbCascades ); final EnumSet<CascadeType> cascadeTypes = convertToHibernateCascadeType( ejbCascades );
CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ? null : hibernateCascadeAnnotation.value(); final CascadeType[] hibernateCascades = hibernateCascadeAnnotation == null ? null : hibernateCascadeAnnotation.value();
if ( hibernateCascades != null && hibernateCascades.length > 0 ) { if ( hibernateCascades != null && hibernateCascades.length > 0 ) {
cascadeTypes.addAll( Arrays.asList( hibernateCascades ) ); cascadeTypes.addAll( Arrays.asList( hibernateCascades ) );
} }
@ -1322,7 +1320,7 @@ public class BinderHelper {
} }
private static String renderCascadeTypeList(EnumSet<CascadeType> cascadeTypes) { private static String renderCascadeTypeList(EnumSet<CascadeType> cascadeTypes) {
StringBuilder cascade = new StringBuilder(); final StringBuilder cascade = new StringBuilder();
for ( CascadeType cascadeType : cascadeTypes) { for ( CascadeType cascadeType : cascadeTypes) {
switch ( cascadeType ) { switch ( cascadeType ) {
case ALL: case ALL:

View File

@ -12,7 +12,6 @@ import jakarta.persistence.Convert;
import jakarta.persistence.Converts; import jakarta.persistence.Converts;
import jakarta.persistence.JoinTable; import jakarta.persistence.JoinTable;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XClass;
@ -183,18 +182,10 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
} }
public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) { public void addProperty(Property prop, AnnotatedColumns columns, XClass declaringClass) {
//Ejb3Column.checkPropertyConsistency( ); //already called earlier //AnnotatedColumn.checkPropertyConsistency( ); //already called earlier
if ( columns != null ) { if ( columns != null ) {
final AnnotatedColumn firstColumn = columns.getColumns()[0]; if ( columns.isSecondary() ) {
if ( firstColumn.isSecondary() ) { addPropertyToJoin( prop, declaringClass, columns.getJoin() );
//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 { else {
addProperty( prop, declaringClass ); addProperty( prop, declaringClass );

View File

@ -239,19 +239,12 @@ class ColumnsBuilder {
} }
private AnnotatedJoinColumns buildJoinColumnsWithFormula(String propertyName, JoinFormula joinFormula) { private AnnotatedJoinColumns buildJoinColumnsWithFormula(String propertyName, JoinFormula joinFormula) {
final AnnotatedJoinColumn[] columns = new AnnotatedJoinColumn[1];
columns[0] = AnnotatedJoinColumn.buildJoinFormula(
joinFormula,
entityBinder.getSecondaryTables(),
propertyHolder,
propertyName,
buildingContext
);
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( buildingContext ); joinColumns.setBuildingContext( buildingContext );
joinColumns.setJoins( entityBinder.getSecondaryTables() );
joinColumns.setPropertyHolder( propertyHolder ); joinColumns.setPropertyHolder( propertyHolder );
joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName) ); joinColumns.setPropertyName( getRelativePath( propertyHolder, propertyName ) );
joinColumns.setColumns( columns ); AnnotatedJoinColumn.buildJoinFormula( joinFormula, joinColumns, propertyHolder, propertyName );
return joinColumns; return joinColumns;
} }
@ -260,13 +253,13 @@ class ColumnsBuilder {
return new JoinColumnOrFormula[] { property.getAnnotation( JoinColumnOrFormula.class ) }; return new JoinColumnOrFormula[] { property.getAnnotation( JoinColumnOrFormula.class ) };
} }
else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) { else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) {
JoinColumnsOrFormulas joinColumnsOrFormulasAnnotations = property.getAnnotation( JoinColumnsOrFormulas.class ); final JoinColumnsOrFormulas joinColumnsOrFormulas = property.getAnnotation( JoinColumnsOrFormulas.class );
final JoinColumnOrFormula[] joinColumnOrFormulaAnnotations = joinColumnsOrFormulasAnnotations.value(); final JoinColumnOrFormula[] joinColumnOrFormula = joinColumnsOrFormulas.value();
if ( joinColumnOrFormulaAnnotations.length == 0 ) { if ( joinColumnOrFormula.length == 0 ) {
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData) throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData)
+ "' has an empty '@JoinColumnsOrFormulas' annotation" ); + "' has an empty '@JoinColumnsOrFormulas' annotation" );
} }
return joinColumnOrFormulaAnnotations; return joinColumnOrFormula;
} }
else { else {
return null; return null;
@ -278,33 +271,34 @@ class ColumnsBuilder {
return new JoinColumn[] { property.getAnnotation( JoinColumn.class ) }; return new JoinColumn[] { property.getAnnotation( JoinColumn.class ) };
} }
else if ( property.isAnnotationPresent( JoinColumns.class ) ) { else if ( property.isAnnotationPresent( JoinColumns.class ) ) {
final JoinColumns joinColumnAnnotation = property.getAnnotation( JoinColumns.class ); final JoinColumns joinColumns = property.getAnnotation( JoinColumns.class );
final JoinColumn[] joinColumnAnnotations = joinColumnAnnotation.value(); final JoinColumn[] joinColumn = joinColumns.value();
if ( joinColumnAnnotations.length == 0 ) { if ( joinColumn.length == 0 ) {
throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData) throw new AnnotationException( "Property '" + getPath( propertyHolder, inferredData)
+ "' has an empty '@JoinColumns' annotation" ); + "' has an empty '@JoinColumns' annotation" );
} }
return joinColumnAnnotations; return joinColumn;
} }
else { else {
return null; return null;
} }
} }
AnnotatedColumns overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
final PropertyData overridingProperty =
getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), buildingContext );
return overridingProperty != null ? buildExplicitOrDefaultJoinColumn( overridingProperty ) : columns;
}
/** /**
* Useful to override a column either by {@code @MapsId} or by {@code @IdClass} * Useful to override a column either by {@code @MapsId} or by {@code @IdClass}
*/ */
//TODO: should we introduce an AnnotatedColumns type and return that here? AnnotatedColumns overrideColumnFromMapperOrMapsIdProperty(boolean isId) {
private AnnotatedColumns buildExplicitOrDefaultJoinColumn(PropertyData overridingProperty) { final PropertyData override =
final AnnotatedJoinColumns columns = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty ); getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), buildingContext );
return columns == null if ( override != null ) {
? buildDefaultJoinColumnsForToOne( overridingProperty.getProperty(), overridingProperty ) final AnnotatedJoinColumns joinColumns = buildExplicitJoinColumns( override.getProperty(), override );
: columns; return joinColumns == null
? buildDefaultJoinColumnsForToOne( override.getProperty(), override )
: joinColumns;
}
else {
return columns;
}
} }
} }

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -67,12 +68,12 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
@Override @Override
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException { public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
PersistentClass referencedPersistentClass = persistentClasses.get( referencedEntityName ); final PersistentClass referencedPersistentClass = persistentClasses.get( referencedEntityName );
if ( referencedPersistentClass == null ) { if ( referencedPersistentClass == null ) {
// TODO: much better error message if this is something that can really happen! // TODO: much better error message if this is something that can really happen!
throw new AnnotationException( "Unknown entity name '" + referencedEntityName + "'"); throw new AnnotationException( "Unknown entity name '" + referencedEntityName + "'");
} }
KeyValue identifier = referencedPersistentClass.getIdentifier(); final KeyValue identifier = referencedPersistentClass.getIdentifier();
if ( !(identifier instanceof Component) ) { if ( !(identifier instanceof Component) ) {
// The entity with the @MapsId annotation has a composite // The entity with the @MapsId annotation has a composite
// id type, but the referenced entity has a basic-typed id. // id type, but the referenced entity has a basic-typed id.
@ -87,13 +88,13 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
); );
} }
Component referencedComponent = (Component) identifier; final Component referencedComponent = (Component) identifier;
//prepare column name structure //prepare column name structure
boolean isExplicitReference = true; boolean isExplicitReference = true;
final AnnotatedJoinColumn[] cols = joinColumns.getColumns(); final List<AnnotatedJoinColumn> columns = joinColumns.getJoinColumns();
final Map<String, AnnotatedJoinColumn> columnByReferencedName = mapOfSize( cols.length ); final Map<String, AnnotatedJoinColumn> columnByReferencedName = mapOfSize( columns.size() );
for ( AnnotatedJoinColumn joinColumn : cols) { for ( AnnotatedJoinColumn joinColumn : columns ) {
if ( !joinColumn.isReferenceImplicit() ) { if ( !joinColumn.isReferenceImplicit() ) {
//JPA 2 requires referencedColumnNames to be case-insensitive //JPA 2 requires referencedColumnNames to be case-insensitive
columnByReferencedName.put( joinColumn.getReferencedColumn().toLowerCase(Locale.ROOT), joinColumn ); columnByReferencedName.put( joinColumn.getReferencedColumn().toLowerCase(Locale.ROOT), joinColumn );
@ -102,8 +103,8 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
//try default column orientation //try default column orientation
if ( columnByReferencedName.isEmpty() ) { if ( columnByReferencedName.isEmpty() ) {
isExplicitReference = false; isExplicitReference = false;
for (int i = 0; i < cols.length; i++ ) { for (int i = 0; i < columns.size(); i++ ) {
columnByReferencedName.put( String.valueOf( i ), cols[i] ); columnByReferencedName.put( String.valueOf( i ), columns.get(i) );
} }
} }
@ -185,7 +186,8 @@ public class CopyIdentifierComponentSecondPass extends FkSecondPass {
final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue(); final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue();
value.copyTypeFrom( referencedValue ); value.copyTypeFrom( referencedValue );
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0]; //TODO: this bit is nasty, move up to AnnotatedJoinColumns
final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
if ( firstColumn.isNameDeferred() ) { if ( firstColumn.isNameDeferred() ) {
firstColumn.copyReferencedStructureAndCreateDefaultJoinColumns( firstColumn.copyReferencedStructureAndCreateDefaultJoinColumns(
referencedPersistentClass, referencedPersistentClass,

View File

@ -29,53 +29,48 @@ public class IndexColumn extends AnnotatedColumn {
} }
public static IndexColumn fromAnnotations( public static IndexColumn fromAnnotations(
OrderColumn jpaAnnotation, OrderColumn orderColumn,
org.hibernate.annotations.IndexColumn hibAnnotation, org.hibernate.annotations.IndexColumn indexColumn,
ListIndexBase indexBaseAnnotation, ListIndexBase listIndexBase,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
Map<String, Join> secondaryTables, Map<String, Join> secondaryTables,
MetadataBuildingContext context) { MetadataBuildingContext context) {
final IndexColumn column; final IndexColumn column;
if ( jpaAnnotation != null ) { if ( orderColumn != null ) {
column = buildColumnFromAnnotation( column = buildColumnFromAnnotation( orderColumn, propertyHolder, inferredData, secondaryTables, context );
jpaAnnotation,
propertyHolder,
inferredData,
secondaryTables,
context
);
} }
else if ( hibAnnotation != null ) { else if ( indexColumn != null ) {
column = buildColumnFromAnnotation( column = buildColumnFromAnnotation( indexColumn, propertyHolder, inferredData, context );
hibAnnotation, column.setBase( indexColumn.base() );
propertyHolder,
inferredData,
context
);
column.setBase( hibAnnotation.base() );
} }
else { else {
column = new IndexColumn(); column = new IndexColumn();
column.setLogicalColumnName( inferredData.getPropertyName() + "_ORDER" ); //JPA default name column.setLogicalColumnName( inferredData.getPropertyName() + "_ORDER" ); //JPA default name
column.setImplicit( true ); column.setImplicit( true );
column.setBuildingContext( context ); // column.setContext( context );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
createParent( propertyHolder, column ); createParent( propertyHolder, secondaryTables, column, context );
column.bind(); column.bind();
} }
if ( indexBaseAnnotation != null ) { if ( listIndexBase != null ) {
column.setBase( indexBaseAnnotation.value() ); column.setBase( listIndexBase.value() );
} }
return column; return column;
} }
private static void createParent(PropertyHolder propertyHolder, IndexColumn column) { private static void createParent(
final AnnotatedColumns columns = new AnnotatedColumns(); PropertyHolder propertyHolder,
columns.setColumns( new AnnotatedColumn[] {column} ); Map<String,Join> secondaryTables,
columns.setPropertyHolder( propertyHolder ); IndexColumn column,
MetadataBuildingContext context) {
final AnnotatedColumns parent = new AnnotatedColumns();
parent.setPropertyHolder( propertyHolder );
parent.setJoins( secondaryTables );
parent.setBuildingContext( context );
column.setParent( parent );
} }
public int getBase() { public int getBase() {
@ -101,30 +96,29 @@ public class IndexColumn extends AnnotatedColumn {
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
Map<String, Join> secondaryTables, Map<String, Join> secondaryTables,
MetadataBuildingContext buildingContext) { MetadataBuildingContext context) {
if ( orderColumn != null ) { if ( orderColumn != null ) {
final String sqlType = isEmptyAnnotationValue( orderColumn.columnDefinition() ) ? null : orderColumn.columnDefinition(); final String sqlType = isEmptyAnnotationValue( orderColumn.columnDefinition() ) ? null : orderColumn.columnDefinition();
final String name = isEmptyAnnotationValue( orderColumn.name() ) ? inferredData.getPropertyName() + "_ORDER" : orderColumn.name(); final String name = isEmptyAnnotationValue( orderColumn.name() ) ? inferredData.getPropertyName() + "_ORDER" : orderColumn.name();
//TODO move it to a getter based system and remove the constructor
final IndexColumn column = new IndexColumn(); final IndexColumn column = new IndexColumn();
column.setLogicalColumnName( name ); column.setLogicalColumnName( name );
column.setSqlType( sqlType ); column.setSqlType( sqlType );
column.setNullable( orderColumn.nullable() ); column.setNullable( orderColumn.nullable() );
column.setJoins( secondaryTables ); // column.setJoins( secondaryTables );
column.setInsertable( orderColumn.insertable() ); column.setInsertable( orderColumn.insertable() );
column.setUpdatable( orderColumn.updatable() ); column.setUpdatable( orderColumn.updatable() );
column.setBuildingContext( buildingContext ); // column.setContext( context );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
createParent( propertyHolder, column ); createParent( propertyHolder, secondaryTables, column, context );
column.bind(); column.bind();
return column; return column;
} }
else { else {
final IndexColumn column = new IndexColumn(); final IndexColumn column = new IndexColumn();
column.setImplicit( true ); column.setImplicit( true );
column.setBuildingContext( buildingContext ); // column.setContext( context );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
createParent( propertyHolder, column ); createParent( propertyHolder, secondaryTables, column, context );
column.bind(); column.bind();
return column; return column;
} }
@ -133,38 +127,38 @@ public class IndexColumn extends AnnotatedColumn {
/** /**
* Legacy {@link IndexColumn @IndexColumn} processing. * Legacy {@link IndexColumn @IndexColumn} processing.
* *
* @param ann The IndexColumn annotation instance * @param indexColumn The IndexColumn annotation instance
* @param propertyHolder Information about the property * @param propertyHolder Information about the property
* @param inferredData Yeah, right. Uh... * @param inferredData Yeah, right. Uh...
* *
* @return The index column * @return The index column
*/ */
public static IndexColumn buildColumnFromAnnotation( public static IndexColumn buildColumnFromAnnotation(
org.hibernate.annotations.IndexColumn ann, org.hibernate.annotations.IndexColumn indexColumn,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PropertyData inferredData, PropertyData inferredData,
MetadataBuildingContext buildingContext) { MetadataBuildingContext context) {
if ( ann != null ) { if ( indexColumn != null ) {
final String sqlType = isEmptyAnnotationValue( ann.columnDefinition() ) ? null : ann.columnDefinition(); final String sqlType = isEmptyAnnotationValue( indexColumn.columnDefinition() ) ? null : indexColumn.columnDefinition();
final String name = isEmptyAnnotationValue( ann.name() ) ? inferredData.getPropertyName() : ann.name(); final String name = isEmptyAnnotationValue( indexColumn.name() ) ? inferredData.getPropertyName() : indexColumn.name();
//TODO move it to a getter based system and remove the constructor //TODO move it to a getter based system and remove the constructor
final IndexColumn column = new IndexColumn(); final IndexColumn column = new IndexColumn();
column.setLogicalColumnName( name ); column.setLogicalColumnName( name );
column.setSqlType( sqlType ); column.setSqlType( sqlType );
column.setNullable( ann.nullable() ); column.setNullable( indexColumn.nullable() );
column.setBase( ann.base() ); column.setBase( indexColumn.base() );
column.setBuildingContext( buildingContext ); // column.setContext( context );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
createParent( propertyHolder, column ); createParent( propertyHolder, null, column, context );
column.bind(); column.bind();
return column; return column;
} }
else { else {
final IndexColumn column = new IndexColumn(); final IndexColumn column = new IndexColumn();
column.setImplicit( true ); column.setImplicit( true );
column.setBuildingContext( buildingContext ); // column.setContext( context );
// column.setPropertyHolder( propertyHolder ); // column.setPropertyHolder( propertyHolder );
createParent( propertyHolder, column ); createParent( propertyHolder, null, column, context );
column.bind(); column.bind();
return column; return column;
} }

View File

@ -91,7 +91,7 @@ public class ToOneBinder {
final JoinTable joinTable = propertyHolder.getJoinTable( property ); final JoinTable joinTable = propertyHolder.getJoinTable( property );
if ( joinTable != null ) { if ( joinTable != null ) {
final Join join = propertyHolder.addJoin( joinTable, false ); final Join join = propertyHolder.addJoin( joinTable, false );
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn joinColumn : joinColumns.getJoinColumns() ) {
joinColumn.setExplicitTableName( join.getTable().getName() ); joinColumn.setExplicitTableName( join.getTable().getName() );
} }
} }
@ -155,14 +155,14 @@ public class ToOneBinder {
value.setCascadeDeleteEnabled( cascadeOnDelete ); value.setCascadeDeleteEnabled( cascadeOnDelete );
//value.setLazy( fetchMode != FetchMode.JOIN ); //value.setLazy( fetchMode != FetchMode.JOIN );
if ( !optional ) { if ( !optional ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : joinColumns.getJoinColumns() ) {
column.setNullable( false ); column.setNullable( false );
} }
} }
if ( property.isAnnotationPresent( MapsId.class ) ) { if ( property.isAnnotationPresent( MapsId.class ) ) {
//read only //read only
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : joinColumns.getJoinColumns() ) {
column.setInsertable( false ); column.setInsertable( false );
column.setUpdatable( false ); column.setUpdatable( false );
} }
@ -228,7 +228,7 @@ public class ToOneBinder {
&& joinColumn.name().equals( columnName ) && joinColumn.name().equals( columnName )
&& !property.isAnnotationPresent( MapsId.class ) ) { && !property.isAnnotationPresent( MapsId.class ) ) {
hasSpecjManyToOne = true; hasSpecjManyToOne = true;
for ( AnnotatedJoinColumn column : columns.getColumns() ) { for ( AnnotatedJoinColumn column : columns.getJoinColumns() ) {
column.setInsertable( false ); column.setInsertable( false );
column.setUpdatable( false ); column.setUpdatable( false );
} }
@ -256,16 +256,16 @@ public class ToOneBinder {
propertyBinder.setName( propertyName ); propertyBinder.setName( propertyName );
propertyBinder.setValue( value ); propertyBinder.setValue( value );
//binder.setCascade(cascadeStrategy); //binder.setCascade(cascadeStrategy);
if (isIdentifierMapper) { if ( isIdentifierMapper ) {
propertyBinder.setInsertable( false ); propertyBinder.setInsertable( false );
propertyBinder.setUpdatable( false ); propertyBinder.setUpdatable( false );
} }
else if (hasSpecjManyToOne) { else if ( hasSpecjManyToOne ) {
propertyBinder.setInsertable( false ); propertyBinder.setInsertable( false );
propertyBinder.setUpdatable( false ); propertyBinder.setUpdatable( false );
} }
else { else {
final AnnotatedJoinColumn firstColumn = columns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = columns.getJoinColumns().get(0);
propertyBinder.setInsertable( firstColumn.isInsertable() ); propertyBinder.setInsertable( firstColumn.isInsertable() );
propertyBinder.setUpdatable( firstColumn.isUpdatable() ); propertyBinder.setUpdatable( firstColumn.isUpdatable() );
} }
@ -393,7 +393,7 @@ public class ToOneBinder {
if ( notFoundAction != null ) { if ( notFoundAction != null ) {
join.disableForeignKeyCreation(); join.disableForeignKeyCreation();
} }
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn joinColumn : joinColumns.getJoinColumns() ) {
joinColumn.setExplicitTableName( join.getTable().getName() ); joinColumn.setExplicitTableName( join.getTable().getName() );
} }
} }
@ -493,16 +493,16 @@ public class ToOneBinder {
} }
else { else {
final List<String> idColumnNames = new ArrayList<>(); final List<String> idColumnNames = new ArrayList<>();
final AnnotatedJoinColumn[] columns = joinColumns.getColumns(); final List<AnnotatedJoinColumn> columns = joinColumns.getJoinColumns();
if ( identifier.getColumnSpan() != columns.length ) { if ( identifier.getColumnSpan() != columns.size() ) {
return false; return false;
} }
else { else {
for ( org.hibernate.mapping.Column currentColumn: identifier.getColumns() ) { for ( org.hibernate.mapping.Column currentColumn: identifier.getColumns() ) {
idColumnNames.add( currentColumn.getName() ); idColumnNames.add( currentColumn.getName() );
} }
for ( AnnotatedJoinColumn col: columns ) { for ( AnnotatedJoinColumn column: columns ) {
if ( !idColumnNames.contains( col.getMappingColumn().getName() ) ) { if ( !idColumnNames.contains( column.getMappingColumn().getName() ) ) {
return false; return false;
} }
} }

View File

@ -56,7 +56,6 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotatedColumn; import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns; import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.AnnotatedJoinColumn;
import org.hibernate.cfg.AnnotatedJoinColumns; import org.hibernate.cfg.AnnotatedJoinColumns;
import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass; import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass;
import org.hibernate.cfg.SetBasicValueTypeSecondPass; import org.hibernate.cfg.SetBasicValueTypeSecondPass;
@ -103,8 +102,8 @@ import static org.hibernate.cfg.annotations.HCANNHelper.findAnnotation;
*/ */
public class BasicValueBinder implements JdbcTypeIndicators { public class BasicValueBinder implements JdbcTypeIndicators {
// todo (6.0) : In light of how we want to build Types (specifically BasicTypes) moving forward this class should undergo major changes // todo (6.0) : In light of how we want to build Types (specifically BasicTypes) moving
// see the comments in #setType // forward this class should undergo major changes: see the comments in #setType
// but as always the "design" of these classes make it unclear exactly how to change it properly. // but as always the "design" of these classes make it unclear exactly how to change it properly.
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BasicValueBinder.class.getName() ); private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, BasicValueBinder.class.getName() );
@ -1126,13 +1125,17 @@ public class BasicValueBinder implements JdbcTypeIndicators {
public void linkWithValue() { public void linkWithValue() {
final InFlightMetadataCollector collector = buildingContext.getMetadataCollector(); final InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
final AnnotatedColumn firstColumn = columns.getColumns()[0]; final AnnotatedColumn firstColumn = columns.getColumns().get(0);
if ( !collector.isInSecondPass() && firstColumn.isNameDeferred() && referencedEntityName != null ) { if ( !collector.isInSecondPass() && firstColumn.isNameDeferred() && referencedEntityName != null ) {
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( buildingContext ); joinColumns.setBuildingContext( buildingContext );
joinColumns.setPropertyHolder( firstColumn.getPropertyHolder() ); joinColumns.setPropertyHolder( columns.getPropertyHolder() );
joinColumns.setPropertyName( firstColumn.getPropertyName() ); joinColumns.setPropertyName( firstColumn.getPropertyName() );
joinColumns.setColumns( (AnnotatedJoinColumn[]) columns.getColumns() ); //TODO: resetting the parent here looks like a dangerous thing to do
// should we be cloning them first (the legacy code did not)
for ( AnnotatedColumn column : columns.getColumns() ) {
column.setParent( joinColumns );
}
collector.addSecondPass( collector.addSecondPass(
new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, joinColumns, basicValue ) new PkDrivenByDefaultMapsIdSecondPass( referencedEntityName, joinColumns, basicValue )
); );

View File

@ -174,7 +174,6 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty;
import static org.hibernate.internal.util.StringHelper.nullIfEmpty; import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
import static org.hibernate.internal.util.StringHelper.qualify; 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. * Base class for binding different types of collections to Hibernate configuration objects.
@ -306,6 +305,7 @@ public abstract class CollectionBinder {
collectionBinder.setCache( property.getAnnotation( Cache.class ) ); collectionBinder.setCache( property.getAnnotation( Cache.class ) );
collectionBinder.setPropertyHolder(propertyHolder); collectionBinder.setPropertyHolder(propertyHolder);
final Cascade hibernateCascade = property.getAnnotation( Cascade.class ); final Cascade hibernateCascade = property.getAnnotation( Cascade.class );
final NotFound notFound = property.getAnnotation( NotFound.class ); final NotFound notFound = property.getAnnotation( NotFound.class );
if ( notFound != null ) { if ( notFound != null ) {
@ -315,6 +315,7 @@ public abstract class CollectionBinder {
} }
collectionBinder.setNotFoundAction( notFound.action() ); collectionBinder.setNotFoundAction( notFound.action() );
} }
collectionBinder.setElementType( inferredData.getProperty().getElementClass() ); collectionBinder.setElementType( inferredData.getProperty().getElementClass() );
collectionBinder.setAccessType( inferredData.getDefaultAccess() ); collectionBinder.setAccessType( inferredData.getDefaultAccess() );
@ -332,17 +333,16 @@ public abstract class CollectionBinder {
virtualProperty, virtualProperty,
comment comment
); );
final JoinColumn[] joinKeyColumns = mapKeyColumns(
propertyHolder,
inferredData,
entityBinder,
context,
property,
collectionBinder,
comment
);
final AnnotatedJoinColumns mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix( final AnnotatedJoinColumns mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix(
joinKeyColumns, mapKeyColumns(
propertyHolder,
inferredData,
entityBinder,
context,
property,
collectionBinder,
comment
),
comment, comment,
null, null,
entityBinder.getSecondaryTables(), entityBinder.getSecondaryTables(),
@ -356,20 +356,7 @@ public abstract class CollectionBinder {
//potential element //potential element
collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) ); collectionBinder.setEmbedded( property.isAnnotationPresent( Embedded.class ) );
collectionBinder.setElementColumns( elementColumns ); collectionBinder.setElementColumns( elementColumns );
collectionBinder.setProperty(property); collectionBinder.setProperty( property );
final String mappedBy = handleTargetEntity(
propertyHolder,
inferredData,
context,
property,
joinColumns,
oneToManyAnn,
manyToManyAnn,
elementCollectionAnn,
collectionBinder,
hibernateCascade
);
bindJoinedTableAssociation( bindJoinedTableAssociation(
property, property,
@ -378,23 +365,34 @@ public abstract class CollectionBinder {
collectionBinder, collectionBinder,
propertyHolder, propertyHolder,
inferredData, inferredData,
mappedBy handleTargetEntity(
propertyHolder,
inferredData,
context,
property,
joinColumns,
oneToManyAnn,
manyToManyAnn,
elementCollectionAnn,
collectionBinder,
hibernateCascade
)
); );
final OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class ); final OnDelete onDelete = property.getAnnotation( OnDelete.class );
final boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action(); final boolean onDeleteCascade = onDelete != null && OnDeleteAction.CASCADE == onDelete.action();
collectionBinder.setCascadeDeleteEnabled( onDeleteCascade ); collectionBinder.setCascadeDeleteEnabled( onDeleteCascade );
if ( isIdentifierMapper ) { if ( isIdentifierMapper ) {
collectionBinder.setInsertable( false ); collectionBinder.setInsertable( false );
collectionBinder.setUpdatable( false ); collectionBinder.setUpdatable( false );
} }
if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary if ( property.isAnnotationPresent( CollectionId.class ) ) { //do not compute the generators unless necessary
HashMap<String, IdentifierGeneratorDefinition> localGenerators = new HashMap<>(classGenerators); final HashMap<String, IdentifierGeneratorDefinition> localGenerators = new HashMap<>(classGenerators);
localGenerators.putAll( AnnotationBinder.buildGenerators(property, context) ); localGenerators.putAll( AnnotationBinder.buildGenerators( property, context ) );
collectionBinder.setLocalGenerators( localGenerators ); collectionBinder.setLocalGenerators( localGenerators );
} }
collectionBinder.setInheritanceStatePerClass(inheritanceStatePerClass); collectionBinder.setInheritanceStatePerClass( inheritanceStatePerClass );
collectionBinder.setDeclaringClass( inferredData.getDeclaringClass() ); collectionBinder.setDeclaringClass( inferredData.getDeclaringClass() );
collectionBinder.bind(); collectionBinder.bind();
} }
@ -419,7 +417,7 @@ public abstract class CollectionBinder {
final String mappedBy; final String mappedBy;
final ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager(); final ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager();
if ( oneToManyAnn != null ) { if ( oneToManyAnn != null ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : joinColumns.getJoinColumns() ) {
if ( column.isSecondary() ) { if ( column.isSecondary() ) {
//TODO: fix the error message //TODO: fix the error message
throw new NotYetImplementedException( "Collections having FK in secondary table" ); throw new NotYetImplementedException( "Collections having FK in secondary table" );
@ -435,7 +433,7 @@ public abstract class CollectionBinder {
collectionBinder.setOneToMany( true ); collectionBinder.setOneToMany( true );
} }
else if ( elementCollectionAnn != null ) { else if ( elementCollectionAnn != null ) {
for ( AnnotatedJoinColumn column : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn column : joinColumns.getJoinColumns() ) {
if ( column.isSecondary() ) { if ( column.isSecondary() ) {
//TODO: fix the error message //TODO: fix the error message
throw new NotYetImplementedException( "Collections having FK in secondary table" ); throw new NotYetImplementedException( "Collections having FK in secondary table" );
@ -1499,8 +1497,8 @@ public abstract class CollectionBinder {
&& !reversePropertyInJoin && !reversePropertyInJoin
&& oneToMany && oneToMany
&& !isExplicitAssociationTable && !isExplicitAssociationTable
&& ( joinColumns.getColumns()[0].isImplicit() && hasMappedBy() //implicit @JoinColumn && ( joinColumns.getJoinColumns().get(0).isImplicit() && hasMappedBy() //implicit @JoinColumn
|| !foreignJoinColumns.getColumns()[0].isImplicit() ) //this is an explicit @JoinColumn || !foreignJoinColumns.getJoinColumns().get(0).isImplicit() ) //this is an explicit @JoinColumn
) { ) {
//this is a foreign key //this is a foreign key
bindOneToManySecondPass( persistentClasses ); bindOneToManySecondPass( persistentClasses );
@ -1546,9 +1544,7 @@ public abstract class CollectionBinder {
final Map<String, Join> joins = buildingContext.getMetadataCollector().getJoins( referencedEntityName ); final Map<String, Join> joins = buildingContext.getMetadataCollector().getJoins( referencedEntityName );
foreignJoinColumns.setPersistentClass( associatedClass, joins, inheritanceStatePerClass ); foreignJoinColumns.setPersistentClass( associatedClass, joins, inheritanceStatePerClass );
for ( AnnotatedJoinColumn column : foreignJoinColumns.getColumns() ) { foreignJoinColumns.setJoins( joins );
column.setJoins( joins );
}
collection.setCollectionTable( foreignJoinColumns.getTable() ); collection.setCollectionTable( foreignJoinColumns.getTable() );
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() ); LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
@ -1572,7 +1568,7 @@ public abstract class CollectionBinder {
final PersistentClass referenced = collector.getEntityBinding( entityName ); final PersistentClass referenced = collector.getEntityBinding( entityName );
final Backref backref = new Backref(); final Backref backref = new Backref();
final String backrefName = '_' + foreignJoinColumns.getPropertyName() final String backrefName = '_' + foreignJoinColumns.getPropertyName()
+ '_' + foreignJoinColumns.getColumns()[0].getLogicalColumnName() + '_' + foreignJoinColumns.getColumns().get(0).getLogicalColumnName()
+ "Backref"; + "Backref";
backref.setName( backrefName ); backref.setName( backrefName );
backref.setUpdateable( false); backref.setUpdateable( false);
@ -1856,10 +1852,10 @@ public abstract class CollectionBinder {
final DependantValue key = new DependantValue( buildingContext, collection.getCollectionTable(), keyValue ); final DependantValue key = new DependantValue( buildingContext, collection.getCollectionTable(), keyValue );
key.setTypeName( null ); key.setTypeName( null );
final AnnotatedJoinColumn[] columns = joinColumns.getColumns(); final List<AnnotatedColumn> columns = joinColumns.getColumns();
checkPropertyConsistency( columns, collection.getOwnerEntityName() ); checkPropertyConsistency( columns, collection.getOwnerEntityName() );
key.setNullable( columns.length == 0 || columns[0].isNullable() ); key.setNullable( columns.isEmpty() || columns.get(0).isNullable() );
key.setUpdateable( columns.length == 0 || columns[0].isUpdatable() ); key.setUpdateable( columns.isEmpty() || columns.get(0).isUpdatable() );
key.setCascadeDeleteEnabled( cascadeDeleteEnabled ); key.setCascadeDeleteEnabled( cascadeDeleteEnabled );
collection.setKey( key ); collection.setKey( key );
@ -1958,7 +1954,7 @@ public abstract class CollectionBinder {
} }
private void overrideReferencedPropertyName(Collection collection, AnnotatedJoinColumns joinColumns) { private void overrideReferencedPropertyName(Collection collection, AnnotatedJoinColumns joinColumns) {
if ( hasMappedBy() && joinColumns.getColumns().length > 0 ) { if ( hasMappedBy() && !joinColumns.getColumns().isEmpty() ) {
final String entityName = joinColumns.getManyToManyOwnerSideEntityName() != null final String entityName = joinColumns.getManyToManyOwnerSideEntityName() != null
? "inverse__" + joinColumns.getManyToManyOwnerSideEntityName() ? "inverse__" + joinColumns.getManyToManyOwnerSideEntityName()
: joinColumns.getPropertyHolder().getEntityName(); : joinColumns.getPropertyHolder().getEntityName();
@ -2199,22 +2195,21 @@ public abstract class CollectionBinder {
String defaultName, String defaultName,
Long defaultLength, Long defaultLength,
MetadataBuildingContext context) { MetadataBuildingContext context) {
if ( elementColumns == null || isEmpty( elementColumns.getColumns() ) ) { if ( elementColumns == null || elementColumns.getColumns().isEmpty() ) {
final AnnotatedColumns columns = new AnnotatedColumns();
columns.setBuildingContext( context );
final AnnotatedColumn column = new AnnotatedColumn(); final AnnotatedColumn column = new AnnotatedColumn();
column.setLogicalColumnName( defaultName ); column.setLogicalColumnName( defaultName );
if ( defaultLength!=null ) { if ( defaultLength != null ) {
column.setLength( defaultLength ); column.setLength( defaultLength );
} }
column.setImplicit( false ); column.setImplicit( false );
//not following the spec but more clean //not following the spec but more clean
column.setNullable( true ); column.setNullable( true );
//TODO create an EMPTY_JOINS collection // column.setContext( context );
column.setJoins( new HashMap<>() ); column.setParent( columns );
column.setBuildingContext( context );
column.bind(); column.bind();
final AnnotatedColumns result = new AnnotatedColumns(); elementColumns = columns;
result.setColumns( new AnnotatedColumn[] { column } );
elementColumns = result;
} }
//override the table //override the table
elementColumns.setTable( collection.getCollectionTable() ); elementColumns.setTable( collection.getCollectionTable() );
@ -2560,7 +2555,7 @@ public abstract class CollectionBinder {
if ( hasMappedBy() ) { if ( hasMappedBy() ) {
final Property property = targetEntity.getRecursiveProperty( mappedBy ); final Property property = targetEntity.getRecursiveProperty( mappedBy );
final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property ); final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property );
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
for ( Selectable selectable: mappedByColumns ) { for ( Selectable selectable: mappedByColumns ) {
firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value ); firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value );
} }

View File

@ -215,7 +215,7 @@ public class EntityBinder {
//TODO: be more strict with secondary table allowance (not for ids, not for secondary table join columns etc) //TODO: be more strict with secondary table allowance (not for ids, not for secondary table join columns etc)
final InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess ); final InheritanceState inheritanceState = inheritanceStatePerClass.get( clazzToProcess );
final PersistentClass superEntity = getSuperEntity( clazzToProcess, inheritanceStatePerClass, context, inheritanceState ); final PersistentClass superEntity = getSuperEntity( clazzToProcess, inheritanceStatePerClass, context, inheritanceState );
detectedAttributeOverrideProblem(clazzToProcess, superEntity ); detectedAttributeOverrideProblem( clazzToProcess, superEntity );
final PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity, context); final PersistentClass persistentClass = makePersistentClass( inheritanceState, superEntity, context);
final EntityBinder entityBinder = new EntityBinder( clazzToProcess, persistentClass, context ); final EntityBinder entityBinder = new EntityBinder( clazzToProcess, persistentClass, context );
@ -789,11 +789,13 @@ public class EntityBinder {
if ( discriminatorColumn == null ) { if ( discriminatorColumn == null ) {
throw new AssertionFailure( "discriminator column should have been built" ); throw new AssertionFailure( "discriminator column should have been built" );
} }
discriminatorColumn.setJoins( secondaryTables );
// discriminatorColumn.setPropertyHolder( propertyHolder );
final AnnotatedColumns columns = new AnnotatedColumns(); final AnnotatedColumns columns = new AnnotatedColumns();
columns.setColumns( new AnnotatedColumn[] { discriminatorColumn } );
columns.setPropertyHolder( propertyHolder ); columns.setPropertyHolder( propertyHolder );
columns.setBuildingContext( context );
columns.setJoins( secondaryTables );
// discriminatorColumn.setJoins( secondaryTables );
// discriminatorColumn.setPropertyHolder( propertyHolder );
discriminatorColumn.setParent( columns );
final BasicValue discriminatorColumnBinding = new BasicValue( context, rootClass.getTable() ); final BasicValue discriminatorColumnBinding = new BasicValue( context, rootClass.getTable() );
rootClass.setDiscriminator( discriminatorColumnBinding ); rootClass.setDiscriminator( discriminatorColumnBinding );
@ -817,16 +819,19 @@ public class EntityBinder {
InheritanceState inheritanceState, InheritanceState inheritanceState,
EntityBinder entityBinder) { EntityBinder entityBinder) {
DiscriminatorColumn discAnn = clazzToProcess.getAnnotation( DiscriminatorColumn.class ); final DiscriminatorColumn discriminatorColumn = clazzToProcess.getAnnotation( DiscriminatorColumn.class );
DiscriminatorType discriminatorType = discAnn != null ? discAnn.discriminatorType() : DiscriminatorType.STRING; final DiscriminatorType discriminatorType = discriminatorColumn != null
? discriminatorColumn.discriminatorType()
: DiscriminatorType.STRING;
DiscriminatorFormula discFormulaAnn = getOverridableAnnotation( clazzToProcess, DiscriminatorFormula.class, context ); final DiscriminatorFormula discriminatorFormula =
getOverridableAnnotation( clazzToProcess, DiscriminatorFormula.class, context );
final boolean isRoot = !inheritanceState.hasParents(); final boolean isRoot = !inheritanceState.hasParents();
final AnnotatedDiscriminatorColumn discriminatorColumn = isRoot final AnnotatedDiscriminatorColumn discriminator = isRoot
? buildDiscriminatorColumn( discriminatorType, discAnn, discFormulaAnn, context ) ? buildDiscriminatorColumn( discriminatorType, discriminatorColumn, discriminatorFormula, context )
: null; : null;
if ( discAnn != null && !isRoot ) { if ( discriminatorColumn != null && !isRoot ) {
//TODO: shouldn't this be an error?! //TODO: shouldn't this be an error?!
LOG.invalidDiscriminatorAnnotation( clazzToProcess.getName() ); LOG.invalidDiscriminatorAnnotation( clazzToProcess.getName() );
} }
@ -836,13 +841,13 @@ public class EntityBinder {
: null; : null;
entityBinder.setDiscriminatorValue( discriminatorValue ); entityBinder.setDiscriminatorValue( discriminatorValue );
DiscriminatorOptions discriminatorOptions = clazzToProcess.getAnnotation( DiscriminatorOptions.class ); final DiscriminatorOptions discriminatorOptions = clazzToProcess.getAnnotation( DiscriminatorOptions.class );
if ( discriminatorOptions != null) { if ( discriminatorOptions != null) {
entityBinder.setForceDiscriminator( discriminatorOptions.force() ); entityBinder.setForceDiscriminator( discriminatorOptions.force() );
entityBinder.setInsertableDiscriminator( discriminatorOptions.insert() ); entityBinder.setInsertableDiscriminator( discriminatorOptions.insert() );
} }
return discriminatorColumn; return discriminator;
} }
/** /**
@ -997,58 +1002,62 @@ public class EntityBinder {
InheritanceState inheritanceState, InheritanceState inheritanceState,
PersistentClass superEntity) { PersistentClass superEntity) {
AnnotatedJoinColumn[] inheritanceJoinedColumns = null;
final boolean hasJoinedColumns = inheritanceState.hasParents() final boolean hasJoinedColumns = inheritanceState.hasParents()
&& InheritanceType.JOINED == inheritanceState.getType(); && InheritanceType.JOINED == inheritanceState.getType();
if ( hasJoinedColumns ) { if ( hasJoinedColumns ) {
//@Inheritance(JOINED) subclass need to link back to the super entity return subclassJoinColumns( clazzToProcess, superEntity, context );
final PrimaryKeyJoinColumns jcsAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class );
boolean explicitInheritanceJoinedColumns = jcsAnn != null && jcsAnn.value().length != 0;
if ( explicitInheritanceJoinedColumns ) {
int nbrOfInhJoinedColumns = jcsAnn.value().length;
PrimaryKeyJoinColumn jcAnn;
inheritanceJoinedColumns = new AnnotatedJoinColumn[nbrOfInhJoinedColumns];
for ( int colIndex = 0; colIndex < nbrOfInhJoinedColumns; colIndex++ ) {
jcAnn = jcsAnn.value()[colIndex];
inheritanceJoinedColumns[colIndex] = buildJoinColumn(
jcAnn,
null,
superEntity.getIdentifier(),
null,
null,
context
);
}
}
else {
final PrimaryKeyJoinColumn jcAnn = clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class );
inheritanceJoinedColumns = new AnnotatedJoinColumn[1];
inheritanceJoinedColumns[0] = buildJoinColumn(
jcAnn,
null,
superEntity.getIdentifier(),
null,
null,
context
);
}
LOG.trace( "Subclass joined column(s) created" );
} }
else { else {
if ( clazzToProcess.isAnnotationPresent( PrimaryKeyJoinColumns.class ) if ( clazzToProcess.isAnnotationPresent( PrimaryKeyJoinColumns.class )
|| clazzToProcess.isAnnotationPresent( PrimaryKeyJoinColumn.class ) ) { || clazzToProcess.isAnnotationPresent( PrimaryKeyJoinColumn.class ) ) {
LOG.invalidPrimaryKeyJoinColumnAnnotation( clazzToProcess.getName() ); LOG.invalidPrimaryKeyJoinColumnAnnotation( clazzToProcess.getName() );
} }
}
if ( inheritanceJoinedColumns == null ) {
return null; return null;
} }
else { }
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( context ); private static AnnotatedJoinColumns subclassJoinColumns(
joinColumns.setColumns( inheritanceJoinedColumns ); XClass clazzToProcess,
return joinColumns; PersistentClass superEntity,
MetadataBuildingContext context) {
//@Inheritance(JOINED) subclass need to link back to the super entity
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( context );
final PrimaryKeyJoinColumns primaryKeyJoinColumns = clazzToProcess.getAnnotation( PrimaryKeyJoinColumns.class );
if ( primaryKeyJoinColumns != null ) {
final PrimaryKeyJoinColumn[] columns = primaryKeyJoinColumns.value();
if ( columns.length > 0 ) {
for ( PrimaryKeyJoinColumn column : columns ) {
buildJoinColumn(
column,
null,
superEntity.getIdentifier(),
joinColumns,
context
);
}
}
else {
buildJoinColumn(
clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ),
null,
superEntity.getIdentifier(),
joinColumns,
context
);
}
} }
else {
buildJoinColumn(
clazzToProcess.getAnnotation( PrimaryKeyJoinColumn.class ),
null,
superEntity.getIdentifier(),
joinColumns,
context
);
}
LOG.trace( "Subclass joined column(s) created" );
return joinColumns;
} }
private static PersistentClass getSuperEntity( private static PersistentClass getSuperEntity(
@ -1741,7 +1750,7 @@ public class EntityBinder {
public void finalSecondaryTableBinding(PropertyHolder propertyHolder) { public void finalSecondaryTableBinding(PropertyHolder propertyHolder) {
// This operation has to be done after the id definition of the persistence class. // This operation has to be done after the id definition of the persistence class.
// ie after the properties parsing // ie after the properties parsing
Iterator<Object> joinColumns = secondaryTableJoins.values().iterator(); final Iterator<Object> joinColumns = secondaryTableJoins.values().iterator();
for ( Map.Entry<String, Join> entrySet : secondaryTables.entrySet() ) { for ( Map.Entry<String, Join> entrySet : secondaryTables.entrySet() ) {
if ( !secondaryTablesFromAnnotation.containsKey( entrySet.getKey() ) ) { if ( !secondaryTablesFromAnnotation.containsKey( entrySet.getKey() ) ) {
createPrimaryColumnsToSecondaryTable( joinColumns.next(), propertyHolder, entrySet.getValue() ); createPrimaryColumnsToSecondaryTable( joinColumns.next(), propertyHolder, entrySet.getValue() );
@ -1771,56 +1780,52 @@ public class EntityBinder {
? createDefaultJoinColumn( propertyHolder ) ? createDefaultJoinColumn( propertyHolder )
: createJoinColumns( propertyHolder, pkColumnsAnn, joinColumnsAnn ); : createJoinColumns( propertyHolder, pkColumnsAnn, joinColumnsAnn );
for ( AnnotatedJoinColumn joinColumn : annotatedJoinColumns.getColumns() ) { for ( AnnotatedJoinColumn joinColumn : annotatedJoinColumns.getJoinColumns() ) {
joinColumn.forceNotNull(); joinColumn.forceNotNull();
} }
bindJoinToPersistentClass( join, annotatedJoinColumns, context ); bindJoinToPersistentClass( join, annotatedJoinColumns, context );
} }
private AnnotatedJoinColumns createDefaultJoinColumn(PropertyHolder propertyHolder) { private AnnotatedJoinColumns createDefaultJoinColumn(PropertyHolder propertyHolder) {
final AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[1]; final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
annotatedJoinColumns[0] = buildJoinColumn( joinColumns.setBuildingContext( context );
joinColumns.setJoins( secondaryTables );
joinColumns.setPropertyHolder( propertyHolder );
buildJoinColumn(
null, null,
null, null,
persistentClass.getIdentifier(), persistentClass.getIdentifier(),
secondaryTables, joinColumns,
propertyHolder,
context context
); );
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns();
joinColumns.setBuildingContext( context );
joinColumns.setPropertyHolder( propertyHolder );
joinColumns.setColumns( annotatedJoinColumns );
return joinColumns; return joinColumns;
} }
private AnnotatedJoinColumns createJoinColumns( private AnnotatedJoinColumns createJoinColumns(
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
PrimaryKeyJoinColumn[] pkColumnsAnn, PrimaryKeyJoinColumn[] primaryKeyJoinColumns,
JoinColumn[] joinColumnsAnn) { JoinColumn[] joinColumns) {
final int joinColumnCount = pkColumnsAnn != null ? pkColumnsAnn.length : joinColumnsAnn.length; final int joinColumnCount = primaryKeyJoinColumns != null ? primaryKeyJoinColumns.length : joinColumns.length;
if ( joinColumnCount == 0 ) { if ( joinColumnCount == 0 ) {
return createDefaultJoinColumn( propertyHolder ); return createDefaultJoinColumn( propertyHolder );
} }
else { else {
final AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[joinColumnCount]; final AnnotatedJoinColumns columns = new AnnotatedJoinColumns();
for (int colIndex = 0; colIndex < joinColumnCount; colIndex++) { columns.setBuildingContext( context );
final PrimaryKeyJoinColumn pkJoinAnn = pkColumnsAnn != null ? pkColumnsAnn[colIndex] : null; columns.setJoins( secondaryTables );
final JoinColumn joinAnn = joinColumnsAnn != null ? joinColumnsAnn[colIndex] : null; columns.setPropertyHolder( propertyHolder );
annotatedJoinColumns[colIndex] = buildJoinColumn( for ( int colIndex = 0; colIndex < joinColumnCount; colIndex++ ) {
pkJoinAnn, final PrimaryKeyJoinColumn primaryKeyJoinColumn = primaryKeyJoinColumns != null ? primaryKeyJoinColumns[colIndex] : null;
joinAnn, final JoinColumn joinColumn = joinColumns != null ? joinColumns[colIndex] : null;
buildJoinColumn(
primaryKeyJoinColumn,
joinColumn,
persistentClass.getIdentifier(), persistentClass.getIdentifier(),
secondaryTables, columns,
propertyHolder,
context context
); );
} }
final AnnotatedJoinColumns joinColumns = new AnnotatedJoinColumns(); return columns;
joinColumns.setBuildingContext( context );
joinColumns.setPropertyHolder( propertyHolder );
joinColumns.setColumns( annotatedJoinColumns );
return joinColumns;
} }
} }

View File

@ -12,8 +12,6 @@ import java.util.function.Supplier;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.OrderBy; import org.hibernate.annotations.OrderBy;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AnnotatedColumn;
import org.hibernate.cfg.AnnotatedColumns;
import org.hibernate.cfg.CollectionSecondPass; import org.hibernate.cfg.CollectionSecondPass;
import org.hibernate.cfg.PropertyHolder; import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.PropertyHolderBuilder; import org.hibernate.cfg.PropertyHolderBuilder;
@ -86,13 +84,10 @@ public class ListBinder extends CollectionBinder {
if ( !listValueMapping.isOneToMany() ) { if ( !listValueMapping.isOneToMany() ) {
indexColumn.forceNotNull(); indexColumn.forceNotNull();
} }
// indexColumn.setPropertyHolder( valueHolder ); indexColumn.getParent().setPropertyHolder( valueHolder );
final AnnotatedColumns columns = new AnnotatedColumns();
columns.setColumns( new AnnotatedColumn[] { indexColumn } );
columns.setPropertyHolder( valueHolder );
final BasicValueBinder valueBinder = new BasicValueBinder( BasicValueBinder.Kind.LIST_INDEX, buildingContext ); final BasicValueBinder valueBinder = new BasicValueBinder( BasicValueBinder.Kind.LIST_INDEX, buildingContext );
valueBinder.setColumns( columns ); valueBinder.setColumns( indexColumn.getParent() );
valueBinder.setReturnedClassName( Integer.class.getName() ); valueBinder.setReturnedClassName( Integer.class.getName() );
valueBinder.setType( property, getElementType(), null, null ); valueBinder.setType( property, getElementType(), null, null );
// valueBinder.setExplicitType( "integer" ); // valueBinder.setExplicitType( "integer" );

View File

@ -100,8 +100,7 @@ public class MapBinder extends CollectionBinder {
property, property,
isEmbedded, isEmbedded,
mapKeyColumns, mapKeyColumns,
mapKeyManyToManyColumns, mapKeyManyToManyColumns
inverseJoinColumns != null ? inverseJoinColumns.getPropertyName() : null
); );
makeOneToManyMapKeyColumnNullableIfNotInProperty( property ); makeOneToManyMapKeyColumnNullableIfNotInProperty( property );
} }
@ -157,8 +156,7 @@ public class MapBinder extends CollectionBinder {
XProperty property, XProperty property,
boolean isEmbedded, boolean isEmbedded,
AnnotatedColumns mapKeyColumns, AnnotatedColumns mapKeyColumns,
AnnotatedJoinColumns mapKeyManyToManyColumns, AnnotatedJoinColumns mapKeyManyToManyColumns) {
String targetPropertyName) {
if ( mapKeyPropertyName != null ) { if ( mapKeyPropertyName != null ) {
//this is an EJB3 @MapKey //this is an EJB3 @MapKey
handleExplicitMapKey( elementType, persistentClasses, mapKeyPropertyName ); handleExplicitMapKey( elementType, persistentClasses, mapKeyPropertyName );
@ -205,7 +203,7 @@ public class MapBinder extends CollectionBinder {
//FIXME pass the Index Entity JoinColumns //FIXME pass the Index Entity JoinColumns
if ( !collection.isOneToMany() ) { if ( !collection.isOneToMany() ) {
//index column should not be null //index column should not be null
for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getColumns() ) { for ( AnnotatedJoinColumn column : mapKeyManyToManyColumns.getJoinColumns() ) {
column.forceNotNull(); column.forceNotNull();
} }
} }
@ -243,7 +241,7 @@ public class MapBinder extends CollectionBinder {
throw new AnnotationException( "Association '" + safeCollectionRole() throw new AnnotationException( "Association '" + safeCollectionRole()
+ "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" ); + "' targets the type '" + elementType.getName() + "' which is not an '@Entity' type" );
} }
final Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName); final Property mapProperty = findPropertyByName( associatedClass, mapKeyPropertyName );
if ( mapProperty == null ) { if ( mapProperty == null ) {
throw new AnnotationException( "Map key property '" + mapKeyPropertyName throw new AnnotationException( "Map key property '" + mapKeyPropertyName
+ "' not found in target entity '" + associatedClass.getEntityName() + "'" ); + "' not found in target entity '" + associatedClass.getEntityName() + "'" );
@ -274,7 +272,7 @@ public class MapBinder extends CollectionBinder {
// 'propertyHolder' is the PropertyHolder for the owner of the collection // 'propertyHolder' is the PropertyHolder for the owner of the collection
// 'holder' is the CollectionPropertyHolder. // 'holder' is the CollectionPropertyHolder.
// 'property' is the collection XProperty // 'property' is the collection XProperty
propertyHolder.startingProperty(property); propertyHolder.startingProperty( property );
holder.prepare(property); holder.prepare(property);
return holder; return holder;
} }
@ -301,9 +299,9 @@ public class MapBinder extends CollectionBinder {
String mapKeyType, String mapKeyType,
org.hibernate.mapping.Map map) { org.hibernate.mapping.Map map) {
final ManyToOne element; final ManyToOne element;
element = new ManyToOne(context, map.getCollectionTable() ); element = new ManyToOne( context, map.getCollectionTable() );
map.setIndex( element ); map.setIndex( element );
element.setReferencedEntityName(mapKeyType); element.setReferencedEntityName( mapKeyType );
//element.setFetchMode( fetchMode ); //element.setFetchMode( fetchMode );
//element.setLazy( fetchMode != FetchMode.JOIN ); //element.setLazy( fetchMode != FetchMode.JOIN );
//make the second join non lazy //make the second join non lazy
@ -344,11 +342,8 @@ public class MapBinder extends CollectionBinder {
AnnotatedClassType classType, AnnotatedClassType classType,
CollectionPropertyHolder holder, CollectionPropertyHolder holder,
AccessType accessType) { AccessType accessType) {
final Class<? extends CompositeUserType<?>> compositeUserType = resolveCompositeUserType( final Class<? extends CompositeUserType<?>> compositeUserType =
property, resolveCompositeUserType( property, keyClass, buildingContext );
keyClass,
buildingContext
);
if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) { if ( AnnotatedClassType.EMBEDDABLE == classType || compositeUserType != null ) {
final EntityBinder entityBinder = new EntityBinder(); final EntityBinder entityBinder = new EntityBinder();
@ -375,7 +370,7 @@ public class MapBinder extends CollectionBinder {
} }
else { else {
final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext ); final BasicValueBinder elementBinder = new BasicValueBinder( BasicValueBinder.Kind.MAP_KEY, buildingContext );
elementBinder.setReturnedClassName(mapKeyType); elementBinder.setReturnedClassName( mapKeyType );
final AnnotatedColumns keyColumns = createElementColumnsIfNecessary( final AnnotatedColumns keyColumns = createElementColumnsIfNecessary(
collection, collection,
mapKeyColumns, mapKeyColumns,
@ -390,10 +385,10 @@ public class MapBinder extends CollectionBinder {
property, property,
keyClass, keyClass,
collection.getOwnerEntityName(), collection.getOwnerEntityName(),
holder.mapKeyAttributeConverterDescriptor(property, keyClass) holder.mapKeyAttributeConverterDescriptor( property, keyClass )
); );
elementBinder.setPersistentClassName( propertyHolder.getEntityName() ); elementBinder.setPersistentClassName( propertyHolder.getEntityName() );
elementBinder.setAccessType(accessType); elementBinder.setAccessType( accessType );
map.setIndex( elementBinder.make() ); map.setIndex( elementBinder.make() );
} }
} }

View File

@ -8,8 +8,6 @@ package org.hibernate.cfg.annotations;
import jakarta.persistence.NamedEntityGraph; import jakarta.persistence.NamedEntityGraph;
import org.hibernate.internal.util.StringHelper;
import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.StringHelper.isNotEmpty;
/** /**

View File

@ -130,7 +130,7 @@ public class PropertyBinder {
} }
public void setColumns(AnnotatedColumns columns) { public void setColumns(AnnotatedColumns columns) {
final AnnotatedColumn firstColumn = columns.getColumns()[0]; final AnnotatedColumn firstColumn = columns.getColumns().get(0);
insertable = firstColumn.isInsertable(); insertable = firstColumn.isInsertable();
updatable = firstColumn.isUpdatable(); updatable = firstColumn.isUpdatable();
//consistency is checked later when we know the property name //consistency is checked later when we know the property name

View File

@ -548,7 +548,7 @@ public class TableBinder {
associatedClass = holder == null ? null : holder.getPersistentClass(); associatedClass = holder == null ? null : holder.getPersistentClass();
} }
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
if ( joinColumns.hasMappedBy() ) { if ( joinColumns.hasMappedBy() ) {
// use the columns of the property referenced by mappedBy // use the columns of the property referenced by mappedBy
// copy them and link the copy to the actual value // copy them and link the copy to the actual value
@ -592,12 +592,12 @@ public class TableBinder {
SimpleValue value, SimpleValue value,
PersistentClass associatedClass) { PersistentClass associatedClass) {
//implicit case, we hope PK and FK columns are in the same order //implicit case, we hope PK and FK columns are in the same order
if ( joinColumns.getColumns().length != referencedEntity.getIdentifier().getColumnSpan() ) { if ( joinColumns.getColumns().size() != referencedEntity.getIdentifier().getColumnSpan() ) {
// TODO: what about secondary tables?? associatedClass is null? // TODO: what about secondary tables?? associatedClass is null?
throw new AnnotationException( throw new AnnotationException(
"An association that targets entity '" + referencedEntity.getEntityName() "An association that targets entity '" + referencedEntity.getEntityName()
+ "' from entity '" + associatedClass.getEntityName() + "' from entity '" + associatedClass.getEntityName()
+ "' has " + joinColumns.getColumns().length + " '@JoinColumn's but the primary key has " + "' has " + joinColumns.getColumns().size() + " '@JoinColumn's but the primary key has "
+ referencedEntity.getIdentifier().getColumnSpan() + " columns" + referencedEntity.getIdentifier().getColumnSpan() + " columns"
); );
} }
@ -631,7 +631,7 @@ public class TableBinder {
boolean match = false; boolean match = false;
// for each PK column, find the associated FK column. // for each PK column, find the associated FK column.
final String quotedName = column.getQuotedName( dialect ); final String quotedName = column.getQuotedName( dialect );
for ( AnnotatedJoinColumn joinColumn : joinColumns.getColumns() ) { for ( AnnotatedJoinColumn joinColumn : joinColumns.getJoinColumns() ) {
final String referencedColumn = buildingContext.getMetadataCollector() final String referencedColumn = buildingContext.getMetadataCollector()
.getPhysicalColumnName( referencedEntity.getTable(), joinColumn.getReferencedColumn() ); .getPhysicalColumnName( referencedEntity.getTable(), joinColumn.getReferencedColumn() );
// in JPA 2 referencedColumnName is case-insensitive // in JPA 2 referencedColumnName is case-insensitive
@ -704,7 +704,7 @@ public class TableBinder {
? referencedEntity.getKey().getColumns() ? referencedEntity.getKey().getColumns()
: referencedEntity.getIdentifier().getColumns(); : referencedEntity.getIdentifier().getColumns();
for ( Column column: idColumns ) { for ( Column column: idColumns ) {
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
firstColumn.linkValueUsingDefaultColumnNaming( column, referencedEntity, value); firstColumn.linkValueUsingDefaultColumnNaming( column, referencedEntity, value);
firstColumn.overrideFromReferencedColumnIfNecessary( column ); firstColumn.overrideFromReferencedColumnIfNecessary( column );
} }
@ -715,7 +715,7 @@ public class TableBinder {
SimpleValue value, SimpleValue value,
PersistentClass associatedClass, PersistentClass associatedClass,
String mappedByProperty) { String mappedByProperty) {
final AnnotatedJoinColumn firstColumn = joinColumns.getColumns()[0]; final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
for ( Column column: mappedByColumns( associatedClass, mappedByProperty ) ) { for ( Column column: mappedByColumns( associatedClass, mappedByProperty ) ) {
firstColumn.overrideFromReferencedColumnIfNecessary( column ); firstColumn.overrideFromReferencedColumnIfNecessary( column );
firstColumn.linkValueUsingAColumnCopy( column, value); firstColumn.linkValueUsingAColumnCopy( column, value);
@ -744,9 +744,9 @@ public class TableBinder {
AnnotatedJoinColumns joinColumns, AnnotatedJoinColumns joinColumns,
SimpleValue simpleValue) { SimpleValue simpleValue) {
final List<Column> valueColumns = value.getColumns(); final List<Column> valueColumns = value.getColumns();
final AnnotatedJoinColumn[] columns = joinColumns.getColumns(); final List<AnnotatedJoinColumn> columns = joinColumns.getJoinColumns();
for (int i = 0; i < columns.length; i++ ) { for ( int i = 0; i < columns.size(); i++ ) {
final AnnotatedJoinColumn joinColumn = columns[i]; final AnnotatedJoinColumn joinColumn = columns.get(i);
final Column synthCol = valueColumns.get(i); final Column synthCol = valueColumns.get(i);
if ( joinColumn.isNameDeferred() ) { if ( joinColumn.isNameDeferred() ) {
//this has to be the default value //this has to be the default value

View File

@ -24,7 +24,7 @@ public class NullableDiscriminatorColumnSecondPass implements SecondPass {
@Override @Override
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException { public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
PersistentClass rootPersistenceClass = persistentClasses.get( rootEntityName ); final PersistentClass rootPersistenceClass = persistentClasses.get( rootEntityName );
if ( hasNullDiscriminatorValue( rootPersistenceClass ) ) { if ( hasNullDiscriminatorValue( rootPersistenceClass ) ) {
for ( Selectable selectable: rootPersistenceClass.getDiscriminator().getSelectables() ) { for ( Selectable selectable: rootPersistenceClass.getDiscriminator().getSelectables() ) {
if ( selectable instanceof Column ) { if ( selectable instanceof Column ) {

View File

@ -106,7 +106,7 @@ public class SqlExceptionHelper {
*/ */
public JDBCException convert(SQLException sqlException, String message, String sql) { public JDBCException convert(SQLException sqlException, String message, String sql) {
logExceptions( sqlException, message + " [" + sql + "]" ); logExceptions( sqlException, message + " [" + sql + "]" );
return sqlExceptionConverter.convert( sqlException, message, sql ); return sqlExceptionConverter.convert( sqlException, message + " [" + sqlException.getMessage() + "]", sql );
} }
/** /**

View File

@ -26,7 +26,7 @@ public class BankAccount {
@GeneratedValue @GeneratedValue
private long id; private long id;
@OneToMany(mappedBy = "account", cascade = { CascadeType.ALL }) @OneToMany(mappedBy = "account", cascade = CascadeType.ALL)
@OrderColumn(name = "transactions_index") @OrderColumn(name = "transactions_index")
private List<Transaction> transactions; private List<Transaction> transactions;