Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Classloader problem

0 views
Skip to first unread message

Rick Cole

unread,
Jul 19, 2001, 12:10:50 AM7/19/01
to
I am having a problem with my application I have deployed to an ear file. I
am attempting to use jakarta's cactus for unit testing. I have placed the
commons-cactus.jar and junit.jar into the lib directory of my war file.
There is a servlet in the cactus jar that is needed to run cactus, and it
has been added to the web.xml. If I deploy the war standalone, everything
works as expected. I can run my unit tests, etc...

Now for the strange part. If I add the war to an ear and deploy it, I get a
NoClassDefFoundError on a support class which is contained within the cactus
jar. In other words, the servlet is found fine. However, another class in
the cactus jar is NOT found. Here is the stack trace I get:

java.lang.NoClassDefFoundError: org/apache/commons/cactus/ServletTestCase
at java.lang.ClassLoader.defineClass0(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:486)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:111)
at
weblogic.utils.classloaders.GenericClassLoader.findLocalClass(GenericClassLo
ader.java:338)
at
weblogic.utils.classloaders.GenericClassLoader.findClass(GenericClassLoader.
java:155)
at java.lang.ClassLoader.loadClass(ClassLoader.java:297)
at java.lang.ClassLoader.loadClass(ClassLoader.java:290)
at java.lang.ClassLoader.loadClass(ClassLoader.java:253)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:313)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:120)
at
org.apache.commons.cactus.server.ServletTestCaller.callTestMethod(ServletTes
tCaller.java:94)
at
org.apache.commons.cactus.server.ServletTestCaller.doTest(ServletTestCaller.
java:173)
at
org.apache.commons.cactus.server.ServletTestRedirector.doPost(ServletTestRed
irector.java:116)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at
weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java
:263)
at
weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java
:200)
at
weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletCo
ntext.java:2349)
at
weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java
:1956)
at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:137)
at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:120)

As you can see the org.apache.commons.cactus.server.ServletTestRedirector
class is found, and it is in the same jar as the
org.apache.commons.cactus.ServetTestCase class, which is not found. Perhaps
this is an issue with cactus, but when I look at the code for
ServletTestRedirector, it does nothing more than a Class.forName() to load
the ServletTestCase class (actually, my class inherits from
ServletTestCase). I notice, however, that some weblogic specific
classloaders are in the stack trace as well. I just find it interesting that
it works with a standalone war, but not in an ear. What is different here?
From what I understand, the ear gets its own classloader, so how can one
class from a jar be loaded from a classloader and not another class from the
same jar?

I can get this to work by putting EVERYTHING on the system classpath
(including my own test classes), but then I lose hot deployment. We want to
be able to test and hot deploy our new classes without restarting weblogic.

Thanks!

Rick Cole


Daniel Hoppe

unread,
Jul 20, 2001, 9:21:58 AM7/20/01
to
Hmmm. Line 94 points into the middle of nowhere in my cactus sources.
Which version are you using? I got the testcase redeployment running,
but it cost me some days, mainly classpath debugging. Are you 100% sure
that

- cactus.jar
- your servlet
- all other auxiliary testclasses which might reference back to classes
in your webapp

are all in the web-app classes and lib directory and *!!*nowhere*!!*
else?

To debug your issue you have to mind 3 things. The first is that every
object instance has an associated classloader. If an object is
instantiated from within this class the associated classloader will be
used. The second is that every classloader has a parent classloader. The
only classloader without is the bootstrapclassloader. If a class is
loaded, a classloader first asks it's parent for the class before
loading it. Third is that the webapp classloader is a child of the ejb
classloader and the ejb classloader is a child of the systemclassloader.

Why is that so important? Imagine your webapp contains class A and B. B
is in the system classpath as well, because it's a common utility class.
In your webapp, A loads B, B is supposed to load class C which is in the
webapp again. This will not work, because when A loads B it's not loaded
by the webapp classloader but by the system classloader
(parentclassloader will be asked first!). When B wants to load C it will
get a ClassNotFoundException as C is not in the system classpath (and
therefore not visible for the classloader which B is associated with).
So you'll get a ClassNotFoundException although all classes are nicely
packaged in your WebApp. This can really cost some nerves...

I guess that something like this is happening in your case. It's a pain
in the neck to debug but great once you understand and utilize it
properly.

Let me know if this helps.

Daniel

Rick Cole

unread,
Aug 4, 2001, 11:42:30 AM8/4/01
to

Thanks. This worked. I had some of my utility classes in my ejb jar. Its classloader
was loading them and couldn't load their base classes, since they were in the
war lib directory.

Rick

khiawpin

unread,
Aug 6, 2001, 9:59:15 PM8/6/01
to

This is very nicely and clearly explained.

Let's say we have another example where class B is a utility class or
value object used in both web tier and EJB tier.
Class A is in the web tier and class C in EJB tier.

Since EJB classloader is parent of WAR classloader, this would mean that
class B needs only to exist in the JAR file, wouldn't it? When class A
loads class B, it would request it from the EJB classloader first, would it
not?

However, I find that I have to include class B in both WAR and JAR file within
the same EAR and that is puzzling me.

Another question:
Does WebLogic handle it the same way for separate WAR and JAR, i.e. not within
an EAR?

Thanks in advance
khiawpin

0 new messages