When mapping our entities to database table names we rely on a @Table
annotation. But if we have a naming convention for our database table names, we can implement a custom physical naming strategy in order to tell hibernate to calculate table names based on the names of the entities, without explicitly stating those names with @Table
annotation. Same goes for attributes and columns mapping.
For example, our entity name is:
ApplicationEventLog
And our table name is:
application_event_log
Our Physical naming strategy needs to convert from entity names that are camel case to our db table names which are snake case. We can achieve this by extending hibernate's PhysicalNamingStrategyStandardImpl
:
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl {
private static final long serialVersionUID = 1L;
public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(addUnderscores(name.getText()), name.isQuoted());
}
protected static String addUnderscores(String name) {
final StringBuilder buf = new StringBuilder(name);
for (int i = 1; i < buf.length() - 1; i++) {
if (Character.isLowerCase(buf.charAt(i - 1)) &&
Character.isUpperCase(buf.charAt(i)) &&
Character.isLowerCase(buf.charAt(i + 1))) {
buf.insert(i++, '_');
}
}
return buf.toString().toLowerCase(Locale.ROOT);
}
}
We are overriding default behavior of methods toPhysicalTableName
and toPhysicalColumnName
to apply our db naming convention.
In order to use our custom implementation we need to define hibernate.physical_naming_strategy
property and give it the name of our PhysicalNamingStrategyImpl
class.
hibernate.physical_naming_strategy=com.example.foo.bar.PhysicalNamingStrategyImpl
This way we can alleviate our code from @Table
and @Column
annotations, so our entity class:
@Entity
public class ApplicationEventLog {
private Date startTimestamp;
private String logUser;
private Integer eventSuccess;
@Column(name="finish_dtl")
private String finishDetails;
}
will be correctly be mapped to db table:
CREATE TABLE application_event_log (
...
start_timestamp timestamp,
log_user varchar(255),
event_success int(11),
finish_dtl varchar(2000),
...
)
As seen in the example above, we can still explicitly state the name of the db object if it is not, for some reason, in accordance with our general naming convention:
@Column(name="finish_dtl")