hibernate Custom Physical Naming Strategy


Example

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")