Liquibase + Hibernate 5 + Envers + Spring Boot Naming Conventions

Posted on March 15, 2018
Tags: gradle, java, jpa

Starting with a project using Spring Boot 1.5.8 and Hibernate 5.2.12 I implemented Liquibase to handle database schema changes. This is all straight forward enough, with plenty of other tutorials of how to setup the runtime side.

The schema diff generation side was another matter. The issues hit was that the identifier names were not correct - Spring Boot would produce underscore versions of names, e.g., my_table, while Liquibase would produce names as per the class or field name, e.g., MyTable. To get around this I could specify the actual table or column names in the @Table or @Column annotations. However, this was not going to work when we put Envers into the mix.

Envers automatically produces a revision table REVINFO, and changelog tables for each table which are normally suffixed with _AUD. However, Spring Boot wanted the lowercase version of these names, but Liquibase wanted to make the uppercase version, and while I could override the changelog tables by passing the relevant Envers property via system parameters, the revision table name is hard coded.

The problem is caused because Liquibase wasn’t setup with the same naming strategies as Spring Boot has. It was being called from a Gradle JavaExec task. Unfortunately it was based on a slightly naive template which didn’t pass in the relevant naming strategies in the referenceUrl. The key is hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy

Unfortunately, there are few results that really explain what is going on given the issues I was seeing, but I do note that the JHipster project generator does exactly this, so I’d suggest using it to generate a project and inspect it for a better example.

For reference, this the basic task:

task liquibaseDiffChangelog(type: JavaExec) {
    group = "liquibase"

    classpath sourceSets.main.runtimeClasspath
    classpath configurations.liquibase
    main = "liquibase.integration.commandline.Main"

    args "--changeLogFile=" + buildTimestamp() +"_changelog.groovy"
    args "--referenceUrl=hibernate:spring:org.nigelsim.springbootproject?dialect=org.hibernate.dialect.MySQLDialect&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy"
    args "--username=${config.spring.datasource.username}"
    args "--password=${config.spring.datasource.password}"
    args "--url=${config.spring.datasource.url}"
    args "--driver=${config.spring.datasource['driver-class-name']}"
    args "diffChangeLog"
}