Search code examples
javaspring-boottomcatjbosswildfly

Getting java.lang.NoClassDefFoundError: org/apache/catalina/connector/Connector in wildFly 21.x


I am trying to run a spring boot project which runs perfectly on embedded tomcat but when deployed to wildfly 21.x throws java.lang.NoClassDefFoundError: org/apache/catalina/connector/Connector

Any help would be appreciated.

Below is my code snippet.

Main file:-

import org.apache.catalina.connector.Connector;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class CdPlaylistadapterApplication {

    @Value("${http.port}")
    private int httpPort;

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

    @Bean
    public ServletWebServerFactory servletContainer() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(createStandardConnector());
        return tomcat;
    }

    private Connector createStandardConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setPort(httpPort);
        return connector;
    }
}

My pom.xml snippet

        <cxf.version>3.4.0</cxf.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
             <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
             </exclusion>
         </exclusions>
        </dependency>
        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <scope>provided</scope>
          </dependency> 
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

Error:-

Caused by: java.lang.IllegalStateException: Failed to introspect Class [com.att.dtss.playlistadapter.CdPlaylistadapterApplication] from ClassLoader [ModuleClassLoader for Module "deployment.cd-playlistadapter-0.0.1-SNAPSHOT.war" from Service Module Loader]
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481)
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:455)
        at org.springframework.core.type.StandardAnnotationMetadata.getAnnotatedMethods(StandardAnnotationMetadata.java:151)
        ... 39 more
Caused by: java.lang.NoClassDefFoundError: org/apache/catalina/connector/Connector
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
        at java.lang.Class.getDeclaredMethods(Class.java:1975)
        at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
        ... 41 more
Caused by: java.lang.ClassNotFoundException: org.apache.catalina.connector.Connector from [Module "deployment.cd-playlistadapter-0.0.1-SNAPSHOT.war" from Service Module Loader]
        at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:255)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:410)
        at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)
        at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:116)
        ... 45 more

Solution

  • The class org.apache.catalina.connector.Connector is part of Tomcat. In order for your application to work correctly on external servlet containers, the embedded copy of Tomcat must not be on the classpath of the web application (i.e. in /WEB-INF/lib). You set it correctly by setting the scope of the spring-boot-starter-tomcat to provided.

    However now you have a problem, because the CdPlaylistadapterApplication has Connector in one of its method signatures and Spring Boot fails while creating an instance of the CdPlaylistadapterApplication class.

    To solve it you need to move Tomcat specific configuration to another class (even nested) and protect it with the @ConditionalOnClass annotation:

    @SpringBootApplication
    public class CdPlaylistadapterApplication extends SpringBootServletInitializer {
    
       @Configuration
       @ConditionalOnClass({Servlet.class, Tomcat.class, UpgradeProtocol.class})
       static class EmbeddedConfiguration {
    
          @Value("${http.port}")
          private int httpPort;
    
          @Bean
          public ServletWebServerFactory servletContainer() {
             TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
             tomcat.addAdditionalTomcatConnectors(createStandardConnector());
             return tomcat;
          }
    
          private Connector createStandardConnector() {
             Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
             connector.setPort(httpPort);
             return connector;
          }
       }
    
       public static void main(String[] args) {
          SpringApplication.run(CdPlaylistadapterApplication.class, args);
       }
    }