Matt Follett

Grails/DatabaseMigrationPlugin/Liquibase Quirk

I just fought with this for a while and figured I’d record this in the vast internets in case others come across this. While attempting to extend the functionality of our Grails project at work I needed to add a new table and related foreign key constraints. We use the Grails Database Migration Plugin which uses liquibase to keep our schema in sync between production, staging, and development boxes. I declared a foreign key constraint similar to this one:

addForeignKeyConstraint(
baseColumnNames: 'column_name,
baseTableSchemaName: 'my_schema',
baseTableName: 'my_table',
constraintName: 'my_constraint_name',
deferrable: 'false',
initiallyDeferred: 'false',
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
referencedTableName: 'referenced_table',
referencedColumnNames: 'my_referenced_column',
referencedTableSchemaName: 'my_schema',
referencesUniqueColumn: 'true',
)
view raw gistfile1.txt hosted with ❤ by GitHub

and got this exception:

2012-01-25 15:53:13,963 [Thread-12] ERROR context.GrailsContextLoader - Error executing bootstraps: liquibase.exception.ValidationFailedException: Validation Failed:
1 changes have validation errors
java.lang.ClassCastException: liquibase.statement.core.AddForeignKeyConstraintStatement cannot be cast to liquibase.statement.core.CreateTableStatement
org.codehaus.groovy.runtime.InvokerInvocationException: liquibase.exception.ValidationFailedException: Validation Failed:
1 changes have validation errors
java.lang.ClassCastException: liquibase.statement.core.AddForeignKeyConstraintStatement cannot be cast to liquibase.statement.core.CreateTableStatement
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:97)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:884)
at groovy.lang.Closure.call(Closure.java:410)
at DatabaseMigrationGrailsPlugin$_closure2.call(DatabaseMigrationGrailsPlugin.groovy)
at org.codehaus.groovy.grails.plugins.DefaultGrailsPlugin.doWithApplicationContext(DefaultGrailsPlugin.java:489)
at org.codehaus.groovy.grails.plugins.AbstractGrailsPluginManager.doPostProcessing(AbstractGrailsPluginManager.java:169)
at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.performPostProcessing(GrailsRuntimeConfigurator.java:232)
at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.configure(GrailsRuntimeConfigurator.java:172)
at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.configure(GrailsRuntimeConfigurator.java:124)
at org.codehaus.groovy.grails.web.context.GrailsConfigUtils.configureWebApplicationContext(GrailsConfigUtils.java:121)
at org.codehaus.groovy.grails.web.context.GrailsContextLoader.initWebApplicationContext(GrailsContextLoader.java:104)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4723)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Caused by: liquibase.exception.ValidationFailedException: Validation Failed:
1 changes have validation errors
java.lang.ClassCastException: liquibase.statement.core.AddForeignKeyConstraintStatement cannot be cast to liquibase.statement.core.CreateTableStatement
at liquibase.changelog.DatabaseChangeLog.validate(DatabaseChangeLog.java:138)
at liquibase.Liquibase.update(Liquibase.java:110)
at liquibase.Liquibase$update.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at grails.plugin.databasemigration.MigrationRunner$_autoRun_closure1.doCall(MigrationRunner.groovy:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:226)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at grails.plugin.databasemigration.MigrationRunner$_autoRun_closure1.doCall(MigrationRunner.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1054)
at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:884)
at groovy.lang.Closure.call(Closure.java:410)
at grails.plugin.databasemigration.MigrationRunner$_autoRun_closure1.call(MigrationRunner.groovy)
at groovy.lang.Closure.call(Closure.java:404)
at grails.plugin.databasemigration.MigrationRunner$_autoRun_closure1.call(MigrationRunner.groovy)
at java_util_concurrent_Callable$call.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at grails.plugin.databasemigration.MigrationUtils.executeInSession(MigrationUtils.groovy:99)
at grails.plugin.databasemigration.MigrationUtils$executeInSession.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at grails.plugin.databasemigration.MigrationRunner.autoRun(MigrationRunner.groovy:46)
at grails.plugin.databasemigration.MigrationRunner$autoRun.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at DatabaseMigrationGrailsPlugin$_closure2.doCall(DatabaseMigrationGrailsPlugin.groovy:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1231)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
... 21 more
view raw gistfile1.txt hosted with ❤ by GitHub

It turns out that passing in a named parameter of referencesUniqueColumn with a value of anything other than false causes this exception. This wasn’t immediately obvious to me and I still don’t know why, but I thought I’d note it in case someone else ran into it too.