Java.Lang.Nosuchmethoderror: Javax.Servlet.Servletcontext.Getcontextpath()Ljava/Lang/String;

java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;

java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String;

That method was added in Servlet 2.5.

So this problem can have at least 3 causes:

  1. The servlet container does not support Servlet 2.5.
  2. The web.xml is not declared conform Servlet 2.5 or newer.
  3. The webapp's runtime classpath is littered with servlet container specific JAR files of a different servlet container make/version which does not support Servlet 2.5.

To solve it,

  1. Make sure that your servlet container supports at least Servlet 2.5. That are at least Tomcat 6, Glassfish 2, JBoss AS 4.1, etcetera. Tomcat 5.5 for example supports at highest Servlet 2.4. If you can't upgrade Tomcat, then you'd need to downgrade Spring to a Servlet 2.4 compatible version.
  2. Make sure that the root declaration of web.xml complies Servlet 2.5 (or newer, at least the highest whatever your target runtime supports). For an example, see also somewhere halfway our servlets wiki page.
  3. Make sure that you don't have any servlet container specific libraries like servlet-api.jar or j2ee.jar in /WEB-INF/lib or even worse, the JRE/lib or JRE/lib/ext. They do not belong there. This is a pretty common beginner's mistake in an attempt to circumvent compilation errors in an IDE, see also How do I import the javax.servlet API in my Eclipse project?.

java.lang.NoSuchMethodError: javax.servlet.ServletContext.getContextPath()Ljava/lang/String when deploying to Tomcat in cargo

The first answer to the question bound the build to a concrete setup on a local machine. One may be able to replicate that on a build server but it will be clumsy and error prone. I personally prefer to configure build so it works without any external dependency. I also had to compromise on that when we needed to run database migration or when we wanted to test RabbitMQ and there was no embedded broker available but at least the app run was self-contained.

Hence, if I were you I would dig deeper and make a configuration that is able to handle your use case without such a local folder. I cannot provide working answer for you since I lack information (your cargo configuration). But I would point you to the org.apache.tomcat.maven.tomcat7-maven-plugin. It worked very well for us. I used Cargo on another project and I find the tomcat7 plugin easier to use.

You can provide your own server.xml: Run Tomcat and deploy project with own server.xml

You can specify (add/override) dependencies in the <dependencies> section - which should solve your servlet-api version problem.

You can add a custom configuration (say some properties files which we put in the lib folder to get them on classpath) by adding them as a dependency in a jar.

It's quite versatile and simple way to get embedded Tomcat up and running. Hope that can help you.

Maybe to give you some primer on the tomcat7 plugin config:

<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>tomcat-run</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run-war-only</goal>
</goals>
<configuration>
<webapps>
<webapp>
<groupId>${project.groupId}</groupId>
<artifactId>project-web</artifactId>
<version>${project.version}</version>
<type>war</type>
<asWebapp>true</asWebapp>
<contextPath>/project-path</contextPath>
</webapp>
</webapps>
<protocol>org.apache.coyote.http11.Http11NioProtocol</protocol>
<port>${app.port}</port>
<fork>true</fork>
</configuration>
</execution>
<execution>
<id>tomcat-shutdown</id>
<phase>post-integration-test</phase>
<goals>
<goal>shutdown</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>project-test-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>

To explain the above a bit. We used JaCoCo to collect integration test coverage for Sonar. We needed a specific Tomcat version (to test it works on the version provided by operations) and we have overridden some of the server.xml configuration directly by <port> and <protocol> directives.

Getting NoSuchMethodError: javax.servlet.ServletContext.addServlet in Spring Boot while running a Spring MVC application

If you want to find out where the class is being loaded from, try

java -verbose:class -jar foo.jar | grep javax.servlet.ServletContext

where foo.jar is the fat JAR produced by Gradle or Maven. For example, the ServletContext class could be getting read from an older servlet-api JAR in a JDK extensions directory instead of your Maven or Gradle dependencies.

The output of the command looks something like this...

$ java -verbose:class -jar build/libs/foo-0.2.3.jar | grep javax.servlet.ServletContext
[Loaded javax.servlet.ServletContext from jar:file:.../build/libs/foo-0.2.3.jar!/lib/javax.servlet-api-3.1.0.jar!/]
[Loaded javax.servlet.ServletContextListener from jar:file:.../build/libs/foo-0.2.3.jar!/lib/javax.servlet-api-3.1.0.jar!/]
[Loaded javax.servlet.ServletContextAttributeListener from jar:file:.../build/libs/foo-0.2.3.jar!/lib/javax.servlet-api-3.1.0.jar!/]

java.lang.NoSuchMethodError because of duplicate class available in lib folder of Tomcat

Try to add javax.persistence-api-2.2.jar as a dependency in your project and remove it from tomcat lib, the reason for that the /WEB-INF/lib/*.jar of your web application will be loaded first if web application class loader is not configured with delegate="true

Normal Order:

  1. Bootstrap classes of your JVM (Core java classes)
  2. /WEB-INF/classes of your web application
  3. /WEB-INF/lib/*.jar of your web application
  4. System class loader classes (Tomcat / Classpath specific classes)
  5. Common class loader classes (classes common to all web apps)

With delegate="true" then order:

  1. Bootstrap classes of your JVM (Core java classes)
  2. System class loader classes (Tomcat / Classpath specific classes)
  3. Common class loader classes (classes common to all web apps)
  4. /WEB-INF/classes of your web application
  5. /WEB-INF/lib/*.jar of your web application


Related Topics



Leave a reply



Submit