ClassNotFoundException from Ant task 'updateDatabase'

ClassNotFoundException from Ant task ‘updateDatabase’ if its classpathref differs from classpath used to load the Ant tasks:

Hello Nathan,

if I want to load my own database implementation (which extends H2Database) from Ant task ‘updateDatabase’ I get a ClassNotFoundException.
Running the Debugger I see that my own database implementation is loaded and my constructor is properly executed,
but then there is a ClassCastException when my class is cast to class ‘liquibase.database.Database’.

The following patch solves the problem:

Index: src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java

— src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java (revision 1837)
+++ src/main/java/liquibase/integration/ant/BaseLiquibaseTask.java (working copy)
@@ -191,7 +191,7 @@

        URLClassLoader loader = AccessController.doPrivileged(new PrivilegedAction() {
            public URLClassLoader run() {
-                return new URLClassLoader(taskClassPath.toArray(new URL[taskClassPath.size()]));
+                return new URLClassLoader(taskClassPath.toArray(new URL[taskClassPath.size()]), Database.class.getClassLoader());
            }
        });

I assume that the
    try … catch (ClassCastException e) { //fails in Ant in particular
which follows seven lines below can be omitted
if the patch is applied.

Some background info:

With
   
I load all the Ant task definitions.
The ‘classpathWithLiquibase’ does not contain my own database implementation.

If I call the Ant task ‘updateDatabase’ I set the classpathref to an extended classpath,
which also contains my own database implementation.
But in spite of setting the classpathref correctly I get the ClassNotFoundException which is really a ClassCastException thrown before.

If I load the Ant task definition with the extended classpath (which also contains my own database implementation)
there is no problem - I don’t get the ClassNotFoundException.

I assume that without the patch the following takes place:

When the URLClassLoader is loading my own database implementation it must load the base class ‘Database’ first.
If it loads this class by itself, this class may be incompatible to the already loaded Database class, because that class is loaded by another ClassLoader.

(Still I am using RC6. I have seen RC7 only now, sorry. But I think there is no change which concerns the patch above.)

Best regards,
Markus M�ller

It seems there are some more problems with the classloader if running ant scripts…
These problems now appeared when I made tests with other databases than our H2 implementation (Oracle, MSSQL, …).

So far I can say that all is working good if I load the ant task definitions with the full classpath:
   
The ‘full.classpath’ includes liquibase, all required jars and all of our specific implementations.
Our specific implementations include slight extensions of …Database, …TypeConverter and …DatabaseSnapshotGenerator classes.
Our extensions provide for case sensitive table and column names, amongst others.

If I load the ant task definitions from a classpath without our specific implementations, I get errors:
ClassNotFoundExceptions or our specific implementations are not applied -
in spite of that I pass the name of the full classpath as attribute classpathref of the ant task ‘updateDatabase’.

Kind regards,
Markus M�ller

Thanks for the patch and the troubleshooting.  I applied your patch for the next release, it looks like it at will at least help, even if it doesn’t completely solve the problem.

I’ll look into it more after the 2.0 release, since it sounds like it is possible to get the extensions working correctly.

Could I ask what your experience making extensions has been?  What has been difficult, what easy?  Has it been flexible enough for your needs?  Any suggestions, especially around documentation?

Nathan