views:

2197

answers:

3

I've been spending hours trying to figure out why I've been getting the java.lang.NoClassDefFoundError, and I've narrowed down the cause to Tomcat's classpath.

I used the code below to see what the path variables hold:

out.println("Classpath: '" + System.getProperty( "java.class.path" ) + "'" );
out.println("Ext dirs: '" + System.getProperty( "java.ext.dirs" ) + "'" );
out.println("Library path: '" + System.getProperty( "java.library.path" ) + "'" );
out.println("Path separator: '" + System.getProperty( "path.separator" ) + "'" );

And the output is:

Classpath: ':/usr/local/tomcat/bin/bootstrap.jar'
Ext dirs: '/usr/lib/jvm/java-6-sun-1.6.0.16/jre/lib/ext:/usr/java/packages/lib/ext'
Library path: '/usr/lib/jvm/java-6-sun-1.6.0.16/jre/lib/i386/server:/usr/lib/jvm/java-6-sun-1.6.0.16/jre/lib/i386:/usr/lib/jvm/java-6-sun-1.6.0.16/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib'
Path separator: ':'

As you can see, Classpath does NOT start with "." as it's supposed to, and I believe that's why my program can't find the classes that I import from subdirectories in my webapp.

To see where the classpath is set, i did grep -R bootstrap.jar /usr/local/tomcat/, and came accross this: CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar (in file /usr/local/tomcat/bin/catalina.sh)

This makes me believe that for some reason $CLASSPATH is empty here. However, echo $CLASSPATH successfully returns .:/usr/lib/jvm/java-6-sun/bin:/usr/local/tomcat/lib/servlet-api.jar

Can anybody help pin down the problem here?


EDIT: All my servlet files are in WEB-INF/classes/controllers/, and the libraries i'm trying to load are class files in subdirectories. For example, if ClassName.class is in the WEB-INF/classes/controllers/packagename/ directory, I add package packagename to the start of ClassName.java, and I import it using import packagename.* in someServlet.java.


EDIT2: I have solved my problem. My main issue was that, as written below, not using the correct package names. Also, I was trying to compile from inside the classes/controllers/ directory, instead of compiling from classes/. Thank you all for your help!

+5  A: 

Classes required in a web application should be located within the web application in the WEB-INF/classes folder or packed in JAR files located in WEB-INF/lib. You should normally not use the servlet containers generic classpath settings for this, as you seem to attempt.

jarnbjo
all my servlets are in WEB-INF/classes/controllers, and the classes i'm trying to load are *.class files in subdirectories.my issue is that since "." doesn't appear to be in my web app's classpath, loading libraries from subdirectories does not work.
Murat Ayfer
The correct package for a class file located in WEB-INF/classes/controllers/packagename/ClassName.class would be "controllers.packagename" and not "packagename" as your question seem to imply. You cannot have additional subdirectories below WEB-INF/classes as class path roots and the system properties or environment variables are in a web application not evaluated by the class loader as they are in a standalone appplication.
jarnbjo
. would likely refer to the startup script of tomcat, not the webapp.
nos
+3  A: 

Tomcat's classpath is not supposed to be starting with .. Actually, adding . to the classpath is just a convenient way to tell java to look for classes in the current directory without having to use -cp when using it on the command line.

Actually, in most case, you don't have to tweak Tomcat's classpath. To make Tomcat able to find your classes, what you need to do is to deploy your application as a standardized WAR (web archive) which has a specific layout. Something like that:

.
|-- WEB-INF
|   |-- classes
|   |   `-- com
|   |       `-- mycompany
|   |           `-- MyServlet.class
|   |-- lib
|   |   |-- bar.jar
|   |   `-- foo.jar
|   `-- web.xml
|-- application.jsp
|-- image.gif
`-- index.html

The WEB-INF/classes directory is where your compiled classes need to be, this is where Tomcat will look for them. If you place your classes in WEB-INF/classes/controllers, controllers will be considered as part of the package name (which is likely not what you want). So you have two options:

  1. remove that controllers directory
  2. or add it to the package name.

But they are mutually exclusive, you can't have both.

Pascal Thivent
+1  A: 
erickson