Earlier in the ant file, I set my base.classpath to the lib directory which contains hibernate.jar, all the database drivers and liquibase.
The updateDatabase depends on compile, which compiles my custom change and places it in ${basedir}/foo/bin. I have verified that the compiled class file is present. In the updateDatase, I set my classpath composed of the base.classpath and ${basedir}/foo/bin. The classpath is printed out and contains ${basedir}/foo/bin.
I did a little bit of debugging in CustomChangeWrapper.setClass.
public void setClass(String className) throws CustomChangeException {
....
try {
try {
Object o = Class.forName(className, true, classLoader).newInstance();
System.out.println("*** o = " + o.toString());
System.out.println("***class = " + o.getClass().getCanonicalName());
System.out.println("o is an instance of CustomSqlChange: " + CustomSqlChange.class.isInstance(o));
System.out.println("o is an instance of CustomChange: " + CustomChange.class.isInstance(o));
customChange = (CustomChange)o;
} catch (ClassCastException e) { //fails in Ant in particular
...
When I recompile and run this updated jar, my output is:
[updateDatabase] *** o = com.example.MyExample@3f6843
[updateDatabase] ***class = com.example.MyExample
[updateDatabase] o is an instance of CustomSqlChange: false
[updateDatabase] o is an instance of CustomChange: false
So the first Class.forName actually loads something that is of the correct class. Yet for some bizarre reason it doesn’t think it is an instance of CustomSQLChange or its parent CustomChange. Thus the class cast exception, which forces it to try the other two methods of loading the class. Neither of those are able to load it, resulting in the ClassNotFoundException.
This is weird, because if I add a little reflection code to see the interfaces on o, it returns CustomSqlChange. Which is correct, it does implement CustomSqlChange.
I think I found a possible work around. I know my team mates are not going to like it though.
Running ant with the “-lib” option, such as
ant -lib c:/dir/where/liqubase.jar/is/located redoDB
produces the following debugging output:
[updateDatabase] ***class = com.example.MyExample
[updateDatabase] o is an instance of CustomSqlChange: true
[updateDatabase] o is an instance of CustomChange: true
So it seems like some issue where ant classloader doesn’t find the liquibase.jar. It is part of my classpath defined in ant though.
I’m using 2.0 and it looks like I’ve also hit this problem when trying to use custom change (and in trying to resolve the issue all my searching has brought me here !). I’ve created a class called ‘Show’ which implements CustomSqlChange and compiled it. My liquibase changeset is as follows :-
When I run liquibase (directly , not via ANT) I get :-
INFO 03/04/13 10:03:liquibase: Successfully released change log lock Liquibase Update Failed: java.lang.ClassNotFoundException: Show SEVERE 03/04/13 10:03:liquibase: java.lang.ClassNotFoundException: Show liquibase.exception.ChangeLogParseException: Invalid Migration File: java.lang.C lassNotFoundException: Show at liquibase.parser.core.xml.XMLChangeLogSAXParser.parse(XMLChangeLogSAX Parser.java:132) at liquibase.parser.core.xml.XMLChangeLogSAXHandler.handleIncludedChange Log(XMLChangeLogSAXHandler.java:504) at liquibase.parser.core.xml.XMLChangeLogSAXHandler.startElement(XMLChan geLogSAXHandler.java:143) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startEle ment(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser. emptyElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.emptyEl ement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scan StartElement(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImp l$FragmentContentDriver.next(Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(U nknown Source) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next (Unknown Source) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImp l.scanDocument(Unknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(U nknown Source) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(U nknown Source) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown So urce) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Un known Source) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.p arse(Unknown Source) at liquibase.parser.core.xml.XMLChangeLogSAXParser.parse(XMLChangeLogSAX Parser.java:98) at liquibase.Liquibase.update(Liquibase.java:107) at liquibase.integration.commandline.Main.doMigration(Main.java:825) at liquibase.integration.commandline.Main.main(Main.java:134) Caused by: org.xml.sax.SAXException: java.lang.ClassNotFoundException: Show liquibase.exception.CustomChangeException: java.lang.ClassNotFoundException: Show
Any advice on how to resolve this would be appreciated.