Skip to content

Commit 5b7fe61

Browse files
committed
HHH-16516 rework CamelCaseToUnderscoresNamingStrategy and handle quoted identifiers
1 parent b6ee791 commit 5b7fe61

File tree

4 files changed

+52
-52
lines changed

4 files changed

+52
-52
lines changed

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

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,84 +8,78 @@
88

99
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
1010

11+
import static java.lang.Character.isDigit;
12+
import static java.lang.Character.isLowerCase;
13+
import static java.lang.Character.isUpperCase;
14+
1115
/**
12-
* Originally copied from Spring Boot as this strategy is popular there
13-
* (original name is SpringPhysicalNamingStrategy).
16+
* Converts {@code camelCase} or {@code MixedCase} logical names to {@code snake_case}.
1417
*
1518
* @author Phillip Webb
1619
* @author Madhura Bhave
1720
*/
21+
// Originally copied from Spring's SpringPhysicalNamingStrategy as this strategy is popular there.
1822
public class CamelCaseToUnderscoresNamingStrategy implements PhysicalNamingStrategy {
1923

2024
@Override
2125
public Identifier toPhysicalCatalogName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
22-
return apply( logicalName, jdbcEnvironment );
26+
return apply( logicalName );
2327
}
2428

2529
@Override
2630
public Identifier toPhysicalSchemaName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
27-
return apply( logicalName, jdbcEnvironment );
31+
return apply( logicalName );
2832
}
2933

3034
@Override
3135
public Identifier toPhysicalTableName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
32-
return apply( logicalName, jdbcEnvironment );
36+
return apply( logicalName );
3337
}
3438

3539
@Override
3640
public Identifier toPhysicalSequenceName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
37-
return apply( logicalName, jdbcEnvironment );
41+
return apply( logicalName );
3842
}
3943

4044
@Override
4145
public Identifier toPhysicalColumnName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
42-
return apply( logicalName, jdbcEnvironment );
46+
return apply( logicalName );
4347
}
4448

