I'm not sure if this is the right place to ask this, but I'll go ahead anyway! I am trying to deploy a JAR that I built with maven into the Tomcat/lib folder. The problem I'm having is that all the classpath JARs for the JAR that I built, aren't getting read. So I am having to explicitly add those JARs to Tomcat's lib folder as well. Is this the expected behavior for Tomcat? Or am I doing something wrong with the Maven build/plugins? My JAR and classpath plugins are done like:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<addDefaultEntries>true</addDefaultEntries>
<addBuildEnvironmentEntries>true</addBuildEnvironmentEntries>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
<attachClasses>true</attachClasses>
<includeEmptyDirectories>true</includeEmptyDirectories>
<outputDirectory>${project.basedir}\target</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<id>pal-copy-dependencies</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<inherited>false</inherited>
<configuration>
<excludeScope>provided</excludeScope>
<excludeClassifiers>shared</excludeClassifiers>
<excludeTransitive>true</excludeTransitive>
<outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<silent>true</silent>
<useBaseVersion>false</useBaseVersion>
</configuration>
</execution>
</executions>
</plugin>
For example, if I have the dependency:
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
</dependency>
I keep getting the error:
09-Jan-2020 16:33:40.347 SEVERE [main] org.apache.catalina.core.ApplicationContext.log Servlet.init() for servlet [InitialiseDAC] threw exception
java.lang.NoClassDefFoundError: org/jasypt/util/text/AES256TextEncryptor
at com.provisioning.common.crypto.Decrypt.doDecrypt(Decrypt.java:192)
It only works when I make the dependency like:
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
<scope>provided</scope>
</dependency>
And put the jasypt.jar in the Tomcat's lib folder.
Is this normal for Tomcat?
There are two reasons, why you are getting
ClassNotFoundException
s andNoClassDefFoundError
s.A jar inside jar project
Unless I am mistaken, you are trying to use the Maven dependency plugin to copy all dependency jars into your jar file. A jar inside jar configuration will not work unless you are using a custom class loader. The only noticeable effect you are getting is a bigger jar file.
When you are building the jar project, you don't need to worry about deploying dependencies, just list them in the POM file. The hard work of collecting them should be done in the web application WAR project.
Tomcat's classpath
Tomcat has a complex classloader hierarchy, which allows every web application to use a different version of the same library. In the standard configuration (cf.
catalina.properties
):${catalina.base}/lib
and${catalina.home}/lib
folders (which by default are equal to thelib
folder of your Tomcat installation) are loaded by the common classloader.WEB-INF/classes
and jars in theWEB-INF/lib
folder (or WAR archive) are loaded by the web application class loader.As a rule you should not put any new library in the common class loader's classpath, since this is administered by the Tomcat server admin, not the Java developer. As an exception you may assume the
lib
folder contains:You should put all the dependencies in the
WEB-INF/lib
folder of your WAR archive. Maven's dependency plugin can help you with that.