ClassNotFoundException: how to find dependency conflict in Java

本秂侑毒 提交于 2019-12-22 12:07:32

问题


In a test WebSocket application using Atmosphere servlet I'm getting the following exception:

SEVERE: Servlet.service() for servlet AtmosphereServlet threw exception
java.lang.ClassNotFoundException: javax.servlet.AsyncContext
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1645)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1491)
    at org.atmosphere.cpr.AtmosphereServlet.doPost(AtmosphereServlet.java:191)
    at org.atmosphere.cpr.AtmosphereServlet.doGet(AtmosphereServlet.java:177)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)

From the below posts I understand that this might be caused by a Servlet container version older than Servlet 3.0:

ClassNotFoundException: javax.servlet.AsyncContext in Jetty hello world

ClassNotFoundException: javax.servlet.AsyncContext in Jetty hello world in eclipse

Grails project - Servlet call - ClassNotFoundException: javax.servlet.AsyncContext

However the application is running on Tomcat7, and the following dependency is added in pom.xml:

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

I've checked all other dependensies in the project and was not able to find anything else related to Servlet. Still I'm getting the exception.

Questions: How to find a jar file which is actually used by the application? How to find the dependency which is causing the usage of an old version?


回答1:


I was finally able to solve the dependency conflict by doing the following.

To find the jar file which is used by application I used the below simple code:

public void listJarFilesAndClassVersions() {    
    Class classToCheck = javax.servlet.ServletRequestWrapper.class;
    URL location = classToCheck.getResource('/'
        + classToCheck.getName().replace('.', '/') + ".class");

    System.out.println(location.toString());

    for(Package p : Package.getPackages()) {
        if (p.getName().startsWith("javax.servlet")) {
            System.out.println("Class: " + p.getName()
                + ", version: " + p.getSpecificationVersion());
        }
    }
}

The class javax.servlet.ServletRequestWrapper was chosen because it does exist in the old Servlet 2.5.

The execution of the above script gives me the following:

jar:file:/C:/Users/[username]/.m2/repository/org/apache/tomcat/servlet-api/6.0.29/servlet-api-6.0.29.jar!/javax/servlet/ServletRequestWrapper.class
Class: javax.servlet.jsp, version: 2.1
Class: javax.servlet, version: 2.5
Class: javax.servlet.http, version: null

So, first, it confirms that the Servlet of version 2.5 is used, and second, the "bad" jar is located in the maven repository under the tomcat directory.

After a short reasearch I was finally able to find the root cause of that: when deploying and running the maven application I need to specify the concrete version of tomcat, otherwise maven uses the libraries from tomcat of version 6. So the fix for me was to change

mvn -Dmaven.tomcat.port=8080 tomcat:run-war

to

mvn -Dmaven.tomcat.port=8080 tomcat7:run-war

Now if I execute the above script it gives the following result:

jar:file:/C:/Users/[username]/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/7.0.47/tomcat-embed-core-7.0.47.jar!/javax/servlet/ServletRequestWrapper.class
Class: javax.servlet.jsp, version: 2.2
Class: javax.servlet, version: 7.0
Class: javax.servlet.http, version: 7.0
Class: javax.servlet.annotation, version: 7.0
Class: javax.servlet.descriptor, version: 7.0

Hope it helps others who is running into the same issue.




回答2:


There're two ways in which I usually find a conflict.

  1. If you are using Eclipse, open the pom.xml in IDE, and switch to "Dependency Hierarchy" tab. In the left panel is the dependency tree, and in the right panel are the dependencies actually getting used. Right after each dependency it's its scope (eg. compile / test / runtime / omitted for conflict)

  1. In terminal run the command. mvn dependency:tree It will print out the dependency like in Eclipse.


来源:https://stackoverflow.com/questions/41286715/classnotfoundexception-how-to-find-dependency-conflict-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!