liquibase javaconfig


I would be interested in using java class files for configuring liquibase instead of xml. A bit like spring javaconfig can replace spring xml.

The main advantage would be the ability to run java code inside a changeset. And possibly using the java compiler to ensure correct syntax…

Has anybody looked into this or thought about this?

I checked out the trunk and will start experimenting in this direction. From what I see, I could implement a new ChangeLogParser which would receive a classname or package name as physical location and either load the class directly or use some kind of classpath scanning to find the changesets.

A class implementing a given interface could be a changeset which would return the list of changes, etc.
Maybe annotations could provide the metadata such as dependencies between changesets, preconditions. Or maybe methods on the interface.

I’m only beginning to think about this and wanted to see if others had any idea about that.


It should work very well to do.  One of the major points of the 2.0 release is to allow changelogs in any format.  Depending on what you want, you may be able to skip the ChangeLogParsers completely if you are already working in Java.  If you have your java classes create *Change objects directly  and add them to your ChangeSet and DatabaseChangeLog objects, them simply pass the DatabaseChangeLog object to liquibase.Liquibase. 

The documentation on the 2.0 code isn’t all there yet, but let me know if you have any questions.


I started yesterday and in about 1 hour, I had 60% (the easy part) done.

Overall I like that liquibase is designed to be extensible, it was very easy to add the basic functionality.

I like the idea of implementing a ChangeLogParser since I would like to use the spring bean to seamlessly parse either XML or Java files. Only problem though is that parser matching occurs on file extensions, so currently I mapped it to .class, but this implies that I specify a full java class including the .class. I’ll start looking around for other solutions as I would really like to be able to specify a package and then load the classes in that package (classpath scanning) and apply all classes in that package as changesets.

Another obstacle is that the Change interface returns SQLStatements, so I might not be able to have it execute java code afterall. A use case for running javacode might be that you have a user table with passwords stored in clear. But you want to change it to hashed passwords with a random salt. You would need to add a column for the salt and hash the passwords appropriately. The clean solution for me would be to have liquibase do the whole conversion process so that the code doesn’t have to check for the old password format all the time.

Maybe a Change could be something more general than SQLstatements and an abstract class SQLChange (or adapter class SQLChange -> Change) would allows subclasses to return SQLStatements. I hope this is clear…

In any case, I’m not asking for these changes formally as I’m still considering the design, but I wanted to say that you did a great job with this project.


Glad it’s working for you so far.  You are right that the ChangeLogParser may work better for you.  I was thinking of adding an additional check that the changeLog parsers can use where they can inspect the contents of the file to determine if they are a valid parser for it.  It may allow you to try reading in the class file and checking what it implements etc.

We do allow custom liquibase changes in the standard xml changelog files where you pass the class you want to execute at runtime.  I’ve used that in the past for the exact encryption issue you mentioned.  Yesterday I added a liquibase.statement.core.RuntimeStatement class that you can return subclasses of, where you do your java code in the generate() method and can return “new Sql[0]” if there is no additional SQL to run, or a set of Sql objects to be executed, depending on your implementation.

I’m still thinking through if I like the name, or if there should be a different class hierarchy there, but it should be very close to what is in the final 2.0 version.