45-
private Identifier apply(final Identifier name, final JdbcEnvironment jdbcEnvironment) {
49+
private Identifier apply(final Identifier name) {
4650
if ( name == null ) {
4751
return null;
4852
}
49-
StringBuilder builder = new StringBuilder( name.getText().replace( '.', '_' ) );
53+
else if ( name.isQuoted() ) {
54+
return quotedIdentifier( name );
55+
}
56+
else {
57+
return unquotedIdentifier( name );
58+
}
59+
}
60+
61+
private String camelCaseToSnakeCase(String name) {
62+
final StringBuilder builder = new StringBuilder( name.replace( '.', '_' ) );
5063
for ( int i = 1; i < builder.length() - 1; i++ ) {
5164
if ( isUnderscoreRequired( builder.charAt( i - 1 ), builder.charAt( i ), builder.charAt( i + 1 ) ) ) {
5265
builder.insert( i++, '_' );
5366
}
5467
}
55-
return getIdentifier( builder.toString(), name.isQuoted(), jdbcEnvironment );
68+
return builder.toString();
5669
}
5770

58-
/**
59-
* Get an identifier for the specified details. By default this method will return an identifier
60-
* with the name adapted based on the result of {@link #isCaseInsensitive(JdbcEnvironment)}
61-
*
62-
* @param name the name of the identifier
63-
* @param quoted if the identifier is quoted
64-
* @param jdbcEnvironment the JDBC environment
65-
*
66-
* @return an identifier instance
67-
*/
68-
protected Identifier getIdentifier(String name, final boolean quoted, final JdbcEnvironment jdbcEnvironment) {
69-
if ( isCaseInsensitive( jdbcEnvironment ) ) {
70-
name = name.toLowerCase( Locale.ROOT );
71-
}
72-
return new Identifier( name, quoted );
71+
protected Identifier unquotedIdentifier(Identifier name) {
72+
return new Identifier( camelCaseToSnakeCase( name.getText() ).toLowerCase( Locale.ROOT ) );
7373
}
7474

75-
/**
76-
* Specify whether the database is case sensitive.
77-
*
78-
* @param jdbcEnvironment the JDBC environment which can be used to determine case
79-
*
80-
* @return true if the database is case insensitive sensitivity
81-
*/
82-
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
83-
return true;
75+
protected Identifier quotedIdentifier(Identifier quotedName) {
76+
return quotedName;
8477
}
8578

8679
private boolean isUnderscoreRequired(final char before, final char current, final char after) {
87-
return ( Character.isLowerCase( before ) || Character.isDigit( before ) ) && Character.isUpperCase( current ) && ( Character.isLowerCase(
88-
after ) || Character.isDigit( after ) );
80+
return ( isLowerCase( before ) || isDigit( before ) )
81+
&& isUpperCase( current )
82+
&& ( isLowerCase( after ) || isDigit( after ) );
8983
}
9084

9185
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public Identifier determinePrimaryTableName(ImplicitEntityNameSource source) {
3636
throw new HibernateException( "Entity naming information was not provided." );
3737
}
3838

39-
String tableName = transformEntityName( source.getEntityNaming() );
39+
final String tableName = transformEntityName( source.getEntityNaming() );
4040

4141
if ( tableName == null ) {
4242
// todo : add info to error message - but how to know what to write since we failed to interpret the naming source
@@ -136,9 +136,9 @@ public Identifier determineJoinColumnName(ImplicitJoinColumnNameSource source) {
136136

137137
// todo : we need to better account for "referencing relationship property"
138138

139-
final String name;
139+
final String referencedColumnName = source.getReferencedColumnName().getText();
140140

141-
String referencedColumnName = source.getReferencedColumnName().getText();
141+
final String name;
142142
if ( source.getNature() == ELEMENT_COLLECTION
143143
|| source.getAttributePath() == null ) {
144144
name = transformEntityName( source.getEntityNaming() )

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/namingstrategy/CamelCaseToUnderscoresNamingStrategyTest.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
*/
55
package org.hibernate.orm.test.annotations.namingstrategy;
66

7+
import jakarta.persistence.Column;
78
import org.hibernate.boot.Metadata;
89
import org.hibernate.boot.MetadataSources;
910
import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy;
1011
import org.hibernate.cfg.Environment;
1112
import org.hibernate.mapping.PersistentClass;
12-
import org.hibernate.mapping.Selectable;
1313
import org.hibernate.service.ServiceRegistry;
1414

1515
import org.hibernate.testing.ServiceRegistryBuilder;
@@ -56,23 +56,27 @@ public void testWithWordWithDigitNamingStrategy() throws Exception {
5656
PersistentClass entityBinding = metadata.getEntityBinding( B.class.getName() );
5757
assertEquals(
5858
"word_with_digit_d1",
59-
( (Selectable) entityBinding.getProperty( "wordWithDigitD1" ).getSelectables().get( 0 ) ).getText()
59+
entityBinding.getProperty( "wordWithDigitD1" ).getSelectables().get( 0 ).getText()
6060
);
6161
assertEquals(
6262
"abcd_efgh_i21",
63-
( (Selectable) entityBinding.getProperty( "AbcdEfghI21" ).getSelectables().get( 0 ) ).getText()
63+
entityBinding.getProperty( "AbcdEfghI21" ).getSelectables().get( 0 ).getText()
6464
);
6565
assertEquals(
6666
"hello1",
67-
( (Selectable) entityBinding.getProperty( "hello1" ).getSelectables().get( 0 ) ).getText()
67+
entityBinding.getProperty( "hello1" ).getSelectables().get( 0 ).getText()
6868
);
6969
assertEquals(
7070
"hello1_d2",
71-
( (Selectable) entityBinding.getProperty( "hello1D2" ).getSelectables().get( 0 ) ).getText()
71+
entityBinding.getProperty( "hello1D2" ).getSelectables().get( 0 ).getText()
7272
);
7373
assertEquals(
7474
"hello3d4",
75-
( (Selectable) entityBinding.getProperty( "hello3d4" ).getSelectables().get( 0 ) ).getText()
75+
entityBinding.getProperty( "hello3d4" ).getSelectables().get( 0 ).getText()
76+
);
77+
assertEquals(
78+
"Quoted-ColumnName",
79+
entityBinding.getProperty( "quoted" ).getSelectables().get( 0 ).getText()
7680
);
7781
}
7882

@@ -85,6 +89,8 @@ class B implements java.io.Serializable {
8589
protected String hello1;
8690
protected String hello1D2;
8791
protected String hello3d4;
92+
@Column(name = "\"Quoted-ColumnName\"")
93+
protected String quoted;
8894

8995
public String getAbcdEfghI21() {
9096
return AbcdEfghI21;

hibernate-core/src/test/java/org/hibernate/orm/test/namingstrategy/ejb3joincolumn/PhysicalNamingStrategyImpl.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
99
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
1010

11+
import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
12+
1113
/**
1214
* @author Anton Wimmer
1315
* @author Steve Ebersole
@@ -20,19 +22,17 @@ public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardIm
2022

2123
@Override
2224
public Identifier toPhysicalTableName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
23-
return Identifier.toIdentifier(makeCleanIdentifier("tbl_" + logicalName.getText()), logicalName.isQuoted());
25+
return toIdentifier( makeCleanIdentifier("tbl_" + logicalName.getText()), logicalName.isQuoted() );
2426
}
2527

2628
@Override
2729
public Identifier toPhysicalColumnName(Identifier logicalName, JdbcEnvironment jdbcEnvironment) {
28-
if ( logicalName.getText().equals("DTYPE") ) {
29-
return logicalName;
30-
}
31-
32-
return Identifier.toIdentifier(makeCleanIdentifier("c_" + logicalName.getText()), logicalName.isQuoted());
30+
return logicalName.getText().equals( "DTYPE" )
31+
? logicalName
32+
: toIdentifier( makeCleanIdentifier( "c_" + logicalName.getText() ), logicalName.isQuoted() );
3333
}
3434

3535
private String makeCleanIdentifier(String s) {
36-
return s.substring(0, Math.min(s.length(), 63)).toLowerCase();
36+
return s.substring( 0, Math.min(s.length(), 63) ).toLowerCase();
3737
}
3838
}

0 commit comments

Comments
 (0)