The Cliftonian

Not as newsy as the name implies…

Liquibase 2.0.3 with Maven, Hibernate 3.5.6, and JPA Annotations

with 2 comments

Here’s what I wanted:  I wanted Liquibase to generate my database change logs automatically from my updated Hibernate/JPA annotated classes.  I wanted to use Maven tasks, not the command line utility to accomplish this.  That way I could leverage maven profiles and not have to worry about writing scripts and worrying about classpaths and everything else.  Problem after problem came up and it’s obvious the developer, while very responsive on the internet had not made Maven or hibernate his top priority.  It just wasn’t his main use case.  Also, the documentation, while good, was out of date and didn’t cover much of the new changes from 2.0.0 on.  So I pieced together a configuration that worked and accomplished my stated goals.

Getting Started

Here’s my persistence.xml file in src/main/resources/META-INF.  All of my hibernate entities are annotated using JPA annotations and are detected automatically.  I do not want to have to explicitly detail every entity in a config file.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
 version="2.0">
    <persistence-unit name="persistenceUnit"
 transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <validation-mode>NONE</validation-mode>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
            <property name="hibernate.hbm2ddl.auto" value="validate" />
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />

 <!-- Hibernate Envers -->
            <property name="hibernate.ejb.event.post-insert"
 value="org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.post-update"
 value="org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.post-delete"
 value="org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.pre-collection-update"
 value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.pre-collection-remove"
 value="org.hibernate.envers.event.AuditEventListener" />
            <property name="hibernate.ejb.event.post-collection-recreate"
 value="org.hibernate.envers.event.AuditEventListener" />
        </properties>
    </persistence-unit>
</persistence>

Configuring the Maven plugin.

There are a couple of things to note in this configuration.  First, you’ll note that I am using version 2.0.3 of the plugin, which at this time is the most recent version. I have, however, built on my own liquibase-hibernate dependency from the latest “liquibase:master branch” from the liquibase-hibernate project which you can access here.  It contains a pull request from user rlamarche which enables the use of a persistence.xml for JPA annotation classes.  You can read about the details here.  Very useful and I’m sure this step will not be necessary once a new version is released.

Secondly, you need your dependencies specified as a plugin dependencies, even if you have them already as regular “compile” or “test” scope build dependencies.  This wasn’t clear from the documentation as none of the examples contained dependency information and it sounded like anything available during the test phase would also be available to the plugin.

While we’re talking about dependencies, you should note that liquibase-hibernate pulls in liquibase-core and liquibase-maven-plugin v2.0.0 instead of 2.0.3.  That’s why I’ve explicitly included them as dependencies.

liquibase-hibernate also by default depends on hibernate core 3.2.6.ga, hibernate annotations 3.3.1.ga and javax.persistence 2.0.0.  I’ve included the 3.5.6 version of the hibernate classes since that’s what we’re using.  I also included the Hibernate Envers jar because we use that too. Good news, this example also produces the audit tables necessary for envers.

I also included slf4j dependencies.  With out them, it complained about missing classes. Also included is Apache Derby.  Even though I am very clear about using MySQL, there’s a warning that shows up if this isn’t on the dependency list.

I enabled logging and set verbose to true to aid in troubleshooting with the <verbose>true</verbose> and <logging>debug</logging> tags.  Also you can run the maven command (mvn liquibase:diff) with the -e and/or the -X flag to enable maven debugging and see stacktraces from the liquibase plugin.

<plugin>
     <groupId>org.liquibase</groupId>
     <artifactId>liquibase-maven-plugin</artifactId>
     <version>2.0.3</version>
     <configuration>
         <changeLogFile>src/main/resources/db/migration/changelog-master.xml</changeLogFile>
         <diffChangeLogFile>src/main/resources/db/migration/changelog-${project.version}.xml</diffChangeLogFile>
         <driver>${database.driver}</driver>
         <url>${database.url}</url>
         <defaultSchemaName>${database.schema}</defaultSchemaName>
         <username>${database.username}</username>
         <password>${database.password}</password>
         <referenceUrl>persistence:persistenceUnit</referenceUrl>
         <verbose>true</verbose>
         <logging>debug</logging>
     </configuration>
     <dependencies>
         <dependency>
             <groupId>org.liquibase.ext</groupId>
             <artifactId>liquibase-hibernate</artifactId>
             <version>2.0.3-MODIFIED</version>
         </dependency>
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-annotations</artifactId>
             <version>${hibernate.version}</version>
         </dependency>
         <dependency>
             <groupId>org.hibernate</groupId>
             <artifactId>hibernate-core</artifactId>
             <version>${hibernate.version}</version>
         </dependency>
     <dependency>
         <groupId>org.hibernate</groupId>
         <artifactId>hibernate-envers</artifactId>
         <version>${hibernate.version}</version>
     </dependency>
     <dependency>
         <groupId>javax.persistence</groupId>
         <artifactId>com.springsource.javax.persistence</artifactId>
         <version>2.0.0</version>
     </dependency>
     <!-- Logging -->
     <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.6.4</version>
     </dependency>
     <dependency>
         <groupId>org.apache.derby</groupId>
         <artifactId>derby</artifactId>
         <version>10.8.2.2</version>
     </dependency>
     </dependencies>
 </plugin>

Changelog Files

You need a master changeLog.xml file (src/main/resources/db/migration/changelog-master.xml).  This is what controls which changelog files are run during an update.

<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog 
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd" >
    <include file="db/migration/changelog-sql-1_0.sql"/>
</databaseChangeLog>

I include my starting file which is a MySql backup dump using MySql Admin (changelog-sql-1_0.sql) in the changelog-master file.

--liquibase formatted sql

--changeset ceaton:1
CREATE DATABASE IF NOT EXISTS mydb;
USE mydb;
CREATE TABLE `MYDB`.`SOME_TABLE` (...

Running liquibase:diff

To run the diff plugin and generate the changelog file for inclusion in your master changelog file, run

mvn liquibase:diff

I also pass a profile on the command line using the -P flag to tell maven which profile to run.  That way I can run this agains any of our environments for which we’ve created a profile.  This generates the changelog file in the location you specified in the <diffChangeLogFile /> tag.  Don’t forget to disable the hbm2ddl.auto property in your persistence.xml file as this is a direct replacement to Hibernate’s schema generation.

Note: Looking at the liquibase-hibernate docs, you might not even know there was a liquibase:diff maven goal.  Here’s some better documentation on the plugin, goals, and configs: http://site.kuali.org/db/liquibase/2.0.2/liquibase-maven-plugin/plugin-info.html

Advertisements

Written by Clifton

April 5, 2012 at 7:28 pm

2 Responses

Subscribe to comments with RSS.

  1. eagecl, how are you?

    Where did you get this dependency? what is the repository?

    org.liquibase.ext
    liquibase-hibernate
    2.0.3-MODIFIED

    Thank’s

    Hussama Ismail

    May 16, 2012 at 9:41 pm

    • I built this from the most recent version of liquibase-hibernate and published it to a private nexus repository. Here’s the part of the article where I explain how I did that:

      “I have, however, built on my own liquibase-hibernate dependency from the latest “liquibase:master branch” from the liquibase-hibernate project which you can access here.  It contains a pull request from user rlamarche which enables the use of a persistence.xml for JPA annotation classes.  You can read about the details here.”

      eagecl

      May 17, 2012 at 11:41 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: