[jdom-interest] ClassCastException
bob mcwhirter
bob at werken.com
Wed Jun 26 22:24:23 PDT 2002
On Wed, 26 Jun 2002, Elliotte Rusty Harold wrote:
> I'm continuing to investigate and there's something really weird
> going on here. build test behaves as normal. However, "build testui"
> results in a version of org.apache.xerces.parsers.SAXParser getting
> loaded which is *not* an instanceof XMLReader. However, if I run
> "build test" then the org.apache.xerces.parsers.SAXParser loaded is
> an instanceof XMLReader. Curiouser and curiouser. Possibly the JUnit
> UI classes or Swing classes use an earlier, pre-XMLReader version of
> org.apache.xerces.parsers.SAXParser? So far I can't explain this.
Whoa boy...
Welcome to how I've spent my last two weeks, fighting Ant's wacky
classloader psychosis, particular with regards to xml parsers and JUnit.
Boils down to roughly...
1) The classloader for ant itself requires the parser interfaces
since ant itself uses XML.
2) When ant spawns a <junit> task, it creates an isolationary
classloader for everything within the junit task, allowing
very few things to load from the parent-loader (notably,
java.*, javax.*, and junit.* load from the parent).
3) So, a test-case may require a parser, which gets loaded
from the isolationary <junit> classloader. It implements
an interface tagging it as an xml parser, and this interface
is also loaded from the isolationary classloader.
4) Due to the way classloading works, and folks usage of
Class.forName(String name), there's a mixup between the
parser interface loaded from ant's own classloader and
the exact same interface loaded from the isolationary
classloader created specifically for junit.
5) Since in java, 2 classes with the same name, signature, etc
loaded from different classloaders are -not- the same class
and are not assignable/castable to each other.
6) Thus, the seemingly odd ClassCastException where it complains
that you are attempting to cast a Foo to a Foo, which is apparently
illegal. It doesn't tell you that the two Foo's involved come
from different classloaders.
One solution is a small set of hacks called commons-grant from
the jakarta project:
http://jakarta.apache.org/commons/sandbox/grant/
It's only in CVS at this time, but it provides an overlay AntClassLoader
that simply allows the isolationary classloader for junit to delegate
requests for xml-parser classes to the parent classloader, thus, only
loading them once, from a single location.
Simply install the grant.jar ahead of ant.jar in your classpath, and
things should clear up.
Additionally, another project aimed at managing classloader issues
is forehead:
http://forehead.sourceforge.net/
> Catching ClassCastExxception as suggested in my previous message does
> fix the problem.
It hides the problem, causing you to fallback to a secondary method.
fwiw, this problem has been conquered in the maven project, which
is progressing nicely towards making futzing with ant a thing of
the past.
http://jakarta.apache.org/turbine/maven/
-bob
More information about the jdom-interest
mailing list