[Summary] Re: WebappClassLoader question

2001-07-27 Thread Vincent Massol

Thanks to all who helped on this.
Andrew was right, and Craig too  and I was wrong !

Here is what happened. My code was written like this :

ServletTestCase testInstance = null;
try {
testClass = Class.forName(theClassName);
Constructor constructor = testClass.getConstructor(new Class[]
{ String.class });
testInstance = (ServletTestCase)constructor.newInstance(new
Object[] { theMethod });
} catch (Exception e) {

As Andrew pointed out, this would never have caught the NoClassDefFoundError
error because it is not a subclass of Exception. Modifying it to Throwable
did not help. However the error was that ServletTestCase was defined outside
the try catch block and thus the error was thrown there and would be caught
in the first class because I was catching Throwable there ...

So it is a stupid error. However I learnt how the Tomcat class loader worked
which I didn't know. I also learned that the error raised when a class is
not found by the class loader was NoClassDefFoundError and not (as I thought
initially) ClassNotFoundException !

So I'll to rewrite my code as follows :

Object dummy; <-- cannot use ServletTestCase here as it might raise
a NoClassDefFoundError!
try {
testClass = Class.forName(theClassName);
Constructor constructor = testClass.getConstructor(new Class[]
{ String.class });
dummy = (ServletTestCase)constructor.newInstance(new Object[]
{ theMethod }); <--- need the cast to catch NoClassDefFoundError
} catch (Exception e) {
...
}
ServletTestCase testInstance = (ServletTestCase)dummy;

... which I don't find that easy to write at first ... (I'll need to put
some comments to explain the trick) !

You might say, why catch this error and not let it be thrown by the
container itself ... However the problem with this is that the error that
gets displayed does not give any clue that the initial problem was a
NoClassDefFoundError, it just prints the following in the console :

 [java] StandardWrapperValve[ServletRedirector]: Servlet.service() for
servlet ServletRedirector threw exception
 [java] javax.servlet.ServletException: Servlet execution threw an
exception
 [java] javax.servlet.ServletException: Servlet execution threw an
exception
 [java] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(Application
FilterChain.java:269)

which is absolutely not explicit ! Wouldn't it be possible to improve Tomcat
so that it chains the exception and also prints the original excpetion in
the console ?

Thanks again.
-Vincent

- Original Message -
From: "Andrew Inggs" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Friday, July 27, 2001 10:01 AM
Subject: RE: WebappClassLoader question


> Hi Vincent
>
> You seem to be missing at least two things here:
>
> 1. In your original post you said:
>
> > When I access the servlet, I get a ClassNotFoundException on a
> > JUnit class. So far it is normal ...
> > When I debugged it, I have actually found that the error was
> > happening when ServletTestRedirector was instancianting
> > MyProxyClass (which does _not_ make use of JUnit) and before
> > it was calling its method.
>
> This does not look right.  You say MyProxyClass does not make
> use of JUnit, but it *does*.  This is the line that causes it to:
>
> > testInstance = (ServletTestCase)constructor.newInstance(new Object[] {
> theMethod });
>
> You see here you are explicitly referencing ServletTestCase which
> extends junit.framework.TestCase, this introduces the dependency.
>
> 2. You seem to be assuming that NoClassDefFoundError extends
> Exception, but it doesn't.  If you want to catch a
> NoClassDefFoundError you'll have to catch it directly, or one of
> its superclasses (java.lang.LinkageError, java.lang.Error, or
> java.lang.Throwable).  This is why "I would have thought here"
> never gets printed out:
>
> >   } catch (Exception e) {
> > log("I would have thought here");
> >   }
>
> As an aside, I'm not sure what you are trying to achieve here?
> You don't have junit.jar in your classpath, and then you're say
> you get this strange error.  The details aside, isn't that what
> you'd expect :-)?  Even if you hadn't referenced ServletTestCase
> directly, you still wouldn't have been able to instantiate it
> using reflection without junit.jar in the classpath.  What are
> you really trying to achieve?
>
> -- Andrew
>




Re: WebappClassLoader question

2001-07-27 Thread Craig R. McClanahan

Vincent, can you send me (privately) a WAR file that illustrates your
difficulties?  But with the code below, and JUnit not visible to the web
app, I would expect to get the error when instantiating B, due to its
direct reference to D, which has a reference to JUnit.

From my experiments (and experience on other apps), it doesn't make any
difference whether the application classes are packed into JARs in
/WEB-INF/lib or unpacked in /WEB-INF/classes (since these are all loaded
by the web app class loader).

Craig

On Fri, 27 Jul 2001, Vincent Massol wrote:

> Hi Craig,
> 
> Thanks again. I have tried it again and it still doesn't work. I'll narrow a
> bit more my example.
> 
> C.java
> ---
> public class C extend D
> {
> ...
> }
> ---
> 
> D.java
> ---
> import junit.framework.*;
> 
> public class D extends TestCase
> {
> ...
> }
> ---
> 
> and the exact code in class B:
> 
> B.java
> ---
> public class B
> {
>   public B()
>   {
>   }
>   public doSomething()
>   {
>  D testInstance = null;
>   try {
>   testClass = Class.forName("C");
>   Constructor constructor = testClass.getConstructor(new Class[] {
> String.class });
>   testInstance = (D)constructor.newInstance(new Object[] {
> "something" });
>   } catch (Exception e) {
> log("I would have thought here");
>   }
>   }
> }
> 
> The error I am getting between "before error" and "after error" is
> "java.lang.NoClassDefFoundError: junit/framework/TestCase".
> 
> ... so yes, class D (which depends on JUnit) is explicitely mentionned in
> class B. So, what you said in your first email is that it is normal
> (although yo have to agree it is very hard to debug and track and means I'll
> have to put a try catch around "B myB = new B()" in class A, which looks at
> bit surnatural ... :-) (I'll need to put a good comment to explain it at
> least!).
> 
> ... then in your second email you say it is working fine with the "I would
> have thought here" message printed ... so that's why I'm resending these
> additional details.
> 
> Classes A, B, and D are in a jar under WEB-INF/lib
> Class C is in WEB-INF/classes
> 
> Any idea. If not, I'll try to make the most simple example that reproduces
> what I have and I'll send it over.
> Thanks a lot.
> -Vincent
> 
> - Original Message -
> From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Cc: "Vincent Massol" <[EMAIL PROTECTED]>
> Sent: Thursday, July 26, 2001 10:08 PM
> Subject: Re: WebappClassLoader question
> 
> 
> 
> 
> On Thu, 26 Jul 2001, Craig R. McClanahan wrote:
> 
> > Hmm, I just tried a case like what you have below.  As long as B does not
> > explicitly reference class C, then it works.  In other words, in my
> > example where you've got the "// call the method by reflection" comment, I
> > added
> >
> >   Object c = myClass.newInstance();
> >
> > and got the class not found exception at "I would have thought here".  On
> > the other hand, if I changed the above line to:
> >
> >   C c = (C) myClass.newInstance();
> >
> > (and compiled with class C on the compiler classpath, but not in the
> > webapp), then I get the error in between "before error" and "after error".
> >
> > This makes sense, because the latter statement makes B explicitly
> > dependent on C, where the former doesn't.
> >
> > I'll mess around some more, playing with JAR-ing up some but not all the
> > classes involved.
> >
> 
> One more follow-up ... this works correctly for me with A and B in a jar
> file under /WEB-INF/lib, and C unpacked under /WEB-INF/classes as well.
> 
> > Craig
> >
> 
> Craig
> 
> 
> >
> > On Thu, 26 Jul 2001, Vincent Massol wrote:
> >
> > > Thanks Craig,
> > >
> > > However I am still not sure this mechanism explains the problem I had.
> It is
> > > not easy to describe in word so I'll write it in java code instead.
> > >
> > > A.java
> > > 
> > > public class A implements HttpServlet
> > > {
> > >   public void doGet()
> > >   {
> > > log("before error");
> > > B myB = new B();
> > > log("after error");
> > >   }
> > > }
> > > 
> > >
> > > B.java
> > > 
> > > public class 

