Note a jar package conflict that caused the project to fail to start [java.lang.NoSuchMethodError:javax.servlet.ServletContext]

Keywords: Programming Java Jetty Apache Eclipse

Ever since I figured it out Under idea, Jetty uses the main method to start the web project After that, I was ready to start other web projects with jetty. Unfortunately, the first project encountered problems. Here is a record of the whole process of investigation and treatment.

1. Abnormal occurrence

Project press Under idea, Jetty uses the main method to start the web project After the configuration described in the article, the following abnormalities were found in the operation:

java.lang.NoSuchMethodError: javax.servlet.ServletContext.getJspConfigDescriptor()Ljavax/servlet/descriptor/JspConfigDescriptor;
	at org.apache.jasper.servlet.TldScanner.scanJspConfig(TldScanner.java:158)
	at org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104)
	at org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:103)
	......

Looking at javax.servlet.ServletContext in idea, we found that there are four jar packages with this class, respectively:

  • javax.servlet-api-3.0.1.jar
  • tomcat-embed-core-9.0.13.jar
  • javax.servlet-api-3.1.0.jar
  • servlet-api-2.4.jar

Why are there so many servlet-api versions? Mainly because in the current project, there are other web modules, because version control is not good, each web module uses a different servlet-api, in addition, there are some jar packages in the introduction, accidentally introduced the jar package of servlet-api.

So it's urgent to find out which jar package the javax.servlet.ServletContext in the web module comes from.

2. View the class introduction path

To find out how classes are loaded in the project, you need to add - verbose:class in the jvm startup parameter:

3. Start and view console logs

Once again, you can see that the console has typed out the class loading information, including the class name, the jar package location:

[Opened C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.io.Serializable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Comparable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.CharSequence from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.String from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.reflect.AnnotatedElement from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.reflect.GenericDeclaration from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.reflect.Type from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Class from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Cloneable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.ClassLoader from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.System from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Throwable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
......

The class with problems in the exception is javax.servlet.ServletContext. In the log search, the following records are found:

[Loaded javax.servlet.ServletContext from file:/C:/Users/Administrator/.m2/repository/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar]

As you can see, in the project, the javax.servlet.ServletContext class was introduced by the servlet-api-2.4.jar package.

For "How to Search in the Console", you can copy a console log into a text editor, such as notepad++, vscode, etc., and then use the search function.

4. Use maven to locate the source of jar packages

It is known that the javax.servlet.ServletContext class in the project was introduced by the servlet-api-2.4.jar package, but where did servlet-api-2.4.jar come from? The project jar package is managed by maven, so the mvn command is used to find the jar package introduction. The command is as follows:

mvn dependency:tree -Dverbose -Dincludes=*:*servlet*

After running, the console output is as follows:

[INFO] com.test:test-web:war:0.0.1-SNAPSHOT
[INFO] +- javax.servlet:servlet-api:jar:2.4:provided
[INFO] +- org.eclipse.jetty:jetty-webapp:jar:9.3.2.v20150730:test
[INFO] |  \- org.eclipse.jetty:jetty-servlet:jar:9.3.2.v20150730:test
[INFO] \- org.eclipse.jetty:apache-jsp:jar:9.3.2.v20150730:test
[INFO]    +- org.eclipse.jetty:jetty-server:jar:9.3.2.v20150730:test
[INFO]    |  \- (javax.servlet:javax.servlet-api:jar:3.1.0:test - omitted for duplicate)
[INFO]    \- javax.servlet:javax.servlet-api:jar:3.1.0:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

As you can see, the servlet-api version introduced in the project is 2.4, while the servlet-api version used by jetty is 3.1.0, which leads to the use of a lower version of the servlet-api in jetty, thus causing an exception.

Understanding the problem, the solution is simple, as long as the version of the project servlet-api is upgraded from 2.4 to 3.1.0.

Posted by wystan on Tue, 23 Apr 2019 13:30:34 -0700