Naming Strategies in Hibernate 5

JPA and Hibernate provide a default mapping that maps each entity class to a database table with the same name. Each of its attributes gets mapped to a column with the same. But what if you want to change this default, e.g., because it doesn’t match your company’s naming conventions?

You can, of course, specify the table name for each entity and the column name for each attribute. That requires a @Table annotation on each class and a @Column annotation on each attribute. This is called explicit naming.

That’s a good approach if you want to change the mapping for one attribute. But doing that for lots of attributes requires a lot of work. Adapting Hibernate’s naming strategy is then often a better approach.

In this article, I will show you how to use it to adjust the mapping of all entities and attributes. But before we do that, we first need to talk about the difference between Hibernate’s logical and physical naming strategy.

A 2-step approach

Hibernate splits the mapping of the entity or attribute name to the table or column name into 2 steps:

  1. It first determines the logical name of an entity or attribute. You can explicitly set the logical name using the @Table and @Column annotations. If you don’t do that, Hibernate will use one of its implicit naming strategies.
  2. It then maps the logical name to a physical name. By default, Hibernate uses the logical name as the physical name. But you can also implement a PhysicalNamingStrategy that maps the logical name to a physical one that follows your internal naming convention. Or, since Hibernate 5.5.4, you can activate Hibernate’s CamelCaseToUnderscoresNamingStrategy.

So, why does Hibernate differentiate between a logical and a physical naming strategy, but the JPA specification doesn’t?

JPA’s approach works, but if you take a closer look at it, you recognize that Hibernate’s approach provides more flexibility. By splitting the process into 2 steps, Hibernate allows you to implement a conversion that gets applied to all attributes and classes.

If your naming conventions, for example, require you to ad “_TBL” to all table names, you can do that in your PhysicalNamingStrategy. It then doesn’t matter if you explicitly specify the table name in a @Table annotation or if you do it implicitly based on the entity name. In both cases, Hibernate will add “_TBL” to the end of your table name.

Because of the added flexibility, I like Hibernate’s approach a little better.

Logical naming strategy

As explained earlier, you can either define the logical name explicitly or implicitly. Let’s take a look at both options.

Explicit naming strategy

The explicit naming strategy is very easy to use. You probably already used it yourself. The only thing you need to do is annotate your entity class with @Table or your entity attribute with @Column and provide your preferred name as a value to the name attribute.

@Entity
@Table(name = "AUTHORS")
public class Author {

    @Column(name = "author_name")
    private String name;

    ...
}

If you then use this entity in your code and activate the logging of SQL statements, you can see that Hibernate uses the provided names instead of the default ones.

15:55:52,525 DEBUG [org.hibernate.SQL] - insert into AUTHORS (author_name, version, id) values (?, ?, ?)

Implicit naming strategy

If you don’t set the table or column name in an annotation, Hibernate uses one of its implicit naming strategies. You can choose between 4 different naming strategies and 1 default strategy:

  • default
    By default, Hibernate uses the implicit naming strategy defined by the JPA specification. This value is an alias for jpa.
  • jpa
    This is the naming strategy defined by the JPA 2.0 specification.
    The logical name of an entity class is either the name provided in the @Entity annotation or the unqualified class name. For basic attributes, it uses the name of the attributes as the logical name. To get the logical name of a join column of an association, this strategy concatenates the name of the referencing attribute, an “_” and the name of the primary key attribute of the referenced entity. The logical name of a join column of an element collection consists of the name of the entity that owns the association, an “_” and the name of the primary key attribute of the referenced entity. And the logical name of a join table starts with the physical name of the owning table, followed by an “_” and the physical name of the referencing table.
  • legacy-hbm
    This is Hibernate’s original naming strategy. It doesn’t recognize any of JPA’s annotations. But you can use Hibernate’s proprietary configuration file and annotations to define a column or entity name.
    In addition to that, there are a few other differences to the JPA specification:
    • The logical name of a join column is only its attribute name.
    • For join tables, this strategy concatenates the name of the physical table that owns the association, an “_” and the name of the attribute that owns the association.
  • legacy-jpa
    The legacy-jpa strategy implements the naming strategy defined by JPA 1.0.
    The main differences to the jpa strategy are:
    • The logical name of a join table consists of the physical table name of the owning side of the association, an “_” and either the physical name of the referencing side of the association or the owning attribute of the association.
    • To get the logical name of the join column of an element collection, the legacy-jpa strategy uses the physical table name instead of the entity name of the referenced side of the association. That means the logical name of the join column consists of the physical table name of the referenced side of the association, an “_” and the name of the referenced primary key column.
  • component-path
    This strategy is almost identical to the jpa strategy. The only difference is that it includes the name of the composite in the logical attribute name.