RE: WebappClassLoader question

2001-07-27 Thread Jim Cheesman


> >
> > The problem is, Cactus (Jakarta's J2EE testing package) raises an
> > exception if junit.jar is not found; it should catch the exception and
> > kindly explain the situation to the user.
> >
> > Right now, the exception is raised in a strange place, and
> > thus the user
> > is faced with an abstruse error. That's what Vincent is
> > trying to solve.
> >
>
>A, Many Thanks.. i was really very lost here :)


It was my problem to start with ;)
Still, glad I had it as this has been an informative thread...




> > [Si los dos somos españoles, qué hacemos hablando en inglés? :]
>
>Para que estos pobreticos se enteren de algo, mientras aprenden Español,
>que todo llegara :)


Anda, que sois vosotros dos los guiris aquí!


Salu2
Jim.





--

   *   Jim Cheesman   *
 Trabajo: 
[EMAIL PROTECTED] - (34)(91) 724 9200 x 2360
   The shortest distance between 
two points is how far apart they are.





RE: WebappClassLoader question

2001-07-27 Thread Ignacio J. Ortega

> -Mensaje original-
> De: Alex Fernández [mailto:[EMAIL PROTECTED]]
> Enviado el: viernes 27 de julio de 2001 11:17
> Para: [EMAIL PROTECTED]
> Asunto: Re: WebappClassLoader question
> 
> 
> The problem is, Cactus (Jakarta's J2EE testing package) raises an
> exception if junit.jar is not found; it should catch the exception and
> kindly explain the situation to the user.
> 
> Right now, the exception is raised in a strange place, and 
> thus the user
> is faced with an abstruse error. That's what Vincent is 
> trying to solve.
> 

A, Many Thanks.. i was really very lost here :)


> [Si los dos somos españoles, qué hacemos hablando en inglés? :]

Para que estos pobreticos se enteren de algo, mientras aprenden Español,
que todo llegara :)

Saludos ,
Ignacio J. Ortega




Re: WebappClassLoader question

2001-07-27 Thread Vincent Massol


- Original Message -
From: "Andrew Inggs" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Friday, July 27, 2001 10:01 AM
Subject: RE: WebappClassLoader question


> Hi Vincent
>
> You seem to be missing at least two things here:
>
> 1. In your original post you said:
>
> > When I access the servlet, I get a ClassNotFoundException on a
> > JUnit class. So far it is normal ...
> > When I debugged it, I have actually found that the error was
> > happening when ServletTestRedirector was instancianting
> > MyProxyClass (which does _not_ make use of JUnit) and before
> > it was calling its method.
>
> This does not look right.  You say MyProxyClass does not make
> use of JUnit, but it *does*.  This is the line that causes it to:
>
> > testInstance = (ServletTestCase)constructor.newInstance(new Object[] {
> theMethod });
>
> You see here you are explicitly referencing ServletTestCase which
> extends junit.framework.TestCase, this introduces the dependency.
>

That's true. I may have used the wrong word. What I meant is that the
MyProxyClass did not have a JUnit import statement, meaning it did not make
a _direct_ use of JUnit. But as you point out, ServletTestCase does make a
direct use of JUnit.

> 2. You seem to be assuming that NoClassDefFoundError extends
> Exception, but it doesn't.  If you want to catch a
> NoClassDefFoundError you'll have to catch it directly, or one of
> its superclasses (java.lang.LinkageError, java.lang.Error, or
> java.lang.Throwable).  This is why "I would have thought here"
> never gets printed out:
>
> >   } catch (Exception e) {
> > log("I would have thought here");
> >   }
>

That's also true but that's the question I am asking ... ! Why do I get a
NoClassDefFoundError whereas I was expecting a ClassNotFoundException !
Please see Craig's answer and my other posts for a better description of
what error I am getting and what I am trying to achieve.

> As an aside, I'm not sure what you are trying to achieve here?
> You don't have junit.jar in your classpath, and then you're say
> you get this strange error.  The details aside, isn't that what
> you'd expect :-)?  Even if you hadn't referenced ServletTestCase
> directly, you still wouldn't have been able to instantiate it
> using reflection without junit.jar in the classpath.  What are
> you really trying to achieve?
>

As Alex kindly answered on the list, I would like to catch this error nicely
(when junit.jar is not in the classpath) so that I can display a good and
relevant message for the end user, telling him to put the class on the class
path ... When I debugged the code to know why I wasn't catching the
exception, I noticed that the error happened in a strange place, i.e. the
first class in the chain of dependencies and that's what I find strange. I
have had no previous experience of this kind of class loading mechanism and
I find it very very hard to debug (It means you have to put try catch blocks
everywhere in your first class being called in your webapp if you want to
catch for possible error resulting from classes not in the classapth !).

> -- Andrew

Thanks Andrew for your help!
-Vincent




Re: WebappClassLoader question

2001-07-27 Thread Alex Fernández

Hola Nacho,

