You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Guy Verbist <gu...@prosumersolutions.com> on 2001/09/11 17:49:14 UTC

RE: Problem with loading classes dynamically, new objects can't " see" things in webapp.

Hi Craig, and thanks for your reply.

> Because you got NoClassDefFoundError instead of 
> ClassNotFoundException, it is *not* ProsumerTestTag that is the
> missing one.  Instead, check the
> sources of ProsumerTag for references to *other* classes, and 
> make sure all of *those* classes are also available in your web app.

Yes, I'm aware of this.

ProsumerTestTag isn't in the webapp, but I've put it in the classpath, and
that's fine.

It can't find com.psl.customtags.CustomTag which is an interface that that
the ProsumerTestTag class implements.  This class (CustomTag) really is in
the web app, honest.

If I pull just com.psl.customtags.CustomTag into the classpath, then as soon
as I actually try to *do* something with the ProsumerTestTag class (as
opposed to just loading it), then the jvm can't find other things in the
webapp that CustomTag references (not just the interface it implements, but
types that are parameters to it's methods).

Many thanks,

Guy

> > Hi all.
> >
> > I hope I'm not being too dumb here.
> >
> > My servlet code wants to load classes dynamically at 
> runtime.  Instances of
> > these classes will call back into the servlet code.
> >
> > So, my server.xml looks like this:
> >
> >     <Context path="/prosumer"
> >          docBase="c:\Products\suite\current\peng\webapp"
> >
> > with all the class files under ...\webapp\WEB-INF\classes
> >
> > Mostly it works fine.
> > However when I try to execute this line:
> >
> >     Class c = 
> Class.forName("com.psl.test.customtags.ProsumerTestTag");
> >
> > where ProsumerTestTag is defined thusly:
> >
> >     public class ProsumerTestTag implements CustomTag {
> >
> > tomcat keels over with:
> >
> > java.lang.NoClassDefFoundError: com/psl/customtags/CustomTag
> > 	at java.lang.ClassLoader.defineClass0(Native Method)
> > 	at java.lang.ClassLoader.defineClass(ClassLoader.java:486)
> > 	at
> > 
> java.security.SecureClassLoader.defineClass(SecureClassLoader.
> java:111)
> > 	at java.net.URLClassLoader.defineClass(URLClassLoader.java:248)
> > 	at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
> > 	at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
> > 	at java.security.AccessController.doPrivileged(Native Method)
> > 	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
> > 	at java.lang.ClassLoader.loadClass(ClassLoader.java:297)
> > 	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:286)
> > 	at java.lang.ClassLoader.loadClass(ClassLoader.java:253)
> > 	at
> > 
> org.apache.tomcat.loader.AdaptiveClassLoader.loadClass(Adaptiv
eClassLoader.j
> > ava:446)
> > 	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)
> >
> > left in the jvm.stderr
> >
> > I guess it can't find the "CustomTag" that ProsumerTestTag 
> implements.
> > However com/psl/customtags/CustomTag *realy is* in the webapp.
> >
> > I'm running tomcat 3.2.2 as a service on a Win2k server 
> box, and if I add
> > the whole of the webapp code to the classpath for the jvm 
> for tomcat by
> > editing the ...wrapper.properties for jk_nt_service.exe, 
> then the whole
> > thing works.  However this workaround seems to be suboptimal.
> >
> > My question is why can't a class loaded by Class.forName() 
> see things in
> > webapp/WEB-INF/classes, only things in the regular JVM 
> classpath, when the
> > rest of the webapp can see things in the webapp/WEB-INF/classes?
> >
> > I guess my call to Class.forName() is creating a different 
> context for the
> > new class to what is created for the rest of the servlet, 
> but is there some
> > way I can resolve the differences?
> >
> > Thanks very much.
> >
> > Guy
> >
> 

RE: Problem with loading classes dynamically, new objects can't " see" things in webapp.

Posted by Dmitri Colebatch <di...@bigpond.net.au>.
On Tue, 11 Sep 2001, Craig R. McClanahan wrote:
> Exactly the same issue.  That's why the Struts documentation tells you
> (over and over again :-) to put "struts.jar" *inside* your web app (in
> /WEB-INF/lib) and nowhere else.

