32

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
  • 103,297
  • 39
  • 432
  • 788
Paul Stanley
  • 3,695
  • 6
  • 30
  • 49
  • 4
    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

4 Answers4

16

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
  • 103,297
  • 39
  • 432
  • 788
  • 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
15

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,604
  • 1
  • 17
  • 24
3

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
  • 165
  • 1
  • 10
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
  • 3,695
  • 6
  • 30
  • 49
zawhtut
  • 7,841
  • 5
  • 46
  • 72