I want to enable the following scenario:
-
my web application (WAR file) is deployed on Tomcat on its own
-
my web application provides an API for extensions in the form of an
IFaceinterface andAbstractIFaceabstract base implementation, whose class files are deployed within the WAR file -
extensions to the applications are delivered as JAR files to be placed somewhere in the classpath (i.e. external to the WAR)
I compiled a ConcreteIFace class which extends AbstractIFace and packaged it into a JAR. I put the JAR in $TOMCAT_HOME/lib and deployed the WAR in webapps. When I try the following from a servlet in the WAR:
Class clazz = Class.forName("ConcreteIFace");
I get the following stack trace:
java.lang.NoClassDefFoundError: AbstractIFace
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
java.lang.ClassLoader.defineClass(ClassLoader.java:615)
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
java.net.URLClassLoader.access$000(URLClassLoader.java:58)
java.net.URLClassLoader$1.run(URLClassLoader.java:197)
java.security.AccessController.doPrivileged(Native Method)
java.net.URLClassLoader.findClass(URLClassLoader.java:190)
java.lang.ClassLoader.loadClass(ClassLoader.java:306)
java.lang.ClassLoader.loadClass(ClassLoader.java:247)
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Class.java:247)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1698)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1556)
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Class.java:169)
com.backbase.sample.DummyServlet.service(DummyServlet.java:14)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
A similar stack trace is presented if ConcreteIFace directly implements IFace instead of going through AbstractIFace
My questions are:
-
as all the required classes are in the application classpath, why do I have
NoClassDefFound? -
is it even possible to achieve the scenario I presented at the beginning? If so, how?
In web applications, the classpath is segregated. The web applications cannot see each-other’s classes, Tomcat cannot see the apps’ classes, the apps cannot see Tomcat’s internal classes (only the exposed interfaces like the Servlet API).
Web applications are supposed to be self-contained, and container-independent.
The easiest way would be to re-package the war file to also include the plugins.
Other options include going up to enterprise archives, which can have interdependencies, or embedding the web server in the application (as opposed to the other way around).