"Ignacio J. Ortega" wrote:
> I'm lost here, where you put the Junit.jar? , because it will be on some
> place? no? to allow you load classes from , no?, i think you need the
> entire inheritance chain for resolving dependencies, so you need
> Junit.jar in some place in classpath AFAIK.. this is the simple dumb
> explanation i know, but is what i'm seeing on your example..

You're absolutely right here, Vincent's exception is raised because he
doesn't have junit.jar in his classpath.

The problem is, Cactus (Jakarta's J2EE testing package) raises an
exception if junit.jar is not found; it should catch the exception and
kindly explain the situation to the user.

Right now, the exception is raised in a strange place, and thus the user
is faced with an abstruse error. That's what Vincent is trying to solve.

[Si los dos somos españoles, qué hacemos hablando en inglés? :]

Un saludo,

Alex.

> Can you make a simple main example trying to do what you want to do,
> without involving a servlet container.. i dont know how you can load (
> using  reflection for it doesnt matter ) a class without his entire
> inheritance chain present ...
> 
> Only a wild thought, i'm not an expert on anything so... take it me too
> seriously .. :)
> 
> Saludos ,
> Ignacio J. Ortega



RE: WebappClassLoader question

2001-07-27 Thread Andrew Inggs

Hi Vincent

You seem to be missing at least two things here:

1. In your original post you said:

> When I access the servlet, I get a ClassNotFoundException on a
> JUnit class. So far it is normal ...
> When I debugged it, I have actually found that the error was
> happening when ServletTestRedirector was instancianting
> MyProxyClass (which does _not_ make use of JUnit) and before
> it was calling its method.

This does not look right.  You say MyProxyClass does not make
use of JUnit, but it *does*.  This is the line that causes it to:

> testInstance = (ServletTestCase)constructor.newInstance(new Object[] {
theMethod });

You see here you are explicitly referencing ServletTestCase which
extends junit.framework.TestCase, this introduces the dependency.

2. You seem to be assuming that NoClassDefFoundError extends
Exception, but it doesn't.  If you want to catch a
NoClassDefFoundError you'll have to catch it directly, or one of
its superclasses (java.lang.LinkageError, java.lang.Error, or
java.lang.Throwable).  This is why "I would have thought here"
never gets printed out:

>   } catch (Exception e) {
> log("I would have thought here");
>   }

As an aside, I'm not sure what you are trying to achieve here?
You don't have junit.jar in your classpath, and then you're say
you get this strange error.  The details aside, isn't that what
you'd expect :-)?  Even if you hadn't referenced ServletTestCase
directly, you still wouldn't have been able to instantiate it
using reflection without junit.jar in the classpath.  What are
you really trying to achieve?

-- Andrew



Re: WebappClassLoader question

2001-07-27 Thread Dmitri Colebatch

If B uses C and C extends D and D uses junit, then to do whatever it is
that B uses C for you will need the junit.jar.  I wasn't able to find
mention of where junit.jar is... sorry for my late joining of the thread -
is junit.jar in $TOMCAT_HOME/lib or WEB-INF/lib?

cheesr
dim

On Fri, 27 Jul 2001, Vincent Massol wrote:

