You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Christopher Piggott <ch...@rochester.rr.com> on 2006/04/28 23:31:37 UTC

Class loading from within a servlet: interface definition not found

I have something happening with class loading from within a server, and I don't understand it.

My servlet defines some classes called:
	org.something.server  -- the class that extends HttpServlet
	org.something.DatabaseRequestHandler -- an interface

When you make a request to the server, it figures out what handler class to load.  Then it attempts to load it:

	Class handlerClass = Class.forName(handlerClassNameString);


QUESTION: looking at the little diagram in the Tomcat 5.5 Class Loader HOW-TO, when I do the above (Class.forName) I am using the Webapp class loader, correct?


The handler classes are all in handlers.jar which is in $CATALINA_BASE/shared/lib.  The actual exception that I get is:

	2006-04-28 17:05:55 StandardWrapperValve[xdb]: Servlet.service() for servlet xdb threw exception
	java.lang.NoClassDefFoundError: org/something/DatabaseRequestHandler

It took me a few minutes to realize that this was not a ClassNotFound exception, but something else.  Reading docs I figured out that the most probably cause is that the servlet's classloader was able to find the handler class, but then it failed to load one of the things it depended on, specifically it was able to find handlerClass but not the interface class that it depends on.

Trouble is: the interface .class file is right there in WEB-INF/classes/com/something/DatabaseRequestHandler.class just like it should be.  So, I am stumped why the class loader would be able to find the handler class in $CATALINA_BASE/shared/lib but NOT the interface that it implements which is in WEB-INF/classes.


At the suggestion of a nice gentleman on freenode, I tried turning on the -verbose:class option in the jvm, and watched it log some interesting stuff to catalina.out.  Unfortunately it doesn't shed any light on what is happening, beyond the exception and stack trace in the error log.  I don't want to post the whole stack trace (unless someone thinks it would help to see it) but I will say that it includes catalina.loader.WebappClassLoader as well as catalina.loader.StandardClassLoader

--Chris




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Class loading from within a servlet: interface definition not found

Posted by Michael Echerer <me...@tngtech.com>.
David Smith wrote:
> most likely the shared classloader instead.  If possible, move the
> handler.jar from shared/lib to WEB-INF/lib of your webapp and the
> problem should go away.
>>It took me a few minutes to realize that this was not a ClassNotFound exception, but something else.  Reading docs I figured out that the most probably cause is that the servlet's classloader was able to find the handler class, but then it failed to load one of the things it depended on, specifically it was able to find handlerClass but not the interface class that it depends on.
>>
>>Trouble is: the interface .class file is right there in WEB-INF/classes/com/something/DatabaseRequestHandler.class just like it should be.  So, I am stumped why the class loader would be able to find the handler class in $CATALINA_BASE/shared/lib but NOT the interface that it implements which is in WEB-INF/classes.

What you are trying to do won't work or at least is asking for much
classloading trouble.
Its basically the same as if you try to put a jdbc jar in common/lib AND
in WEB-INF/lib or put the servlet api which is included by Tomcat into
WEB-INF/lib again.
Bad idea and sometimes caused by unwanted glitches in ant build.xmls as
it is convenient to put all .jars into the .war that were required for
the build, eventhough the are harmful when deployed.

Even if the classloader would find your classes and interfaces if you
rebundle your jars you'll run into problems (class cast exceptions) as
soon if you try to cast objects loaded by two different classloaders
later on. E.g. you have created a Handler class by the shared
classloader and later on cast in your webapp by using the webapp
classloader to use it.
Remember: for instanceof to be true it's not enough to have the same
class, two objects have to be loaded by the same classloader, too.

Repackage your code, use the same classloader, or as David said put
everything into WEB-INF/lib.

Cheers,
Michael


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Class loading from within a servlet: interface definition not found

Posted by David Smith <dn...@cornell.edu>.
I think you are assuming the classloader
org.something.DatabaseRequestHandler is using is the webapp's local
classloader.  I doubt this is the case.  Those with more knowlege of the
classloader architecture may chime in, but the classloader being used is
most likely the shared classloader instead.  If possible, move the
handler.jar from shared/lib to WEB-INF/lib of your webapp and the
problem should go away.

--David

Christopher Piggott wrote:

>I have something happening with class loading from within a server, and I don't understand it.
>
>My servlet defines some classes called:
>	org.something.server  -- the class that extends HttpServlet
>	org.something.DatabaseRequestHandler -- an interface
>
>When you make a request to the server, it figures out what handler class to load.  Then it attempts to load it:
>
>	Class handlerClass = Class.forName(handlerClassNameString);
>
>
>QUESTION: looking at the little diagram in the Tomcat 5.5 Class Loader HOW-TO, when I do the above (Class.forName) I am using the Webapp class loader, correct?
>
>
>The handler classes are all in handlers.jar which is in $CATALINA_BASE/shared/lib.  The actual exception that I get is:
>
>	2006-04-28 17:05:55 StandardWrapperValve[xdb]: Servlet.service() for servlet xdb threw exception
>	java.lang.NoClassDefFoundError: org/something/DatabaseRequestHandler
>
>It took me a few minutes to realize that this was not a ClassNotFound exception, but something else.  Reading docs I figured out that the most probably cause is that the servlet's classloader was able to find the handler class, but then it failed to load one of the things it depended on, specifically it was able to find handlerClass but not the interface class that it depends on.
>
>Trouble is: the interface .class file is right there in WEB-INF/classes/com/something/DatabaseRequestHandler.class just like it should be.  So, I am stumped why the class loader would be able to find the handler class in $CATALINA_BASE/shared/lib but NOT the interface that it implements which is in WEB-INF/classes.
>
>
>At the suggestion of a nice gentleman on freenode, I tried turning on the -verbose:class option in the jvm, and watched it log some interesting stuff to catalina.out.  Unfortunately it doesn't shed any light on what is happening, beyond the exception and stack trace in the error log.  I don't want to post the whole stack trace (unless someone thinks it would help to see it) but I will say that it includes catalina.loader.WebappClassLoader as well as catalina.loader.StandardClassLoader
>
>--Chris
>
>
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>For additional commands, e-mail: users-help@tomcat.apache.org
>
>  
>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Classloading questions

Posted by Michael Echerer <me...@tngtech.com>.
Christopher Piggott wrote:
> As an experiment, I placed a file in the webapp dir of a servlet (not in
> WEB-INF but in the directory above it) and attempted to read it using
> getResource().  What I found was that I could not locate the resource unless
> I used getServletContext().getResource().
> 

Your basic assumption that getServletContext().getResource() works by
using classloader means is simply wrong.

If you look at the JavaDoc of ServletContext it says that getResource()
works file based (relative to the context root) and does not use the
classloader.

http://tomcat.apache.org/tomcat-5.0-doc/servletapi/javax/servlet/ServletContext.html#getResource(java.lang.String)


Cheers,
Michael


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Classloading questions

Posted by Christopher Piggott <ch...@rochester.rr.com>.
As an experiment, I placed a file in the webapp dir of a servlet (not in
WEB-INF but in the directory above it) and attempted to read it using
getResource().  What I found was that I could not locate the resource unless
I used getServletContext().getResource().

Reading through the Classloading How-To, I am confused why this works.  The
how-to says that from the perspective of the webapp, loading takes place in
this order:

    * Bootstrap classes of your JVM
    * System class loader classses (described above)
    * /WEB-INF/classes of your web application
    * /WEB-INF/lib/*.jar of your web application
    * $CATALINA_HOME/common/classes
    * $CATALINA_HOME/common/endorsed/*.jar
    * $CATALINA_HOME/common/lib/*.jar
    * $CATALINA_BASE/shared/classes
    * $CATALINA_BASE/shared/lib/*.jar

But, what is the order for getServletContext() ?

To try to figure this out, I ran another experiment:

	ClassLoader c1 = this.getClass().getClassLoader();
	log(" this's classloader is " + c1.getClass().getName());

	ClassLoader c2 = getServletContext().getClass().getClassLoader();
	log(" servlet context's  classloader is " + c2.getClass().getName());

Results:

	this's classloader is org.apache.catalina.loader.WebappClassLoader
	servlet context's  classloader is
org.apache.catalina.loader.StandardClassLoader

The HowTo says the following classloaders exist:

    * Bootstrap
    * System
    * Common
    * Catalina
    * Shared
    * WebappX

How is that some instance of StandarClassLoader able to access the webapp
root?



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Class loading from within a servlet: interface definition not found

Posted by Boris Unckel <bo...@gmx.net>.
Hello Christopher,

> Von: "Christopher Piggott" <ch...@rochester.rr.com>
> QUESTION: looking at the little diagram in the Tomcat 5.5 Class Loader
> HOW-TO, when I do the above (Class.forName) I am using the Webapp class
> loader, correct?
Yes.

> The handler classes are all in handlers.jar which is in
> $CATALINA_BASE/shared/lib.  The actual exception that I get is:
> 
> 	2006-04-28 17:05:55 StandardWrapperValve[xdb]: Servlet.service() 
> for
> servlet xdb threw exception
> 	java.lang.NoClassDefFoundError: 
> org/something/DatabaseRequestHandler
>
> Trouble is: the interface .class file is right there in
> WEB-INF/classes/com/something/DatabaseRequestHandler.class just like it 
> should be.  So, I am
> stumped why the class loader would be able to find the handler class in
> $CATALINA_BASE/shared/lib but NOT the interface that it implements which 
> is in
> WEB-INF/classes.
> 
This looks very similiar to problems with Jakarta Commons Logging, caused by
wrong position of the different JCL jars.
It is generally not a good idea to share JARs. This should just be done if
they require it (i.E. some JDBC drivers).

For JCL there is a lot of material about the special issues with wrong
positions, i.E.
http://wiki.apache.org/jakarta-commons/Commons_Logging_FUD

Try to put everything you need under WEB-INF/lib, even if it means to copy
the shared JARs into different webapps.
Please post the result.

Regards
Boris


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org