28

TL;DR: I have a Spring MVC Hello, World! application that works on Tomcat 9. The same application on Tomcat 10 gives a 404 error for web request mappings.

The Problem

When deploying a Spring MVC 5 Hello, World! application to Tomcat 10, the application gives a 404 error for web request mappings. The same Hello, World! application works on Tomcat 9. It displays the Hello, World! message on Tomcat 9.

What I Expected

I expected the application to display the Hello, World! message on Tomcat 10.

Environment

  • MS Windows 10
  • Tomcat 10.0.2
  • Spring MVC 5.3.3

Research I Performed

I researched in the Spring Reference Manual, Section on Web Servlet. I also tested Spring MVC Tutorials online. These tutorials worked on Tomcat 9. However, the same tutorials failed on Tomcat 10. I also performed Google search on Tomcat 10. I saw references to Jakarta EE, but I am not sure if this is the source of the issue. Java EE 8 and Jakarta EE 8 are backwards compatible.

How to Reproduce

I created a very basic Hello, World! project to test this out. Here is the code that I'm using for the project.

File pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example.spring</groupId>
    <artifactId>example-spring</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.3</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.1</version>
            </plugin>
        </plugins>
    </build>
</project>

File ProjectInitializer.java

package com.example;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ProjectInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { PureJavaConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }
}

File PureJavaConfig.java

package com.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
@ComponentScan("com.example")
public class PureJavaConfig {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setSuffix(".jsp");
        resolver.setPrefix("/WEB-INF/jsp/");
        return resolver;
    }

}

File TutorialController.java

package com.example;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class TutorialController {

    @GetMapping("/")
    public String home() {
        return "home";
    }
}

File home.jsp

<html>
    <body>Hello, World! of Spring! <%= java.time.LocalDateTime.now() %></body>
</html>

This project runs okay on Tomcat 9. It displays the Hello, World! message. However, when I run on Tomcat 10, I get a 404 error message.

Piotr P. Karwasz
  • 12,857
  • 3
  • 20
  • 43
knelson59406
  • 751
  • 2
  • 6
  • 9
  • With no other details, it will be hard for anyone to help. Please take the [tour], visit the [help] and read [Ask] to learn how to use this site effectively. Your error message implies a large chunk of the Servlet implementation is missing, so it's likely an installation error or configuration error. – Jim Garrison Feb 16 '21 at 01:07
  • 1
    @JimGarrison - thank you sir for reference on how to ask question. I am sorry i did not follow the correct procedures. I have updated my question with more details, source code and expected outcome. – knelson59406 Feb 16 '21 at 02:35
  • since he has added all details, we should revert our down vote – LowCool Feb 16 '21 at 09:35

2 Answers2

44

TL;DR: Spring MVC 5 does not run on Tomcat 10 because of the package renaming from javax.* to jakarta.*.

After further research, I was able to find the answer to my question. Spring MVC 5 does not work on Tomcat 10. This is because Tomcat 10 is based on Jakarta EE 9 where package names for APIs have changed from javax.* to jakarta.*.

Tomcat 10 mentioned this on the download webpage:

Users of Tomcat 10 onwards should be aware that, as a result of the move from Java EE to Jakarta EE as part of the transfer of Java EE to the Eclipse Foundation, the primary package for all implemented APIs has changed from javax.* to jakarta.*. This will almost certainly require code changes to enable applications to migrate from Tomcat 9 and earlier to Tomcat 10 and later.

For Spring MVC 5, the Spring MVC DispatcherServlet has a dependency on the javax.servlet.* package namespace. This is using the Java EE 8 javax package naming. Since Tomcat 10 is based on Jakarta EE 9, the packages for javax naming are not supported. This explains why Spring MVC 5 does not work on Tomcat 10.

There are GitHub issues filed against the Spring Framework regarding this:

Spring core 5 is not starting on Tomcat 10

Support for Jakarta EE 9 (annotations and interfaces in jakarta.* namespace)

In my case, instead of migrating to Tomcat 10, I will stay on Tomcat 9 until the Spring framework is upgraded to Jakarta EE 9.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
knelson59406
  • 751
  • 2
  • 6
  • 9
  • 4
    In the second paragraph wrote `Spring MVC 5 does currently work on Tomcat 10`. So does it work or does it not? – izogfif Jul 21 '21 at 13:28
  • 4
    @izogfif: oh that was a typo. it does not work. I added the *not*. I made the edits to my answer: _Spring MVC 5 does *not* work on Tomcat 10._ – knelson59406 Aug 05 '21 at 13:52
  • How about spring MVC 6.0.9. I have also the same problem with the latest available versions. How did you solve this? – orcl user May 26 '23 at 07:34
0

The Problem as mentioned from @knelson is right. And painfull! :-/

For us it was not just Spring (6.0.10), it was just a lot of releated dependencies, Hibernate/JPA (6.2.2.Final), JAXB, Servlets API (6), Maven Plugins und so on.

I will suggest you to watch really nice video, i was watching of the IntelliJ colleages (Dalia Abo Sheasha):

https://youtu.be/mukr2Q_zBm4

There are some tipps how these task/migration could be less painful with the help of IntelliJ and maven dependencies analysis.

After that i was getting 404 Http Status calling a servlet. Issue was the flag metadata-complete from web.xml. I copied from the example that come with Tomcat and this was not setting right. For me it was needed metadata-complete="false" in the web.xml but from example it was true.

harryssuperman
  • 465
  • 3
  • 7