0

I'm following the guide Building an Application with Spring Boot. My goal is to run the project in my Tomcat server.

First, I could run the project locally in intellij.

Then, I created a war called sample.war and deployed it to my Tomcat server by following 12.17.1. Create a Deployable War File. I then put the war to the directory webapps/sample.war. However, it fails to run. The key error (for full log please see below):

2021-08-26 16:40:37,453 [localhost-startStop-15] ERROR o.s.b.SpringApplication - Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>serving-web-content-complete</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>serving-web-content-complete</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

       <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <scope>provided</scope>
      </dependency>
       
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

servingwebcontent\GreetingController.java:

package com.example.servingwebcontent;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class GreetingController {
    @GetMapping("/greeting")
    public String greeting(@RequestParam(name = "name", required = false, defaultValue = "World") String name, Model model) {
        model.addAttribute("name", name);
        return "greeting";
    }
}

ServingWebContentApplication.java

package com.example.servingwebcontent;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class ServingWebContentApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ServingWebContentApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(ServingWebContentApplication.class, args);
    }
}

Server information:

Server version: Apache Tomcat/8.5.20
Server number: 8.5.20.0
OS Name: Linux
OS Version: 5.4.0-77-generic

Below please see the error log from catalina.out:

26-Aug-2021 16:40:35.813 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/sample]
26-Aug-2021 16:40:35.824 INFO [localhost-startStop-15] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/opt/apache-tomcat-8.5.20/webapps/sample.war]
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/apache-tomcat-8.5.20/lib/news-client-0.7.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/apache-tomcat-8.5.20/webapps/sample/WEB-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.2)

2021-08-26 16:40:37,453 [localhost-startStop-15] ERROR o.s.b.SpringApplication - Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type
Exception Details:
  Location:
    org/springframework/http/converter/json/Jackson2ObjectMapperBuilder$SmileFactoryInitializer.create()Lcom/fasterxml/jackson/core/JsonFactory; @7: areturn
  Reason:
    Type 'com/fasterxml/jackson/dataformat/smile/SmileFactory' (current frame, stack[0]) is not assignable to 'com/fasterxml/jackson/core/JsonFactory' (from method signature)
  Current Frame:
    bci: @7
    flags: { }
    locals: { 'org/springframework/http/converter/json/Jackson2ObjectMapperBuilder$SmileFactoryInitializer' }
    stack: { 'com/fasterxml/jackson/dataformat/smile/SmileFactory' }
  Bytecode:
    0x0000000: bb00 0359 b700 04b0                    

    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338)
    at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:175)
    at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:155)
    at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:97)
    at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:174)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5196)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:988)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1860)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'formContentFilter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.filter.OrderedFormContentFilter]: Factory method 'formContentFilter' threw exception; nested exception is java.lang.VerifyError: Bad return type

[nipped with more of the same errors]

26-Aug-2021 16:40:37.531 INFO [localhost-startStop-15] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/opt/apache-tomcat-8.5.20/webapps/sample.war] has finished in [1,708] ms

Here's what I've tried so far:

  1. I have the exact problem mentioned in ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. I've followed the advice of the three cases but to no avail:

    Case 1: @SpringBootApplication annotation isn't missing

    Case 2: not applicable because my project is a web project

    Case 3: I don't use spring-boot-starter-webflux

  2. I have the exact problems mentioned in Unable to start embedded Tomcat org.springframework.context.ApplicationContextException but we don't have the same cause.

  3. I have tried adding using an older version of com.fasterxml.jackson.core like 2.8.10 as mentioned in java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/JsonFactory, but to no avail.

Any help is very, very much appreciated.

seenukarthi
  • 8,241
  • 10
  • 47
  • 68
kohane15
  • 809
  • 12
  • 16
  • 1
    Spirng Boot 2.5 requires Tomcat 9. – M. Deinum Aug 26 '21 at 09:04
  • 1
    @M.Deinum: do you have a reference? As far as I understand the [baseline requirements](https://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-Spring-Framework-5.x#jdk-8-and-java-ee-7-baseline) of Spring 5.x are Servlet 3.1. Servlet 4.0 is used if available. – Piotr P. Karwasz Aug 26 '21 at 09:13
  • 2
    _"SLF4J: Found binding in [jar:file:/opt/apache-tomcat-8.5.20/lib/news-client-0.7.2.jar"_: you have a modified Tomcat installation. Please try on a clean installation or provide the list of libraries you added in `/opt/apache-tomcat-8.5.20/lib`. – Piotr P. Karwasz Aug 26 '21 at 09:16
  • 1
    I thought the minimum for Boot (not Spring itself) is tomcat 9. But looking at the verify error, you probably have a duplicate servlet-api somewhere inyour path in a different classloader, leading to all sorts of issues. – M. Deinum Aug 26 '21 at 09:20
  • 1
    A copy of [`jackson-dataformat-smile`](https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-smile) must be in the server's classpath and it's detected by the `ServiceLoader`. If that library really must be there (probably not), there should be a way to disable automatic detection. – Piotr P. Karwasz Aug 26 '21 at 09:32
  • @PiotrP.Karwasz Thank you for looking into the log. I don't have admin rights to change any Tomcat settings. Is there any way I could disable automatic detection of `jackson-dataformat-smile` without touching Tomcat? Thank you again. – kohane15 Aug 27 '21 at 07:46
  • @M.Deinum I could successfully run the sample project in my local machine with a fresh install of Tomcat (version `8.5.20`). Is there a way to solve this clashing of classloader issue? Thank you. – kohane15 Aug 27 '21 at 07:55
  • 1
    THe problem (as pointed out others as well) is that you have shared libraries in that tomcat installation, one of those includes the culprit. Do you really need those shared libraries in there, if not remove them, else I think you are in a tight spot. I don't think you can switch classloader orders in tomcat. – M. Deinum Aug 27 '21 at 08:04

1 Answers1

1

As stated in the comments, the problem comes from a jackson-dataformat-smile library that your system administrator put in Tomcat's classpath.

If you really can't get rid of it you can use one of three solutions:

  1. Add the library to your project dependencies (it will override the one in Tomcat's classpath),

  2. Disable the MappingJackson2SmileHttpMessageConverter: unlike previously stated the SmileFactory is not detected by the ServiceLoader, but called explicitly by Spring if it detects the factory on its classpath (cf. WebMvcConfigurationSupport #addDefaultMessageConverters). This is the price of features "magically" appearing by adding a library to the classpath.

    Fortunately you can override the default message converters: just add a WebMvcConfigurer and override its configureMessageConverters. You can even do it in your @SpringBootApplication class:

    @SpringBootApplication
    public class YourSpringApplication implements WebMvcConfigurer {
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            // add configuration here
        }
    
        ...
    }
    

    You can copy parts of the aforementioned addDefaultMessageConverters.

  3. Change the classloader's search order by adding to your context file (cf. Documentation on the ways to do it and change the delegate attribute of your loader:

    <Context>
        <Loader delegate="true" />
        ...
    </Context>
    
Piotr P. Karwasz
  • 12,857
  • 3
  • 20
  • 43
  • I've tried the option 1 you mentioned. However, the problem still persisted. Turned out that it's the `jar:file:/opt/apache-tomcat-8.5.20/lib/news-client-0.7.2.jar` that's causing the error. Once my sysadmin removed it, the problem is gone. Thank you again. I really appreciate it. – kohane15 Aug 30 '21 at 08:42