You can configure the logical naming strategy by setting the hibernate.implicit_naming_strategy attribute in your configuration.

<persistence>
    <persistence-unit name="naming">
        ...
        <properties>
            <property name="hibernate.implicit_naming_strategy"
                      value="jpa" />
            ...
        </properties>
    </persistence-unit>
</persistence>

Physical naming strategy

As mentioned earlier, Hibernate’s default physical naming strategy uses the logical name without changing it. So, whatever the logic name is, it will also be the name of the database table or column.

If you prefer a different mapping, you can define a custom strategy. I will show you how to do that later in this article. But before that, I want to show you the CamelCaseToUnderscoresNamingStrategy that was introduced in Hibernate 5.5.4. It replicates the mapping used by Spring Boot’s SpringPhysicalNamingStrategy.

CamelCaseToUnderscoresNamingStrategy in Hibernate >5.5.4

Spring’s SpringPhysicalNamingStrategy has become very popular. It not only gets used by default in Spring Boot applications, but many developers also started to apply it to non-Spring projects. It replaces all dots and camel casing with underscores and generates all tables names in lower case.

Activating Hibernate’s CamelCaseToUnderscoresNamingStrategy

The Hibernate team replicated that mapping strategy in the CamelCaseToUnderscoresNamingStrategy. Since Hibernate 5.5.4.Final, you can activate this strategy by setting the configuration property hibernate.physical_naming_strategy in your persistence.xml file to org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy.

<persistence>
    <persistence-unit name="my-persistence-unit">
        ...

        <properties>
            ...
			
            <property name="hibernate.physical_naming_strategy"
                      value="org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy"/>
        </properties>
    </persistence-unit>
</persistence>

Using Hibernate’s CamelCaseToUnderscoresNamingStrategy

We need an entity class name in camel case to show this strategy in all details. Because of that, I’m using the ChessPlayer entity instead of the Author entity you saw in previous examples.

@Entity
public class ChessPlayer {

	@Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "player_seq")
    @SequenceGenerator(name = "player_seq", sequenceName = "player_seq", initialValue = 100)
	private Long id;

    private String firstName;
    
    private String lastName;

    private LocalDate birthDate;

    @OneToMany(mappedBy = "playerWhite")
    private Set<ChessGame> gamesWhite;

    @OneToMany(mappedBy = "playerBlack")
    private Set<ChessGame> gamesBlack;

    @Version
    private int version;
	
	...
	
}

As you can see in the code snippet, I don’t define any logical names for the entity class and its attributes. By default, Hibernate then uses the Java class’s name and the names of each of its attributes as their logical names.

Hibernate’s CamelCaseToUnderscoresNamingStrategy physical naming strategy replaces all dots and camel casing with underscores and changes the logical class name to lower case. Based on this mapping, the ChessGame entity class gets mapped to the chess_game table. And the attributes firstName, lastName, and birthDate get mapped to the columns first_name, last_name, and birth_date.

You can see that when I persist a new ChessGame entity object.

19:27:25,995 DEBUG SQL:144 - select chessplaye0_.id as id1_1_0_, chessplaye0_.birth_date as birth_da2_1_0_, chessplaye0_.first_name as first_na3_1_0_, chessplaye0_.last_name as last_nam4_1_0_, chessplaye0_.version as version5_1_0_ from chess_player chessplaye0_ where chessplaye0_.id=?

Implementing a custom physical naming strategy

If none of Hibernate’s physical naming strategies fulfill your requirements, you can implement your own strategy. Doing that isn’t complicated. You can either implement the PhysicalNamingStrategy interface or extend Hibernate’s PhysicalNamingStrategyStandardImpl class.

I extend Hibernate’s PhysicalNamingStrategyStandardImpl in the following example to create a naming strategy that adds the postfix “_TBL” to each table name And in the 2nd example, we will define a naming strategy that converts camel case names into snake case.

Table postfix strategy

The only thing I want to change in this naming strategy is the handing of the table name. Extending Hibernate’s PhysicalNamingStrategyStandardImpl class is the easiest way to achieve that.

Implementing a custom strategy

I overwrite the toPhysicalTableName method, add a static postfix to the name, and convert it into an Identifier.

public class TablePostfixPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {

    private final static String POSTFIX = "_TBL";
    
    @Override
    public Identifier toPhysicalTableName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
        if (identifier == null) {
            return null;
        }

        final String newName = identifier.getText() + POSTFIX;
        return Identifier.toIdentifier(newName);
    }

}

In the next step, you need to activate the naming strategy. You do that by setting the hibernate.physical_naming_strategy attribute to the fully qualified class name of the strategy.

<persistence>
    <persistence-unit name="naming">
        ...
        <properties>
            <property name="hibernate.physical_naming_strategy"
                      value="org.thoughtsonjava.naming.config.TablePostfixPhysicalNamingStrategy" />
            ...
        </properties>
    </persistence-unit>
