Search code examples
javamavenwarmaven-dependency

ClassNotFound With Maven WAR file


I looked around for a solution to this but could find anything reasonable. Most of them are related to JARs. I keep getting this frustrating error:

15-Jan-2020 11:36:06.605 SEVERE [Catalina-utility-1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [org.springframework.web.context.ContextLoaderListener] java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:269)

It comes from commons-logging.jar (1.2).

I have added my dependency, like:

<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
</dependency>

The version comes from the parent pom.xml

I have these two plugins of note:

<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>

and

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <inherited>false</inherited>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <addDefaultEntries>true</addDefaultEntries>
                <addBuildEnvironmentEntries>true</addBuildEnvironmentEntries>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                <classpathPrefix>WEB-INF/lib/</classpathPrefix>
            </manifest>
        </archive>
        <attachClasses>true</attachClasses>
        <classesClassifier>shared</classesClassifier>
        <failOnMissingWebXml>true</failOnMissingWebXml>
        <includeEmptyDirectories>true</includeEmptyDirectories>
        <outputDirectory>${project.basedir}\lib</outputDirectory>
        <webResources>
            <webResource>
                <directory>src/main/resources/ProcessOrderService</directory>
                <include>*.*</include>
                <targetPath>/ProcessOrderService/wsdl/</targetPath>
            </webResource>
        </webResources>
    </configuration>
</plugin>

I don't know what I am doing wrong. The kicker is, when I put the commons-logging.jar in the Tomcat's lib folder, It works like a charm.

There is a dependency that I have in this war file:

<dependency>
    <groupId>com.test.mypackage</groupId>
    <artifactId>common-files</artifactId>
    <version>${project.version}</version>
    <type>jar</type>
    <scope>provided</scope>
</dependency>

This also uses commons-logging, with the scope compile. But this dependency has to remain provided. Cant change that!

The only other dependency that might have caused a conflict or something was the activemq-core.jar but I added the exclusions parameter to it. But still didn't work.

Any help would be appreciated! Thanks!


Solution

  • Tomcat classloader considers the application local dependencies as last (https://tomcat.apache.org/tomcat-8.5-doc/class-loader-howto.html).

    My best guess there is already this library (different version) somewhere in the Tomcat classpath (not surprisingly as it is an Apache logging library).

    You can try to define the commons-logging as optional, it wont get transitively imported and will use whats available in Tomcat (assuming that version works fine with your code). Alternatively you need to find the library and replace/upgrade it.