38

I have database fields in underscore. I have entity fields in camelcase. I can't change either of those.

Is there something, maybe a class level annotation I can use to default entity column name annotations to the camelcase equivalent?

for example, I have an entity like this:

@Entity
public class AuthorisationEntity {

    @Column(name = "non_recoverable")
    private BigDecimal nonRecoverable;

    @Column(name = "supplier_recoverable")
    private BigDecimal supplierRecoverable;

    @Column(name = "refund_amount")
    private BigDecimal refundAmount;

}

I dream of this:

@Entity
@DatabaseIsUnderscoreAndThisAnnotationConvertsThemToCamelCaseByDefault
public class AuthorisationEntity {

    private BigDecimal nonRecoverable;

    private BigDecimal supplierRecoverable;

    private BigDecimal refundAmount;

}
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
Paul Stanley
  • 4,018
  • 6
  • 35
  • 56
  • 6
    I can't find the class `@DatabaseIsUnderscoreAndThisAnnotationConvertsThemToCamelCaseByDefault` ... Just kidding, but I really wanted to paste this to my friend. :) – Kenny Cason Nov 07 '16 at 23:37

5 Answers5

21

You can achieve this using a custom Hibernate naming strategy.

All you need to do is to use the hibernate-types open-source project.

Hibernate 5.2 or later

You need to add the following Maven dependency:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

And set the following Hibernate configuration property:

<property name="hibernate.physical_naming_strategy"
          value="com.vladmihalcea.hibernate.type.util.CamelCaseToSnakeCaseNamingStrategy"
/>

Hibernate 5.0 and 5.1

You need to add the following Maven dependency:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-5</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

And set the following Hibernate configuration property:

<property name="hibernate.physical_naming_strategy"
          value="com.vladmihalcea.hibernate.type.util.CamelCaseToSnakeCaseNamingStrategy"
/>

Hibernate 4.3

You need to add the following Maven dependency:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-43</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

And set the following Hibernate configuration property:

<property name="hibernate.ejb.naming_strategy"
          value="com.vladmihalcea.hibernate.type.util.CamelCaseToSnakeCaseNamingStrategy"
/>

Hibernate 4.2 and 4.1

You need to add the following Maven dependency:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-4</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

And set the following Hibernate configuration property:

<property name="hibernate.ejb.naming_strategy"
          value="com.vladmihalcea.hibernate.type.util.CamelCaseToSnakeCaseNamingStrategy"
/>

Testing time

Assuming you have the following entities:

@Entity(name = "BookAuthor")
public class BookAuthor {
 
    @Id
    private Long id;
 
    private String firstName;
 
    private String lastName;
 
    //Getters and setters omitted for brevity
}
 
@Entity(name = "PaperBackBook")
public class PaperBackBook {
 
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE
    )
    private Long id;
 
    @NaturalId
    private String ISBN;
 
    private String title;
 
    private LocalDate publishedOn;
 
    @ManyToOne(fetch = FetchType.LAZY)
    private BookAuthor publishedBy;
 
    //Getters and setters omitted for brevity
}

When using the CamelCaseToSnakeCaseNamingStrategy custom naming strategy, Hibernate is going to generate the following database schema using the hbm2ddl tool:

CREATE SEQUENCE hibernate_sequence
START WITH 1 INCREMENT BY 1
 
CREATE TABLE book_author (
    id          BIGINT NOT NULL,
    first_name  VARCHAR(255),
    last_name   VARCHAR(255),
    PRIMARY KEY (id)
)
 
CREATE TABLE paper_back_book (
    id              BIGINT NOT NULL,
    isbn            VARCHAR(255),
    published_on    DATE, 
    title           VARCHAR(255),
    published_by_id BIGINT, 
    PRIMARY KEY (id)
)

Cool, right?

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • 1
    Two shots of whiskey to this gentleman! This finally fixes snake case naming strategy for hibernate 5! – AbstractVoid Mar 12 '19 at 18:29
  • This is not working. Do you have any idea what it could be? `javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet`. I am using the `implementation("com.vladmihalcea", "hibernate-types-52","2.10.0")` and I put the property in the `hibernate.cfg` – Braian Coronel Oct 14 '20 at 01:04
  • You can find plenty of test cases on GitHub that prove it works. Compare my tests to yours to see where they differ – Vlad Mihalcea Oct 14 '20 at 04:59
  • hibernate-types is awesome! I'm using it for Postgres extensions support. – mokaymakci Mar 31 '21 at 13:18
  • I'm glad you liked it. – Vlad Mihalcea Mar 31 '21 at 13:40
16

You can use hibernate's naming strategy. Such naming strategy class describes how to generate database names for given java names.

See:

naming strategy example

second example

very good oracle naming strategy - it converts camel to underscore convention, and much more

przemek hertel
  • 3,924
  • 1
  • 19
  • 27
5

I was experiencing the same problem in a Spring boot application, I tried adding the above Hibernate config to the spring properties file with no success, added it as a java bean, again with no success.

I am using Hibernate Properties object, adding the hibernate configuration within this solved my issue:

    protected Properties buildHibernateProperties() {
        Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
        hibernateProperties.setProperty("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());

        return hibernateProperties;
    }
Leroy
  • 430
  • 8
  • 12
2

From Hibernate 5.5.4.Final, CamelCaseToUnderscoresNamingStrategy has been introduced, the new strategy is the equivalent of the Spring SpringPhysicalNamingStrategy.

The CamelCaseToUnderscoresNamingStrategy replaces all dots with underscores, all camel casing with underscores and generates all table names in lower case.

For example, the LineItem entity will be mapped to the line_item table.

SANN3
  • 9,459
  • 6
  • 61
  • 97
1
import org.hibernate.cfg.DefaultNamingStrategy;
import org.hibernate.cfg.ImprovedNamingStrategy;

public class NamingStratagyTest {
    public static void main(String[] args) {
        String colName = DefaultNamingStrategy.INSTANCE.columnName("UserName");
        System.out.println(colName); // UserName
        colName = ImprovedNamingStrategy.INSTANCE.columnName("UserName");
        System.out.println(colName);// user_name
    }
}

There you go, choose the naming strategy that suits your need.

Paul Stanley
  • 4,018
  • 6
  • 35
  • 56
zawhtut
  • 8,335
  • 5
  • 52
  • 76