</persistence>
Using the table postfix strategy

Let’s try this mapping using this basic Author entity. I don’t specify a logical name for the entity. So, it defaults to the name of the class, which is Author. Without our custom naming strategy, Hibernate would map this entity to the Author table.

@Entity
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Version
    private int version;

    private String name;

    @ManyToMany(mappedBy = "authors", fetch = FetchType.LAZY)
    private Set<Book> books;

    ...
}

When I persist this entity, you can see in the log file that Hibernate mapped it to the AUTHOR_TBL table.

14:05:56,619 DEBUG [org.hibernate.SQL] - insert into Author_TBL (name, version, id) values (?, ?, ?)

Names in snake case instead of camel case

In Java, we prefer to use camel case for our class and attribute names. By default, Hibernate uses the logical name as the physical name. So, the entity attribute LocalDate publishingDate gets mapped to the database column publishingDate.

Some companies use naming conventions that require you to use snake case for your table and column names. That means that your publishingDate attribute needs to be mapped to the publishing_date column.

As explained earlier, you could use the explicit naming strategy and annotate each attribute with a @Column annotation. But for most persistence layers, that’s a lot of work, and it’s easy to forget.

So, let’s implement a naming strategy that does that for us.

Implementing a custom strategy
public class SnakeCasePhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {

    @Override
    public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) {
        return super.toPhysicalCatalogName(toSnakeCase(name), context);
    }

    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
        return super.toPhysicalColumnName(toSnakeCase(name), context);
    }

    @Override
    public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {
        return super.toPhysicalSchemaName(toSnakeCase(name), context);
    }

    @Override
    public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) {
        return super.toPhysicalSequenceName(toSnakeCase(name), context);
    }

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        return super.toPhysicalTableName(toSnakeCase(name), context);
    }
    
    private Identifier toSnakeCase(Identifier id) {
        if (id == null)
            return id;
            
        String name = id.getText();
        String snakeName = name.replaceAll("([a-z]+)([A-Z]+)", "$1\\_$2").toLowerCase();
        if (!snakeName.equals(name))
            return new Identifier(snakeName, id.isQuoted());
        else
            return id;
    }
}

The interesting part of this naming strategy is the toSnakeCase method. I call it in all methods that return a physical name to convert the provided name to snake case.

If you’re familiar with regular expressions, the implementation of the toSnakeCase method is pretty simple. By calling replaceAll(“([a-z]+)([A-Z]+)”, “$1\\_$2”), we add an “_” in front of each capital letter. After that is done, we only need to change all characters to lower case.

In the next step, we need to set the strategy in the persistence.xml file.

<persistence>
    <persistence-unit name="naming">
        ...
        <properties>
            <property name="hibernate.physical_naming_strategy"
                      value="org.thoughtsonjava.naming.config.SnakeCasePhysicalNamingStrategy" />
            ...
        </properties>
    </persistence-unit>
</persistence>
Using the snake case strategy

When I now persist this Book entity, Hibernate will use the custom strategy to map the publishingDate attribute to the database column publishing_date.

@Entity
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    @Version
    private int version;

    private String title;

    private LocalDate publishingDate;

    @ManyToMany
    private Set<Author> authors;

    @ManyToOne
    private Publisher publisher;

    ...
}

As you can see in the log file, the naming strategy worked as expected and changed the name of the publishingDate column to publishing_date.

14:28:59,337 DEBUG [org.hibernate.SQL] - insert into books (publisher_id, publishing_date, title, version, id) values (?, ?, ?, ?, ?)

Conclusion

Hibernate’s naming strategy provides you with lots of flexibility. It consists of 2 parts, the mapping of the logical and the physical name.

You can explicitly define the logical name using the @Table and @Column annotation. If you don’t do that, Hibernate uses one of its implicit naming strategies. The default one is compliant with JPA 2.0.

After the logical name got determined, Hibernate applies a physical naming strategy. By default, it returns the logical name. Since version 5.5.4, Hibernate also offers the CamelCaseToUnderscoresNamingStrategy. It replaces all dots and camel casing with underscores and generates all tables names in lower case. And you can also implement your own physical naming strategy. Most teams use this to apply a naming convention to all logical entity and attribute names. As you have seen in the examples, this provides an easy way to fulfill your internal naming conventions.

Related Articles

Responses

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  1. Thank you for every time you release an article.
    Your website Thoughts on Java is very helpful and valuable.
    you always give us information for free.
    For more this course help all of you a lot.

  2. Really useful, i have been in the pain to use @Column(name = “name”) for all the attributes. Thanks for sharing the knowledge.

    1. Yes, changing every column mapping to follow some naming conventions can get really annoying.
      Happy to help 🙂