> Hi Craig,
> 
> Thanks again. I have tried it again and it still doesn't work. I'll narrow a
> bit more my example.
> 
> C.java
> ---
> public class C extend D
> {
> ...
> }
> ---
> 
> D.java
> ---
> import junit.framework.*;
> 
> public class D extends TestCase
> {
> ...
> }
> ---
> 
> and the exact code in class B:
> 
> B.java
> ---
> public class B
> {
>   public B()
>   {
>   }
>   public doSomething()
>   {
>  D testInstance = null;
>   try {
>   testClass = Class.forName("C");
>   Constructor constructor = testClass.getConstructor(new Class[] {
> String.class });
>   testInstance = (D)constructor.newInstance(new Object[] {
> "something" });
>   } catch (Exception e) {
> log("I would have thought here");
>   }
>   }
> }
> 
> The error I am getting between "before error" and "after error" is
> "java.lang.NoClassDefFoundError: junit/framework/TestCase".
> 
> ... so yes, class D (which depends on JUnit) is explicitely mentionned in
> class B. So, what you said in your first email is that it is normal
> (although yo have to agree it is very hard to debug and track and means I'll
> have to put a try catch around "B myB = new B()" in class A, which looks at
> bit surnatural ... :-) (I'll need to put a good comment to explain it at
> least!).
> 
> ... then in your second email you say it is working fine with the "I would
> have thought here" message printed ... so that's why I'm resending these
> additional details.
> 
> Classes A, B, and D are in a jar under WEB-INF/lib
> Class C is in WEB-INF/classes
> 
> Any idea. If not, I'll try to make the most simple example that reproduces
> what I have and I'll send it over.
> Thanks a lot.
> -Vincent
> 
> - Original Message -
> From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Cc: "Vincent Massol" <[EMAIL PROTECTED]>
> Sent: Thursday, July 26, 2001 10:08 PM
> Subject: Re: WebappClassLoader question
> 
> 
> 
> 
> On Thu, 26 Jul 2001, Craig R. McClanahan wrote:
> 
> > Hmm, I just tried a case like what you have below.  As long as B does not
> > explicitly reference class C, then it works.  In other words, in my
> > example where you've got the "// call the method by reflection" comment, I
> > added
> >
> >   Object c = myClass.newInstance();
> >
> > and got the class not found exception at "I would have thought here".  On
> > the other hand, if I changed the above line to:
> >
> >   C c = (C) myClass.newInstance();
> >
> > (and compiled with class C on the compiler classpath, but not in the
> > webapp), then I get the error in between "before error" and "after error".
> >
> > This makes sense, because the latter statement makes B explicitly
> > dependent on C, where the former doesn't.
> >
> > I'll mess around some more, playing with JAR-ing up some but not all the
> > classes involved.
> >
> 
> One more follow-up ... this works correctly for me with A and B in a jar
> file under /WEB-INF/lib, and C unpacked under /WEB-INF/classes as well.
> 
> > Craig
> >
> 
> Craig
> 
> 
> >
> > On Thu, 26 Jul 2001, Vincent Massol wrote:
> >
> > > Thanks Craig,
> > >
> > > However I am still not sure this mechanism explains the problem I had.
> It is
> > > not easy to describe in word so I'll write it in java code instead.
> > >
> > > A.java
> > > 
> > > public class A implements HttpServlet
> > > {
> > >   public void doGet()
> > >   {
> > > log("before error");
> > > B myB = new B();
> > > log("after error");
> > >   }
> > > }
> > > 
> > >
> > > B.java
> > > 
> > > public class B
> > > {
> > >   public B()
> > >   {
> > >   }
> > >   public doSomething()
> > >   {
> > > try {
> > >   Class myClass = Class.forName("C");
&g

Re: WebappClassLoader question

2001-07-27 Thread Vincent Massol

Hi Craig,

Thanks again. I have tried it again and it still doesn't work. I'll narrow a
bit more my example.

C.java
---
public class C extend D
{
...
}
---

D.java
---
import junit.framework.*;

public class D extends TestCase
{
...
}
---

and the exact code in class B:

B.java
---
public class B
{
  public B()
  {
  }
  public doSomething()
  {
 D testInstance = null;
  try {
  testClass = Class.forName("C");
  Constructor constructor = testClass.getConstructor(new Class[] {
String.class });
  testInstance = (D)constructor.newInstance(new Object[] {
"something" });
  } catch (Exception e) {
log("I would have thought here");
  }
  }
}

The error I am getting between "before error" and "after error" is
"java.lang.NoClassDefFoundError: junit/framework/TestCase".

... so yes, class D (which depends on JUnit) is explicitely mentionned in
class B. So, what you said in your first email is that it is normal
(although yo have to agree it is very hard to debug and track and means I'll
have to put a try catch around "B myB = new B()" in class A, which looks at
bit surnatural ... :-) (I'll need to put a good comment to explain it at
least!).

... then in your second email you say it is working fine with the "I would
have thought here" message printed ... so that's why I'm resending these
additional details.

Classes A, B, and D are in a jar under WEB-INF/lib
Class C is in WEB-INF/classes

Any idea. If not, I'll try to make the most simple example that reproduces
what I have and I'll send it over.
Thanks a lot.
-Vincent

- Original Message -
From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Cc: "Vincent Massol" <[EMAIL PROTECTED]>
Sent: Thursday, July 26, 2001 10:08 PM
Subject: Re: WebappClassLoader question




On Thu, 26 Jul 2001, Craig R. McClanahan wrote:

> Hmm, I just tried a case like what you have below.  As long as B does not
> explicitly reference class C, then it works.  In other words, in my
> example where you've got the "// call the method by reflection" comment, I
> added
>
>   Object c = myClass.newInstance();
>
> and got the class not found exception at "I would have thought here".  On
> the other hand, if I changed the above line to:
>
>   C c = (C) myClass.newInstance();
>
> (and compiled with class C on the compiler classpath, but not in the
> webapp), then I get the error in between "before error" and "after error".
>
> This makes sense, because the latter statement makes B explicitly
> dependent on C, where the former doesn't.
>
> I'll mess around some more, playing with JAR-ing up some but not all the
> classes involved.
>

One more follow-up ... this works correctly for me with A and B in a jar
file under /WEB-INF/lib, and C unpacked under /WEB-INF/classes as well.

> Craig
>

Craig


>
> On Thu, 26 Jul 2001, Vincent Massol wrote:
>
> > Thanks Craig,
> >
> > However I am still not sure this mechanism explains the problem I had.
It is
> > not easy to describe in word so I'll write it in java code instead.
> >
> > A.java
> > 
> > public class A implements HttpServlet
> > {
> >   public void doGet()
> >   {
> > log("before error");
> > B myB = new B();
> > log("after error");
> >   }
> > }
> > 
> >
> > B.java
> > 
> > public class B
> > {
> >   public B()
> >   {
> >   }
> >   public doSomething()
> >   {
> > try {
> >   Class myClass = Class.forName("C");
> >   // call the method by reflection ...
> > } catch (Exception e) {
> >   log("I would have thought here");
> > }
> >   }
> > }
> > 
> >
> > C.java
> > 
> > import junit.framework.*;
> >
> > public class C extends TestCase
> > {
> > ...
> > }
> > 
> >
> > Now all of this is packaged in a war, classes A and B and in a jar put
in
> > WEB-INF/lib and class C is put in WEB-INF/classes. The junit jar is
*not*
> > put in WEB-INF/lib.
> >
> > Calling the servlet A result in an error occurring between the logs
"before
> > error" and "after error" and the log "I would have thought here" is
never
> > printed because the error happens _before_ ... This is what I don't
> > understand.
> >
> > Any idea ?
> > Thanks a lot
> > -Vincent
> >
> > - Original Message -
> > From: &quo

Re: WebappClassLoader question

2001-07-26 Thread Craig R. McClanahan



On Thu, 26 Jul 2001, Craig R. McClanahan wrote:

> Hmm, I just tried a case like what you have below.  As long as B does not
> explicitly reference class C, then it works.  In other words, in my
> example where you've got the "// call the method by reflection" comment, I
> added
> 
>   Object c = myClass.newInstance();
> 
> and got the class not found exception at "I would have thought here".  On
> the other hand, if I changed the above line to:
> 
>   C c = (C) myClass.newInstance();
> 
> (and compiled with class C on the compiler classpath, but not in the
> webapp), then I get the error in between "before error" and "after error".
> 
> This makes sense, because the latter statement makes B explicitly
> dependent on C, where the former doesn't.
> 
> I'll mess around some more, playing with JAR-ing up some but not all the
> classes involved.
> 

One more follow-up ... this works correctly for me with A and B in a jar
file under /WEB-INF/lib, and C unpacked under /WEB-INF/classes as well.

> Craig
> 

Craig


> 
> On Thu, 26 Jul 2001, Vincent Massol wrote:
> 
> > Thanks Craig,
> > 
> > However I am still not sure this mechanism explains the problem I had. It is
> > not easy to describe in word so I'll write it in java code instead.
> > 
> > A.java
> > 
> > public class A implements HttpServlet
> > {
> >   public void doGet()
> >   {
> > log("before error");
> > B myB = new B();
> > log("after error");
> >   }
> > }
> > 
> > 
> > B.java
> > 
> > public class B
> > {
> >   public B()
> >   {
> >   }
> >   public doSomething()
> >   {
> > try {
> >   Class myClass = Class.forName("C");
> >   // call the method by reflection ...
> > } catch (Exception e) {
> >   log("I would have thought here");
> > }
> >   }
> > }
> > 
> > 
> > C.java
> > 
> > import junit.framework.*;
> > 
> > public class C extends TestCase
> > {
> > ...
> > }
> > 
> > 
> > Now all of this is packaged in a war, classes A and B and in a jar put in
> > WEB-INF/lib and class C is put in WEB-INF/classes. The junit jar is *not*
> > put in WEB-INF/lib.
> > 
> > Calling the servlet A result in an error occurring between the logs "before
> > error" and "after error" and the log "I would have thought here" is never
> > printed because the error happens _before_ ... This is what I don't
> > understand.
> > 
> > Any idea ?
> > Thanks a lot
> > -Vincent
> > 
> > - Original Message -
> > From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
> > To: <[EMAIL PROTECTED]>; "Vincent Massol" <[EMAIL PROTECTED]>
> > Sent: Thursday, July 26, 2001 6:18 PM
> > Subject: Re: WebappClassLoader question
> > 
> > 
> > On Thu, 26 Jul 2001, Vincent Massol wrote:
> > 
> > > Thanks Alex,
> > >
> > > I don't think the standard classloader mechanism is involved here. I
> > believe
> > > it is a 'feature' of Tomcat and more specifically of it's
> > WebappClassLoader.
> > > When you do standard java code and you have the following situation :
> > >
> > > 1st -> 2nd --- (using reflection) --> 3rd (not in classpath)
> > >
> > > then the error always happen in the 2nd class and you can put the code
> > > between a try catch block and you'll be able to catch the
> > > ClassNotFoundException. However what happens here is that the error
> > happens
> > > when calling a method on the 1st class that instanciates the 2nd class !
> > > This is what I don't understand.
> > >
> > > Am I dreaming or is this a behaviour of Tomcat 4 ?
> > >
> > 
> > The web app class loader in Tomcat 4 is based on java.net.URLClassLoader,
> > and has the same basic class loading behavior.  In particular, when a
> > class A is loaded, all the classes that A directly references (i.e. listed
> > in import statements, used as a variable declaration, and so on) are also
> > loaded.  This is done recursively on the referenced classes, until the
> > entire tree of references is resolved.  If the load for class A fails, you
> > will get ClassNotFoundException.  However, if the load for one of the
> > referenced classes fails, you will typically get No

Re: WebappClassLoader question

2001-07-26 Thread Craig R. McClanahan

Hmm, I just tried a case like what you have below.  As long as B does not
explicitly reference class C, then it works.  In other words, in my
example where you've got the "// call the method by reflection" comment, I
added

  Object c = myClass.newInstance();

and got the class not found exception at "I would have thought here".  On
the other hand, if I changed the above line to:

  C c = (C) myClass.newInstance();

(and compiled with class C on the compiler classpath, but not in the
webapp), then I get the error in between "before error" and "after error".

This makes sense, because the latter statement makes B explicitly
dependent on C, where the former doesn't.

I'll mess around some more, playing with JAR-ing up some but not all the
classes involved.

Craig


On Thu, 26 Jul 2001, Vincent Massol wrote:

> Thanks Craig,
> 
> However I am still not sure this mechanism explains the problem I had. It is
> not easy to describe in word so I'll write it in java code instead.
> 
> A.java
> 
> public class A implements HttpServlet
> {
>   public void doGet()
>   {
> log("before error");
> B myB = new B();
> log("after error");
>   }
> }
> 
> 
> B.java
> 
> public class B
> {
>   public B()
>   {
>   }
>   public doSomething()
>   {
> try {
>   Class myClass = Class.forName("C");
>   // call the method by reflection ...
> } catch (Exception e) {
>   log("I would have thought here");
> }
>   }
> }
> 
> 
> C.java
> 
> import junit.framework.*;
> 
> public class C extends TestCase
> {
> ...
> }
> 
> 
> Now all of this is packaged in a war, classes A and B and in a jar put in
> WEB-INF/lib and class C is put in WEB-INF/classes. The junit jar is *not*
> put in WEB-INF/lib.
> 
> Calling the servlet A result in an error occurring between the logs "before
> error" and "after error" and the log "I would have thought here" is never
> printed because the error happens _before_ ... This is what I don't
> understand.
> 
> Any idea ?
> Thanks a lot
> -Vincent
> 
> - Original Message -
> From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>; "Vincent Massol" <[EMAIL PROTECTED]>
> Sent: Thursday, July 26, 2001 6:18 PM
> Subject: Re: WebappClassLoader question
> 
> 
> On Thu, 26 Jul 2001, Vincent Massol wrote:
> 
> > Thanks Alex,
> >
> > I don't think the standard classloader mechanism is involved here. I
> believe
> > it is a 'feature' of Tomcat and more specifically of it's
> WebappClassLoader.
> > When you do standard java code and you have the following situation :
> >
> > 1st -> 2nd --- (using reflection) --> 3rd (not in classpath)
> >
> > then the error always happen in the 2nd class and you can put the code
> > between a try catch block and you'll be able to catch the
> > ClassNotFoundException. However what happens here is that the error
> happens
> > when calling a method on the 1st class that instanciates the 2nd class !
> > This is what I don't understand.
> >
> > Am I dreaming or is this a behaviour of Tomcat 4 ?
> >
> 
> The web app class loader in Tomcat 4 is based on java.net.URLClassLoader,
> and has the same basic class loading behavior.  In particular, when a
> class A is loaded, all the classes that A directly references (i.e. listed
> in import statements, used as a variable declaration, and so on) are also
> loaded.  This is done recursively on the referenced classes, until the
> entire tree of references is resolved.  If the load for class A fails, you
> will get ClassNotFoundException.  However, if the load for one of the
> referenced classes fails, you will typically get NoClassDefError instead
> (and the class named in the error message may or may not be the one that
> is actually missing, which complicates debugging this problem tremendously
> :-).
> 
> A good rule of thumb to avoid this kind of problem -- if you need to add
> classes to your CLASSPATH at compile time (when rebuilding the entire
> app), be sure all of those classes are visible to the web app at runtime.
> 
> Using reflection, on the other hand, lets you defer loading of "dependent"
> classes until runtime, and you can deal with ClassNotFoundException errors
> that you might run into.  Note however that, even if you load a class
> dynamically, *that* class still contains direct references to other
> classes that must all be resolved in the manner described above.
&

RE: WebappClassLoader question

2001-07-26 Thread Ignacio J. Ortega

Hola Vincent: 

> -Mensaje original-
> De: Vincent Massol [mailto:[EMAIL PROTECTED]]
> Enviado el: jueves 26 de julio de 2001 22:20
> Para: Craig R. McClanahan; [EMAIL PROTECTED]
> Asunto: Re: WebappClassLoader question
> 
  

> Now all of this is packaged in a war, classes A and B and in 
> a jar put in
> WEB-INF/lib and class C is put in WEB-INF/classes. The junit 
> jar is *not*
> put in WEB-INF/lib.
> 

I'm lost here, where you put the Junit.jar? , because it will be on some
place? no? to allow you load classes from , no?, i think you need the
entire inheritance chain for resolving dependencies, so you need
Junit.jar in some place in classpath AFAIK.. this is the simple dumb
explanation i know, but is what i'm seeing on your example.. 

Can you make a simple main example trying to do what you want to do,
without involving a servlet container.. i dont know how you can load (
using  reflection for it doesnt matter ) a class without his entire
inheritance chain present ... 

Only a wild thought, i'm not an expert on anything so... take it me too
seriously .. :)

Saludos ,
Ignacio J. Ortega



> Calling the servlet A result in an error occurring between 
> the logs "before
> error" and "after error" and the log "I would have thought 
> here" is never
> printed because the error happens _before_ ... This is what I don't
> understand.
> 
> Any idea ?
> Thanks a lot
> -Vincent
> 
> - Original Message -
> From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>; "Vincent Massol" 
> <[EMAIL PROTECTED]>
> Sent: Thursday, July 26, 2001 6:18 PM
> Subject: Re: WebappClassLoader question
> 
> 
> On Thu, 26 Jul 2001, Vincent Massol wrote:
> 
> > Thanks Alex,
> >
> > I don't think the standard classloader mechanism is involved here. I
> believe
> > it is a 'feature' of Tomcat and more specifically of it's
> WebappClassLoader.
> > When you do standard java code and you have the following 
> situation :
> >
> > 1st -> 2nd --- (using reflection) --> 3rd (not in classpath)
> >
> > then the error always happen in the 2nd class and you can 
> put the code
> > between a try catch block and you'll be able to catch the
> > ClassNotFoundException. However what happens here is that the error
> happens
> > when calling a method on the 1st class that instanciates 
> the 2nd class !
> > This is what I don't understand.
> >
> > Am I dreaming or is this a behaviour of Tomcat 4 ?
> >
> 
> The web app class loader in Tomcat 4 is based on 
> java.net.URLClassLoader,
> and has the same basic class loading behavior.  In particular, when a
> class A is loaded, all the classes that A directly references 
> (i.e. listed
> in import statements, used as a variable declaration, and so 
> on) are also
> loaded.  This is done recursively on the referenced classes, until the
> entire tree of references is resolved.  If the load for class 
> A fails, you
> will get ClassNotFoundException.  However, if the load for one of the
> referenced classes fails, you will typically get 
> NoClassDefError instead
> (and the class named in the error message may or may not be 
> the one that
> is actually missing, which complicates debugging this problem 
> tremendously
> :-).
> 
> A good rule of thumb to avoid this kind of problem -- if you 
> need to add
> classes to your CLASSPATH at compile time (when rebuilding the entire
> app), be sure all of those classes are visible to the web app 
> at runtime.
> 
> Using reflection, on the other hand, lets you defer loading 
> of "dependent"
> classes until runtime, and you can deal with 
> ClassNotFoundException errors
> that you might run into.  Note however that, even if you load a class
> dynamically, *that* class still contains direct references to other
> classes that must all be resolved in the manner described above.
> 
> 
> > Thanks
> > -Vincent
> >
> 
> Craig McClanahan
> 
> PS:  One place where the Tomcat 4 class loader *does* vary 
> from the usual
> class loader behavior is in the order of places it looks to load a
> class.  The usual pattern in Java2 is to delegate to the parent class
> loader first, then look locally.  Tomcat 4 does the opposite 
> -- it checks
> in /WEB-INF/classes and /WEB-INF/lib of your web application *before*
> looking up the parent class loader chain.  This means that, 
> if you have a
> class in the $CATALINA_HOME/lib directory (shared across web 
> apps), and a
> version of that same class in your web app, the version in your webapp
>

Re: WebappClassLoader question

2001-07-26 Thread Vincent Massol

Thanks Craig,

However I am still not sure this mechanism explains the problem I had. It is
not easy to describe in word so I'll write it in java code instead.

A.java

public class A implements HttpServlet
{
  public void doGet()
  {
log("before error");
B myB = new B();
log("after error");
  }
}


B.java

public class B
{
  public B()
  {
  }
  public doSomething()
  {
try {
  Class myClass = Class.forName("C");
  // call the method by reflection ...
} catch (Exception e) {
  log("I would have thought here");
}
  }
}


C.java

import junit.framework.*;

public class C extends TestCase
{
...
}


Now all of this is packaged in a war, classes A and B and in a jar put in
WEB-INF/lib and class C is put in WEB-INF/classes. The junit jar is *not*
put in WEB-INF/lib.

Calling the servlet A result in an error occurring between the logs "before
error" and "after error" and the log "I would have thought here" is never
printed because the error happens _before_ ... This is what I don't
understand.

Any idea ?
Thanks a lot
-Vincent

- Original Message -
From: "Craig R. McClanahan" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>; "Vincent Massol" <[EMAIL PROTECTED]>
Sent: Thursday, July 26, 2001 6:18 PM
Subject: Re: WebappClassLoader question


On Thu, 26 Jul 2001, Vincent Massol wrote:

> Thanks Alex,
>
> I don't think the standard classloader mechanism is involved here. I
believe
> it is a 'feature' of Tomcat and more specifically of it's
WebappClassLoader.
> When you do standard java code and you have the following situation :
>
> 1st -> 2nd --- (using reflection) --> 3rd (not in classpath)
>
> then the error always happen in the 2nd class and you can put the code
> between a try catch block and you'll be able to catch the
> ClassNotFoundException. However what happens here is that the error
happens
> when calling a method on the 1st class that instanciates the 2nd class !
> This is what I don't understand.
>
> Am I dreaming or is this a behaviour of Tomcat 4 ?
>

The web app class loader in Tomcat 4 is based on java.net.URLClassLoader,
and has the same basic class loading behavior.  In particular, when a
class A is loaded, all the classes that A directly references (i.e. listed
in import statements, used as a variable declaration, and so on) are also
loaded.  This is done recursively on the referenced classes, until the
entire tree of references is resolved.  If the load for class A fails, you
will get ClassNotFoundException.  However, if the load for one of the
referenced classes fails, you will typically get NoClassDefError instead
(and the class named in the error message may or may not be the one that
is actually missing, which complicates debugging this problem tremendously
:-).

A good rule of thumb to avoid this kind of problem -- if you need to add
classes to your CLASSPATH at compile time (when rebuilding the entire
app), be sure all of those classes are visible to the web app at runtime.

Using reflection, on the other hand, lets you defer loading of "dependent"
classes until runtime, and you can deal with ClassNotFoundException errors
that you might run into.  Note however that, even if you load a class
dynamically, *that* class still contains direct references to other
classes that must all be resolved in the manner described above.


> Thanks
> -Vincent
>

Craig McClanahan

PS:  One place where the Tomcat 4 class loader *does* vary from the usual
class loader behavior is in the order of places it looks to load a
class.  The usual pattern in Java2 is to delegate to the parent class
loader first, then look locally.  Tomcat 4 does the opposite -- it checks
in /WEB-INF/classes and /WEB-INF/lib of your web application *before*
looking up the parent class loader chain.  This means that, if you have a
class in the $CATALINA_HOME/lib directory (shared across web apps), and a
version of that same class in your web app, the version in your webapp
wins.


> - Original Message -
> From: "Alex Fernández" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Sent: Wednesday, July 25, 2001 3:44 PM
> Subject: Re: WebappClassLoader question
>
>
> > Hi Vincent!
> >
> > I've run into the same situation a couple of times, when one class uses
> > a second class, and this second class uses a third one that is not
> > present.
> >
> > 1st -> 2nd -> 3rd (missing)
> >
> > One would think that instantiating the 2nd should give an error, but
> > that loading the 2nd and/or instantiating the 1st should be ok. In fact,
> > all of the behaviors raise exceptions.
> >
> > The following paragraph in ClassLoader 

Re: WebappClassLoader question

2001-07-26 Thread Craig R. McClanahan

On Thu, 26 Jul 2001, Vincent Massol wrote:

> Thanks Alex,
> 
> I don't think the standard classloader mechanism is involved here. I believe
> it is a 'feature' of Tomcat and more specifically of it's WebappClassLoader.
> When you do standard java code and you have the following situation :
> 
> 1st -> 2nd --- (using reflection) --> 3rd (not in classpath)
> 
> then the error always happen in the 2nd class and you can put the code
> between a try catch block and you'll be able to catch the
> ClassNotFoundException. However what happens here is that the error happens
> when calling a method on the 1st class that instanciates the 2nd class !
> This is what I don't understand.
> 
> Am I dreaming or is this a behaviour of Tomcat 4 ?
> 

The web app class loader in Tomcat 4 is based on java.net.URLClassLoader,
and has the same basic class loading behavior.  In particular, when a
class A is loaded, all the classes that A directly references (i.e. listed
in import statements, used as a variable declaration, and so on) are also
loaded.  This is done recursively on the referenced classes, until the
entire tree of references is resolved.  If the load for class A fails, you
will get ClassNotFoundException.  However, if the load for one of the
referenced classes fails, you will typically get NoClassDefError instead
(and the class named in the error message may or may not be the one that
is actually missing, which complicates debugging this problem tremendously
:-).

A good rule of thumb to avoid this kind of problem -- if you need to add
classes to your CLASSPATH at compile time (when rebuilding the entire
app), be sure all of those classes are visible to the web app at runtime.

Using reflection, on the other hand, lets you defer loading of "dependent"
classes until runtime, and you can deal with ClassNotFoundException errors
that you might run into.  Note however that, even if you load a class
dynamically, *that* class still contains direct references to other
classes that must all be resolved in the manner described above.


> Thanks
> -Vincent
> 

Craig McClanahan

PS:  One place where the Tomcat 4 class loader *does* vary from the usual
class loader behavior is in the order of places it looks to load a
class.  The usual pattern in Java2 is to delegate to the parent class
loader first, then look locally.  Tomcat 4 does the opposite -- it checks
in /WEB-INF/classes and /WEB-INF/lib of your web application *before*
looking up the parent class loader chain.  This means that, if you have a
class in the $CATALINA_HOME/lib directory (shared across web apps), and a
version of that same class in your web app, the version in your webapp
wins.


> - Original Message -
> From: "Alex Fernández" <[EMAIL PROTECTED]>
> To: <[EMAIL PROTECTED]>
> Sent: Wednesday, July 25, 2001 3:44 PM
> Subject: Re: WebappClassLoader question
> 
> 
> > Hi Vincent!
> >
> > I've run into the same situation a couple of times, when one class uses
> > a second class, and this second class uses a third one that is not
> > present.
> >
> > 1st -> 2nd -> 3rd (missing)
> >
> > One would think that instantiating the 2nd should give an error, but
> > that loading the 2nd and/or instantiating the 1st should be ok. In fact,
> > all of the behaviors raise exceptions.
> >
> > The following paragraph in ClassLoader javadoc might be of help:
> >
> > "The methods and constructors of objects created by a class loader may
> > reference other classes. To determine the class(es) referred to, the
> > Java virtual machine calls the loadClass method of the class loader that
> > originally created the class."
> >
> > Or, to find out what the JVM is doing, the spec is here:
> > http://java.sun.com/docs/books/vmspec/
> >
> > Hope it helps.
> >
> > Un saludo,
> >
> > Alex.
> >
> > > Vincent Massol wrote:
> > >
> > > Hi,
> > >
> > > Here is the situation :
> > >
> > > * I have a class that makes use of JUnit (by extending the JUnit
> > > TestCase class). Let's call it ServletTestCase
> > > * I have a second class that is used to call a method in
> > > ServletTestCase, let's call it MyProxyClass
> > > * I have a third class (a servlet) that does _not_ make use of JUnit.
> > > Let's call it ServletTestRedirector. This class actually instanciate
> > > MyProxyClass and calls one of its method.
> > > * I package these classes in a war file and I _don't_ include
> > > junit.jar in this war file
> > >
> > > When I access the servlet, I get a ClassNotFoundException on a JUnit

Re: WebappClassLoader question

2001-07-26 Thread Vincent Massol

Thanks Alex,

I don't think the standard classloader mechanism is involved here. I believe
it is a 'feature' of Tomcat and more specifically of it's WebappClassLoader.
When you do standard java code and you have the following situation :

1st -> 2nd --- (using reflection) --> 3rd (not in classpath)

then the error always happen in the 2nd class and you can put the code
between a try catch block and you'll be able to catch the
ClassNotFoundException. However what happens here is that the error happens
when calling a method on the 1st class that instanciates the 2nd class !
This is what I don't understand.

Am I dreaming or is this a behaviour of Tomcat 4 ?

Thanks
-Vincent

- Original Message -
From: "Alex Fernández" <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Wednesday, July 25, 2001 3:44 PM
Subject: Re: WebappClassLoader question


> Hi Vincent!
>
> I've run into the same situation a couple of times, when one class uses
> a second class, and this second class uses a third one that is not
> present.
>
> 1st -> 2nd -> 3rd (missing)
>
> One would think that instantiating the 2nd should give an error, but
> that loading the 2nd and/or instantiating the 1st should be ok. In fact,
> all of the behaviors raise exceptions.
>
> The following paragraph in ClassLoader javadoc might be of help:
>
> "The methods and constructors of objects created by a class loader may
> reference other classes. To determine the class(es) referred to, the
> Java virtual machine calls the loadClass method of the class loader that
> originally created the class."
>
> Or, to find out what the JVM is doing, the spec is here:
> http://java.sun.com/docs/books/vmspec/
>
> Hope it helps.
>
> Un saludo,
>
> Alex.
>
> > Vincent Massol wrote:
> >
> > Hi,
> >
> > Here is the situation :
> >
> > * I have a class that makes use of JUnit (by extending the JUnit
> > TestCase class). Let's call it ServletTestCase
> > * I have a second class that is used to call a method in
> > ServletTestCase, let's call it MyProxyClass
> > * I have a third class (a servlet) that does _not_ make use of JUnit.
> > Let's call it ServletTestRedirector. This class actually instanciate
> > MyProxyClass and calls one of its method.
> > * I package these classes in a war file and I _don't_ include
> > junit.jar in this war file
> >
> > When I access the servlet, I get a ClassNotFoundException on a JUnit
> > class. So far it is normal ...
> > When I debugged it, I have actually found that the error was happening
> > when ServletTestRedirector was instancianting MyProxyClass (which does
> > _not_ make use of JUnit) and before it was calling its method.
> >
> > Here is the stack trace I got :
> >
> > java.lang.NoClassDefFoundError: junit/framework/TestCase
> >  at java.lang.ClassLoader.defineClass0(Native Method)
> >  at java.lang.ClassLoader.defineClass(ClassLoader.java:486)
> >  at
> > java.security.SecureClassLoader.defineClass(SecureClassLoader.java:111)
> >  at
> >
org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLo
ader.java:1475)
> >  at
> >
org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.jav
a:836)
> >  at
> >
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.jav
a:1215)
> >  at
> >
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.jav
a:1098)
> >  at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:313)
> >  at
> >
org.apache.commons.cactus.server.ServletTestRedirector.doPost(ServletTestRed
irector.java:143)
> > Here is what I imagined is happening (tell me if this correct or wrong
> > !) :
> >
> > As MyProxyClass is within the war file, the WebappClassLoader gets
> > called to load it. The WebappClassLoader, in trying to find out the
> > correct class, actually loads some other class in memory, and thus the
> > ServletTestCase, which fails to load because the junit jar is not in
> > the classpath.
> >
> > Is that correct ?
> > Don't you find it strange that the error about the missing class is
> > reported when calling a class that has nothing to do with the problem
> > ? It gets very hard to catch errors ...
> >
> > For example, in MyProxyClass, the code that calls the ServletTestCase
> > method is as follows :
> >
> > ServletTestCase testInstance = null;
> > try {
> > testClass = Class.forName(theClassName);
> > Constructor constructor = testClass

Re: WebappClassLoader question

2001-07-25 Thread Alex Fernández

Hi Vincent!

I've run into the same situation a couple of times, when one class uses
a second class, and this second class uses a third one that is not
present.

1st -> 2nd -> 3rd (missing)

One would think that instantiating the 2nd should give an error, but
that loading the 2nd and/or instantiating the 1st should be ok. In fact,
all of the behaviors raise exceptions.

The following paragraph in ClassLoader javadoc might be of help:

"The methods and constructors of objects created by a class loader may
reference other classes. To determine the class(es) referred to, the
Java virtual machine calls the loadClass method of the class loader that
originally created the class."

Or, to find out what the JVM is doing, the spec is here:
http://java.sun.com/docs/books/vmspec/

Hope it helps.

Un saludo,

Alex.

> Vincent Massol wrote:
> 
> Hi,
> 
> Here is the situation :
> 
> * I have a class that makes use of JUnit (by extending the JUnit
> TestCase class). Let's call it ServletTestCase
> * I have a second class that is used to call a method in
> ServletTestCase, let's call it MyProxyClass
> * I have a third class (a servlet) that does _not_ make use of JUnit.
> Let's call it ServletTestRedirector. This class actually instanciate
> MyProxyClass and calls one of its method.
> * I package these classes in a war file and I _don't_ include
> junit.jar in this war file
> 
> When I access the servlet, I get a ClassNotFoundException on a JUnit
> class. So far it is normal ...
> When I debugged it, I have actually found that the error was happening
> when ServletTestRedirector was instancianting MyProxyClass (which does
> _not_ make use of JUnit) and before it was calling its method.
> 
> Here is the stack trace I got :
> 
> java.lang.NoClassDefFoundError: junit/framework/TestCase
>  at java.lang.ClassLoader.defineClass0(Native Method)
>  at java.lang.ClassLoader.defineClass(ClassLoader.java:486)
>  at
> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:111)
>  at
> 
>org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1475)
>  at
> org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:836)
>  at
> org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1215)
>  at
> org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1098)
>  at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:313)
>  at
> 
>org.apache.commons.cactus.server.ServletTestRedirector.doPost(ServletTestRedirector.java:143)
> Here is what I imagined is happening (tell me if this correct or wrong
> !) :
> 
> As MyProxyClass is within the war file, the WebappClassLoader gets
> called to load it. The WebappClassLoader, in trying to find out the
> correct class, actually loads some other class in memory, and thus the
> ServletTestCase, which fails to load because the junit jar is not in
> the classpath.
> 
> Is that correct ?
> Don't you find it strange that the error about the missing class is
> reported when calling a class that has nothing to do with the problem
> ? It gets very hard to catch errors ...
> 
> For example, in MyProxyClass, the code that calls the ServletTestCase
> method is as follows :
> 
> ServletTestCase testInstance = null;
> try {
> testClass = Class.forName(theClassName);
> Constructor constructor = testClass.getConstructor(new
> Class[] { String.class });
> testInstance =
> (ServletTestCase)constructor.newInstance(new Object[] { theMethod });
> } catch (Exception e) {
> logger.debug("Error instanciating class [" + theClassName
> + "]", e);
> e.printStackTrace();
> throw new ServletException("Error instanciating class [" +
> theClassName + "]", e);
> }
> And there is never any exception caught here  because the error
> happens earlier in the call stack, when the ServletTestRedirector
> instanciates MyProxyClass ...
> 
> ... or am I missing something ? :)
> 
> Thanks
> -Vincent Massol
>