IBM ® WebSphere® Application Server has a run-time library of classes, including Xerces. Those
classes are loaded by applications when their application classloaders delegate upward and use the WASext Application Server
classloader to load them. WebSphere Application Server V5 has a hierarchy of classloaders and delegation modes (preference
orders) that can be set for J2EE modules. You can use the classloader hierarchy and the
PARENT_LAST delegation mode
to build Web Archive files (WARs) or Enterprise Application files (EARs) that include their own specific version of common
libraries, particularly the Xerces XML parsing classes. Normally, everything works as expected, but sometimes
ClassCastExceptions occur because utility EAR classes that use Xerces unexpectedly load Xerces classes from WAR modules
(which they should not be able to "see" or load), instead of from the EAR Xerces (if Xerces is included in the EAR) or
from the default WASext run-time Xerces.
A typical scenario: a developer creates a utility class that uses Xerces and puts that utility class
into a library JAR in one or more EARs. Another typical scenario involves a utility class that will be widely used
throughout an enterprise and is therefore put into the
ws.ext.dir for use by any application. The expectation is
that an EAR utility class will use an EAR Xerces (if one is included in the EAR), or else will default up to the WASext
run-time Xerces (since EARs can only see the EAR libraries or the default run-time libraries)
Various Web application WARs are then built, which sometimes include a specific Xerces within their WAR, and
they set the
PARENT_LAST delegation (so that their specific Xerces is used). However, when such a WAR uses your EAR
(or WASext) utility class, that utility class creates a Xerces
DOMParser (loading the WebSphere Xerces) and the
ObjectFactory.createObject, which switches to the
actually create the
DOMparser object. This causes a
ClassCastException error, since the resulting WAR
DOMparseris not the same as the expected
WASext DOMparser. Suddenly your utility class has switched to
use the WAR Xerces instead of the WASext Xerces, even though that utility class was loaded by the EAR (or WASext) classloader
and should not be able to see or load WAR classes.
What causes this problem, and how do you eliminate it? The answer is that some special coding is required in the utility class, the same as is done for all WebSphere run-time classes that use Xerces.
There is, by design, a hierarchy of classloaders in WebSphere Application Server V5. The main ones we are interested in are:
WebSphere Extension Classloader ^ ^ EAR Classloader ^ ^ WAR Classloader
There are two related concepts associated with classloaders:
- defines which classes are "reachable" -- that is, which classes can be loaded. Normally, visibility extends "up" but not "down". Therefore, any class loaded by a WAR classloader can also load classes using the EAR or WASext classloader, but any class loaded by the EAR (or WASext) classloader cannot subsequently load classes using the WAR classloader.
- defines the "preference" order of classloaders. In other words, it defines where to look
first (and subsequently if necessary) to try to load classes. Within WebSphere Application Server V5, each J2EE module
classloader has a setting
PARENT_LAST)that you can use to set the delegation mode for the EAR and WAR (but not for anything higher).
When a Web application WAR is built to include and use a specific Xerces version, a specific server configuration is required. Follow these steps to set up that configuration:
- In WebSphere Application Server, open your WebSphere server configuration.
- Click the Configuration tab. In the Application classloader policy drop-down list, select MULTIPLE:
- Click the Applications tab and select your application (your EAR file). In the Classloader mode drop-down list, select PARENT_FIRST (or if you prefer, PARENT_LAST).
- Within that same Applications tab, move to the WAR classloader policy drop-down list and select MODULE, as shown below:
- Still within the same Applications tab, select your WAR file, and in the Classloader mode drop-down list, select PARENT_LAST, as shown below:
- Save your changes and close your server configuration.
When the Web application is running, the thread of execution comes from the servlet in the WAR. Any WAR classes that use Xerces will locate and load Xerces classes using the WAR classloader. Any WAR classes using WASext run-time classes will locate and load those classes using the WASext classloader (since the WAR does not contain those classes and its classloader delegates up to the EAR and then WASext classloader until they are found and loaded). Those WASext classes in turn can then only locate and load other classes using that same WASext classloader. This kind of isolation is intended (and desirable).
So far, everything is behaving as expected. However, a problem
occurs if your WAR uses a utility class in your EAR file (or in
The root cause of the problem is that J2EE requires that
contextclassloader must always be
the classloader of the currently executing J2EE artifact. Specifically, J2EE containers must provide a per thread
contextclassloader for the use of system or library classes when dynamically loading and executing such classes.
Therefore the system library Xerces code calls
to switch and use the
contextclassloader during its execution. In particular, when your utility class creates a
DOMParser object, that class is initially found and loaded using the EAR classloader, which delegates to the WASext
classloader (assuming there are no Xerces classes in the EAR libraries) to locate and load the WASext run-time Xerces
DOMParser class (all as expected). That
DOMParser constructor then calls
ObjectFactory.createObject, but that method then switches to the J2EE artifact
(the current WAR classloader), to construct (using
getResourceAsStream) the actual
Unfortunately , the resulting
DOMParser object is therefore a class from the WAR Xerces rather than from
the original WASext (or EAR) Xerces, which causes a
ClassCastException when it is returned from the
In other words, when a utility class in a
PARENT_LAST hierarchy constructs a WASext
DOMParser switches to the active J2EE
and it will fail trying to return an actual
DOMParser object from the active
(lower-level) WAR Xerces.
To work around this, your utility class code must:
- Get the currently executing thread
contextclassloaderand save it, as shown below:
ClassLoader savedClassloader = Thread.currentThread().getContextClassloader();
- Set the
contextclassloaderto its own classloader, as shown below:
Thread.currentThread().setContextClassloader( this.getClass().getClassLoader() );
- Invoke the Xerces parsing operations it needs to use
- Restore the
contextclassloader, as shown below:
Thread.currentThread().setContextClassloader( savedClassLoader );
By performing the above steps, your utility class can safely be in the classloader hierarchy above
PARENT_LAST J2EE modules that include their own version of Xerces.
Whenever a WebSphere run-time class uses Xerces, WebSphere has to similarly modify all such classes to save
contextclassloader, explicitly use the WASext classloader to load Xerces and perform the parsing operations,
and then restore the
Here are some problems similar to the one described above:
- Commons-logging has the same run-time problem as Xerces, so any utility class that uses it can have
PARENT_LAST ClassCastExceptionsfrom WARs (containing a different version of commons-logging).
- A few WebSphere V5.0.0 run-time classes that use Xerces previously caused similar errors, but all known WebSphere V5 run-time problems have now been fixed in recent APARs or PTFs (using the solution described above). As of October 2003, the most recent PTFs and APARs related to this are V5 PTF-2, plus APAR-PQ77263, which is also part of WebSphere Application Server 5.0.2 Cumulative Fix 1.
Developers often want to create Web application WARs that contain and use a specific version of Xerces.
WebSphere Application Server provides visibility (the classloader hierarchy) and delegation (the classloader
order preference) settings to support this. However, you must avoid creating any EAR or
ws.ext.dir utility classes
that use Xerces, unless you implement a specific
contextclassloader workaround within them to ensure that
PARENT_LAST WAR modules will not have a
ClassCastException whenever they use those utility classes
Barry Searle is the Migration Team Leader for WebSphere Studio Application Developer. He is a Professional Engineer who has worked at the IBM Canada Lab for over ten years on various application development tools. Prior to that he had many years of industry experience developing command and control systems and leading communications development projects. You can reach Barry at email@example.com .
Ellen McKay is an Information Developer for IBM Canada Ltd. She writes online help and publications for WebSphere Studio Application Developer. You can reach Ellen at firstname.lastname@example.org