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
- 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
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