Skip to content

Commit e093b68

Browse files
committed
HHH-19484 make it easier to customize constraint name generation in ImplicitNamingStrategyJpaCompliantImpl
1 parent 530285f commit e093b68

9 files changed

+186
-93
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,11 @@ private void createIndexOrUniqueKey(
159159
String[] columnNames,
160160
String[] orderings,
161161
boolean unique,
162+
boolean declaredAsIndex,
162163
String options,
163164
Selectable[] columns) {
164165
final IndexOrUniqueKeyNameSource source =
165-
new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName );
166+
new IndexOrUniqueKeyNameSource( context, table, columnNames, originalKeyName, declaredAsIndex );
166167
boolean hasFormula = false;
167168
for ( Selectable selectable : columns ) {
168169
if ( selectable.isFormula() ) {
@@ -218,6 +219,7 @@ void bindIndexes(Table table, jakarta.persistence.Index[] indexes) {
218219
columnExpressions,
219220
ordering,
220221
unique,
222+
true,
221223
options,
222224
selectables( table, name, columnExpressions )
223225
);
@@ -236,6 +238,7 @@ void bindUniqueConstraints(Table table, UniqueConstraint[] constraints) {
236238
columnNames,
237239
null,
238240
true,
241+
false,
239242
options,
240243
columns( table, name, columnNames )
241244
);
@@ -261,17 +264,32 @@ else if ( tmp.endsWith( " asc" ) ) {
261264
}
262265
}
263266

264-
private class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource {
267+
private class IndexOrUniqueKeyNameSource
268+
implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource {
265269
private final MetadataBuildingContext buildingContext;
266270
private final Table table;
267271
private final String[] columnNames;
268272
private final String originalKeyName;
273+
private final boolean declaredAsIndex;
269274

270-
public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) {
275+
private IndexOrUniqueKeyNameSource(
276+
MetadataBuildingContext buildingContext,
277+
Table table,
278+
String[] columnNames,
279+
String originalKeyName,
280+
boolean declaredAsIndex) {
271281
this.buildingContext = buildingContext;
272282
this.table = table;
273283
this.columnNames = columnNames;
274284
this.originalKeyName = originalKeyName;
285+
this.declaredAsIndex = declaredAsIndex;
286+
}
287+
288+
@Override
289+
public Kind kind() {
290+
return declaredAsIndex
291+
? ImplicitIndexNameSource.super.kind()
292+
: ImplicitUniqueKeyNameSource.super.kind();
275293
}
276294

277295
@Override

hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitConstraintNameSource.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,17 @@
1111
*
1212
* @author Steve Ebersole
1313
*/
14-
public interface ImplicitConstraintNameSource extends ImplicitNameSource {
14+
public sealed interface ImplicitConstraintNameSource
15+
extends ImplicitNameSource
16+
permits ImplicitIndexNameSource, ImplicitUniqueKeyNameSource, ImplicitForeignKeyNameSource {
1517
Identifier getTableName();
1618
List<Identifier> getColumnNames();
1719
Identifier getUserProvidedIdentifier();
20+
Kind kind();
21+
22+
enum Kind {
23+
FOREIGN_KEY,
24+
UNIQUE_KEY,
25+
INDEX
26+
}
1827
}

hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitForeignKeyNameSource.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@
99
/**
1010
* @author Steve Ebersole
1111
*/
12-
public interface ImplicitForeignKeyNameSource extends ImplicitConstraintNameSource {
12+
public non-sealed interface ImplicitForeignKeyNameSource
13+
extends ImplicitConstraintNameSource {
1314
Identifier getReferencedTableName();
1415
List<Identifier> getReferencedColumnNames();
16+
17+
@Override
18+
default Kind kind() {
19+
return Kind.FOREIGN_KEY;
20+
}
1521
}

hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitIndexNameSource.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,10 @@
77
/**
88
* @author Steve Ebersole
99
*/
10-
public interface ImplicitIndexNameSource extends ImplicitConstraintNameSource {
10+
public non-sealed interface ImplicitIndexNameSource
11+
extends ImplicitConstraintNameSource {
12+
@Override
13+
default Kind kind() {
14+
return Kind.INDEX;
15+
}
1116
}

hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java

Lines changed: 100 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.hibernate.HibernateException;
1010
import org.hibernate.boot.model.source.spi.AttributePath;
1111
import org.hibernate.boot.spi.MetadataBuildingContext;
12+
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
1213

1314
import static org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION;
1415
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
@@ -92,17 +93,19 @@ public Identifier determineIdentifierColumnName(ImplicitIdentifierColumnNameSour
9293

9394
@Override
9495
public Identifier determineDiscriminatorColumnName(ImplicitDiscriminatorColumnNameSource source) {
96+
final MetadataBuildingContext context = source.getBuildingContext();
9597
return toIdentifier(
96-
source.getBuildingContext().getEffectiveDefaults().getDefaultDiscriminatorColumnName(),
97-
source.getBuildingContext()
98+
context.getEffectiveDefaults().getDefaultDiscriminatorColumnName(),
99+
context
98100
);
99101
}
100102

101103
@Override
102104
public Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource source) {
105+
final MetadataBuildingContext context = source.getBuildingContext();
103106
return toIdentifier(
104-
source.getBuildingContext().getEffectiveDefaults().getDefaultTenantIdColumnName(),
105-
source.getBuildingContext()
107+
context.getEffectiveDefaults().getDefaultTenantIdColumnName(),
108+
context
106109
);
107110
}
108111

@@ -113,7 +116,10 @@ public Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource s
113116
*/
114117
@Override
115118
public Identifier determineBasicColumnName(ImplicitBasicColumnNameSource source) {
116-
return toIdentifier( transformAttributePath( source.getAttributePath() ), source.getBuildingContext() );
119+
return toIdentifier(
120+
transformAttributePath( source.getAttributePath() ),
121+
source.getBuildingContext()
122+
);
117123
}
118124

119125
/**
@@ -152,25 +158,24 @@ public Identifier determinePrimaryKeyJoinColumnName(ImplicitPrimaryKeyJoinColumn
152158

153159
@Override
154160
public Identifier determineAnyDiscriminatorColumnName(ImplicitAnyDiscriminatorColumnNameSource source) {
155-
final MetadataBuildingContext buildingContext = source.getBuildingContext();
161+
final MetadataBuildingContext context = source.getBuildingContext();
156162
return toIdentifier(
157163
transformAttributePath( source.getAttributePath() )
158-
+ "_" + buildingContext.getEffectiveDefaults().getDefaultDiscriminatorColumnName(),
159-
buildingContext
164+
+ "_" + context.getEffectiveDefaults().getDefaultDiscriminatorColumnName(),
165+
context
160166
);
161167
}
162168

163169
@Override
164170
public Identifier determineAnyKeyColumnName(ImplicitAnyKeyColumnNameSource source) {
165-
final MetadataBuildingContext buildingContext = source.getBuildingContext();
171+
final MetadataBuildingContext context = source.getBuildingContext();
166172
return toIdentifier(
167173
transformAttributePath( source.getAttributePath() )
168-
+ "_" + buildingContext.getEffectiveDefaults().getDefaultIdColumnName(),
169-
buildingContext
174+
+ "_" + context.getEffectiveDefaults().getDefaultIdColumnName(),
175+
context
170176
);
171177
}
172178

173-
174179
@Override
175180
public Identifier determineMapKeyColumnName(ImplicitMapKeyColumnNameSource source) {
176181
return toIdentifier(
@@ -190,35 +195,25 @@ public Identifier determineListIndexColumnName(ImplicitIndexColumnNameSource sou
190195
@Override
191196
public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) {
192197
final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier();
193-
final MetadataBuildingContext buildingContext = source.getBuildingContext();
194-
return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier(
195-
NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() )
196-
.generateHashedFkName( "FK", source.getTableName(),
197-
source.getReferencedTableName(), source.getColumnNames() ),
198-
buildingContext
199-
);
198+
return userProvidedIdentifier == null
199+
? generateConstraintName( source )
200+
: userProvidedIdentifier;
200201
}
201202

202203
@Override
203204
public Identifier determineUniqueKeyName(ImplicitUniqueKeyNameSource source) {
204205
final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier();
205-
final MetadataBuildingContext buildingContext = source.getBuildingContext();
206-
return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier(
207-
NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() )
208-
.generateHashedConstraintName( "UK", source.getTableName(), source.getColumnNames() ),
209-
buildingContext
210-
);
206+
return userProvidedIdentifier == null
207+
? generateConstraintName( source )
208+
: userProvidedIdentifier;
211209
}
212210

213211
@Override
214212
public Identifier determineIndexName(ImplicitIndexNameSource source) {
215213
final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier();
216-
final MetadataBuildingContext buildingContext = source.getBuildingContext();
217-
return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier(
218-
NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() )
219-
.generateHashedConstraintName( "IDX", source.getTableName(), source.getColumnNames() ),
220-
buildingContext
221-
);
214+
return userProvidedIdentifier == null
215+
? generateConstraintName( source )
216+
: userProvidedIdentifier;
222217
}
223218

224219
/**
@@ -235,18 +230,85 @@ protected String transformAttributePath(AttributePath attributePath) {
235230
}
236231

237232
/**
238-
* Easy hook to build an Identifier using the keyword safe IdentifierHelper.
233+
* Easy hook to build an {@link Identifier} using the keyword safe
234+
* {@link org.hibernate.engine.jdbc.env.spi.IdentifierHelper}.
239235
*
240236
* @param stringForm The String form of the name
241-
* @param buildingContext Access to the IdentifierHelper
237+
* @param buildingContext Access to the {@code IdentifierHelper}
242238
*
243239
* @return The identifier
244240
*/
245241
protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) {
246-
return buildingContext.getMetadataCollector()
247-
.getDatabase()
248-
.getJdbcEnvironment()
249-
.getIdentifierHelper()
250-
.toIdentifier( stringForm );
242+
return toIdentifier( stringForm,
243+
buildingContext.getMetadataCollector()
244+
.getDatabase()
245+
.getJdbcEnvironment()
246+
.getIdentifierHelper() );
247+
}
248+
249+
/**
250+
* Easy hook to build an {@link Identifier} using the keyword safe
251+
* {@link org.hibernate.engine.jdbc.env.spi.IdentifierHelper}.
252+
*
253+
* @param stringForm The String form of the name
254+
* @param identifierHelper The {@code IdentifierHelper}
255+
*
256+
* @return The identifier
257+
*/
258+
protected Identifier toIdentifier(String stringForm, IdentifierHelper identifierHelper) {
259+
return identifierHelper.toIdentifier( stringForm );
260+
}
261+
262+
/**
263+
* Generate a name for the given constraint.
264+
*
265+
* @return The identifier
266+
*/
267+
protected Identifier generateConstraintName(ImplicitConstraintNameSource source) {
268+
return toIdentifier( generateConstraintNameString( source ), source.getBuildingContext() );
269+
}
270+
271+
/**
272+
* Generate a name for the given constraint.
273+
*
274+
* @return The name as a string
275+
*/
276+
protected String generateConstraintNameString(ImplicitConstraintNameSource source) {
277+
final NamingHelper namingHelper = namingHelper( source.getBuildingContext() );
278+
final String prefix = constraintNamePrefix( source.kind() );
279+
return source instanceof ImplicitForeignKeyNameSource foreignKeySource
280+
? namingHelper.generateHashedFkName(
281+
prefix,
282+
source.getTableName(),
283+
// include the referenced table in the hash
284+
foreignKeySource.getReferencedTableName(),
285+
source.getColumnNames()
286+
)
287+
: namingHelper.generateHashedConstraintName(
288+
prefix,
289+
source.getTableName(),
290+
source.getColumnNames()
291+
);
292+
}
293+
294+
/**
295+
* Obtain a {@link NamingHelper} for use in constraint name generation.
296+
*/
297+
protected NamingHelper namingHelper(MetadataBuildingContext context) {
298+
return NamingHelper.withCharset( context.getBuildingOptions().getSchemaCharset() );
299+
}
300+
301+
/**
302+
* The prefix for a generated constraint name of the given
303+
* {@linkplain ImplicitConstraintNameSource.Kind kind}.
304+
*
305+
* @return The prefix as a string
306+
*/
307+
protected String constraintNamePrefix(ImplicitConstraintNameSource.Kind kind) {
308+
return switch ( kind ) {
309+
case INDEX -> "IDX";
310+
case UNIQUE_KEY -> "UK";
311+
case FOREIGN_KEY -> "FK";
312+
};
251313
}
252314
}

hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyLegacyHbmImpl.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55
package org.hibernate.boot.model.naming;
66

7-
import org.hibernate.internal.util.StringHelper;
7+
import static org.hibernate.internal.util.StringHelper.unqualify;
88

99
/**
1010
* Implements the original legacy naming behavior.
@@ -19,7 +19,7 @@ public class ImplicitNamingStrategyLegacyHbmImpl extends ImplicitNamingStrategyJ
1919

2020
@Override
2121
protected String transformEntityName(EntityNaming entityNaming) {
22-
return StringHelper.unqualify( entityNaming.getEntityName() );
22+
return unqualify( entityNaming.getEntityName() );
2323
}
2424

2525
@Override
@@ -37,21 +37,21 @@ public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) {
3737
source.getBuildingContext()
3838
);
3939
}
40-
41-
return super.determineJoinColumnName( source );
40+
else {
41+
return super.determineJoinColumnName( source );
42+
}
4243
}
4344

44-
4545
@Override
4646
public Identifier determineJoinTableName(ImplicitJoinTableNameSource source) {
4747
if ( source.getAssociationOwningAttributePath() != null ) {
4848
final String name = source.getOwningPhysicalTableName()
4949
+ '_'
5050
+ transformAttributePath( source.getAssociationOwningAttributePath() );
51-
5251
return toIdentifier( name, source.getBuildingContext() );
5352
}
54-
55-
return super.determineJoinTableName( source );
53+
else {
54+
return super.determineJoinTableName( source );
55+
}
5656
}
5757
}

0 commit comments

Comments
 (0)