oops (o:  should have read the doco... I skipped straight to the archives
(o:

thanks for your insights.

cheers
dim

> This would solve the problem in a Servlet 2.3 based container, which is
> required to supply the web app class loader when getContextClassLoader()
> is called.  However:
> 
> * Support for this was not required in Servlet 2.2, so you cannot
>   count on it working.  In fact, it won't work in Tomcat 3.2 unless
>   you enable the Jdk12Interceptor described in server.xml.
> 
> * getContextClassLoader() is not supported at all on JDK 1.1 systems.
> 
> > look forward to hearing thoughts on this.
> >
> > cheers
> > dim
> >
> >
> 
> Craig McClanahan
> 
> 
> 


RE: Problem with loading classes dynamically, new objects can't " see" things in webapp.

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Wed, 12 Sep 2001, Dmitri Colebatch wrote:

> Date: Wed, 12 Sep 2001 08:02:47 +1000
> From: Dmitri Colebatch <di...@bigpond.net.au>
> Reply-To: tomcat-user@jakarta.apache.org
> To: "'tomcat-user@jakarta.apache.org'" <to...@jakarta.apache.org>
> Subject: RE: Problem with loading classes dynamically,
>      new objects can't " see"  things in webapp.
>
> On Tue, 11 Sep 2001, Craig R. McClanahan wrote:
>
> > If ProsumerTestTag is being loaded from the class path, it's being loaded
> > by the system class loader.
> >
> > If CustomTag is being loaded from the web app, it is being loaded from the
> > webapp class loader.
> >
> > Classes loaded from the system class loader CANNOT see classes loaded from
> > the webapp class loader -- therefore, Tomcat is telling you the truth.
> > These restrictions are based on the way class loaders work in Java, so
> > there's nothing Tomcat can do about it.
> >
> > Note that any of the following should work:
> > * Put CustomTag and ProsumerTestTag both on the classpath
> > * Put CustomTag and ProsumerTestTag both in the webapp
> > * Put CustomTag on the classpath and ProsumerTestTag in the webapp
> >   (webapp class loaders can look "up" the class loader hierarchy)
>
> ok - this is highlighting my lack of knowledge on classloaders - so
> hopefully I can learn something here.  This is the same thing that causes
> an issue with struts:
>
>   using struts, and jboss with embedded tomcat.  if the struts.jar is
>   in the jboss/lib/ext (command classpath) then it cannot find form or
>   action classes that are in the web application.
>

Exactly the same issue.  That's why the Struts documentation tells you
(over and over again :-) to put "struts.jar" *inside* your web app (in
/WEB-INF/lib) and nowhere else.

> I assume this is due to code along the lines of Class.getClassLoader() -
> now what I dont understand is why those lines of code are not
> Thread.currentThread().getContextClassLoader() .  would that not solve
> both of these problems - it seems to be a more "embeddable" approach,
> letting another container (be it jspc, or jboss) control the system.
>

This would solve the problem in a Servlet 2.3 based container, which is
required to supply the web app class loader when getContextClassLoader()
is called.  However:

* Support for this was not required in Servlet 2.2, so you cannot
  count on it working.  In fact, it won't work in Tomcat 3.2 unless
  you enable the Jdk12Interceptor described in server.xml.

* getContextClassLoader() is not supported at all on JDK 1.1 systems.

> look forward to hearing thoughts on this.
>
> cheers
> dim
>
>

Craig McClanahan



RE: Problem with loading classes dynamically, new objects can't " see" things in webapp.

Posted by Dmitri Colebatch <di...@bigpond.net.au>.
On Tue, 11 Sep 2001, Craig R. McClanahan wrote:

> If ProsumerTestTag is being loaded from the class path, it's being loaded
> by the system class loader.
> 
> If CustomTag is being loaded from the web app, it is being loaded from the
> webapp class loader.
> 
> Classes loaded from the system class loader CANNOT see classes loaded from
> the webapp class loader -- therefore, Tomcat is telling you the truth.
> These restrictions are based on the way class loaders work in Java, so
> there's nothing Tomcat can do about it.
> 
> Note that any of the following should work:
> * Put CustomTag and ProsumerTestTag both on the classpath
> * Put CustomTag and ProsumerTestTag both in the webapp
> * Put CustomTag on the classpath and ProsumerTestTag in the webapp
>   (webapp class loaders can look "up" the class loader hierarchy)

ok - this is highlighting my lack of knowledge on classloaders - so
hopefully I can learn something here.  This is the same thing that causes
an issue with struts:

  using struts, and jboss with embedded tomcat.  if the struts.jar is
  in the jboss/lib/ext (command classpath) then it cannot find form or 
  action classes that are in the web application.

I assume this is due to code along the lines of Class.getClassLoader() -
now what I dont understand is why those lines of code are not
Thread.currentThread().getContextClassLoader() .  would that not solve
both of these problems - it seems to be a more "embeddable" approach,
letting another container (be it jspc, or jboss) control the system.

look forward to hearing thoughts on this.

cheers
dim


RE: Problem with loading classes dynamically, new objects can't " see" things in webapp.

Posted by "Craig R. McClanahan" <cr...@apache.org>.

On Tue, 11 Sep 2001, Guy Verbist wrote:

> Date: Tue, 11 Sep 2001 16:49:14 +0100
> From: Guy Verbist <gu...@prosumersolutions.com>
> Reply-To: tomcat-user@jakarta.apache.org
> To: "'tomcat-user@jakarta.apache.org'" <to...@jakarta.apache.org>
> Subject: RE: Problem with loading classes dynamically,
>      new objects can't " see"  things in webapp.
>
> Hi Craig, and thanks for your reply.
>
> > Because you got NoClassDefFoundError instead of
> > ClassNotFoundException, it is *not* ProsumerTestTag that is the
> > missing one.  Instead, check the
> > sources of ProsumerTag for references to *other* classes, and
> > make sure all of *those* classes are also available in your web app.
>
> Yes, I'm aware of this.
>
> ProsumerTestTag isn't in the webapp, but I've put it in the classpath, and
> that's fine.
>

Not necessarily.  See below.

> It can't find com.psl.customtags.CustomTag which is an interface that that
> the ProsumerTestTag class implements.  This class (CustomTag) really is in
> the web app, honest.
>

If ProsumerTestTag is being loaded from the class path, it's being loaded
by the system class loader.

If CustomTag is being loaded from the web app, it is being loaded from the
webapp class loader.

Classes loaded from the system class loader CANNOT see classes loaded from
the webapp class loader -- therefore, Tomcat is telling you the truth.
These restrictions are based on the way class loaders work in Java, so
there's nothing Tomcat can do about it.

Note that any of the following should work:
* Put CustomTag and ProsumerTestTag both on the classpath
* Put CustomTag and ProsumerTestTag both in the webapp
* Put CustomTag on the classpath and ProsumerTestTag in the webapp
  (webapp class loaders can look "up" the class loader hierarchy)

Craig

> If I pull just com.psl.customtags.CustomTag into the classpath, then as soon
> as I actually try to *do* something with the ProsumerTestTag class (as
> opposed to just loading it), then the jvm can't find other things in the
> webapp that CustomTag references (not just the interface it implements, but
> types that are parameters to it's methods).
>
> Many thanks,
>
> Guy
>
> > > Hi all.
> > >
> > > I hope I'm not being too dumb here.
> > >
> > > My servlet code wants to load classes dynamically at
> > runtime.  Instances of
> > > these classes will call back into the servlet code.
> > >
> > > So, my server.xml looks like this:
> > >
> > >     <Context path="/prosumer"
> > >          docBase="c:\Products\suite\current\peng\webapp"
> > >
> > > with all the class files under ...\webapp\WEB-INF\classes
> > >
> > > Mostly it works fine.
> > > However when I try to execute this line:
> > >
> > >     Class c =
> > Class.forName("com.psl.test.customtags.ProsumerTestTag");
> > >
> > > where ProsumerTestTag is defined thusly:
> > >
> > >     public class ProsumerTestTag implements CustomTag {
> > >
> > > tomcat keels over with:
> > >
> > > java.lang.NoClassDefFoundError: com/psl/customtags/CustomTag
> > > 	at java.lang.ClassLoader.defineClass0(Native Method)
> > > 	at java.lang.ClassLoader.defineClass(ClassLoader.java:486)
> > > 	at
> > >
> > java.security.SecureClassLoader.defineClass(SecureClassLoader.
> > java:111)
> > > 	at java.net.URLClassLoader.defineClass(URLClassLoader.java:248)
> > > 	at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
> > > 	at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
> > > 	at java.security.AccessController.doPrivileged(Native Method)
> > > 	at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
> > > 	at java.lang.ClassLoader.loadClass(ClassLoader.java:297)
> > > 	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:286)
> > > 	at java.lang.ClassLoader.loadClass(ClassLoader.java:253)
> > > 	at
> > >
> > org.apache.tomcat.loader.AdaptiveClassLoader.loadClass(Adaptiv
> eClassLoader.j
> > > ava:446)
> > > 	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)
> > >
> > > left in the jvm.stderr
> > >
> > > I guess it can't find the "CustomTag" that ProsumerTestTag
> > implements.
> > > However com/psl/customtags/CustomTag *realy is* in the webapp.
> > >
> > > I'm running tomcat 3.2.2 as a service on a Win2k server
> > box, and if I add
> > > the whole of the webapp code to the classpath for the jvm
> > for tomcat by
> > > editing the ...wrapper.properties for jk_nt_service.exe,
> > then the whole
> > > thing works.  However this workaround seems to be suboptimal.
> > >
> > > My question is why can't a class loaded by Class.forName()
> > see things in
> > > webapp/WEB-INF/classes, only things in the regular JVM
> > classpath, when the
> > > rest of the webapp can see things in the webapp/WEB-INF/classes?
> > >
> > > I guess my call to Class.forName() is creating a different
> > context for the
> > > new class to what is created for the rest of the servlet,
> > but is there some
> > > way I can resolve the differences?
> > >
> > > Thanks very much.
> > >
> > > Guy
> > >
> >
>