[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