Search code examples
javaspring-bootmavenintellij-ideaopenfeign

Why get java.lang.ClassNotFoundException when run as jar, but work well with IntelliJ IDEA


spring boot version : 2.4.1

spring cloud version : 2020.0.0

My code

@Configuration
public class BaseConfig {

    @Bean
    public Module sortJacksonModule() {
        return new SortJacksonModule();
    }
}

my pom.xml dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-openfeign-core</artifactId>
</dependency>

my pom.xml plugin

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

When run with IntelliJ IDEA, it work well.

But when run with jar(by mvn clean package), it show

Caused by: java.lang.NoClassDefFoundError: feign/codec/EncodeException
        at org.springframework.cloud.openfeign.support.SortJacksonModule.setupModule(SortJacksonModule.java:47) ~[spring-cloud-openfeign-core-3.0.0.jar!/:3.0.0]
        at com.fasterxml.jackson.databind.ObjectMapper.registerModule(ObjectMapper.java:819) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at com.fasterxml.jackson.databind.ObjectMapper.registerModules(ObjectMapper.java:1021) ~[jackson-databind-2.11.3.jar!/:2.11.3]
        at org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.configure(Jackson2ObjectMapperBuilder.java:712) ~[spring-web-5.3.2.jar!/:5.3.2]
        at org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.build(Jackson2ObjectMapperBuilder.java:680) ~[spring-web-5.3.2.jar!/:5.3.2]
        at org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration.jacksonObjectMapper(JacksonAutoConfiguration.java:101) ~[spring-boot-autoconfigure-2.4.1.jar!/:2.4.1]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_232]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_232]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_232]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_232]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.2.jar!/:5.3.2]
        ... 113 common frames omitted
Caused by: java.lang.ClassNotFoundException: feign.codec.EncodeException
        at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_232]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_232]
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) ~[demo-spring-core-11-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_232]
        ... 124 common frames omitted

After study the error log, I found that feign.codec.EncodeException is optional dependency in spring-cloud-openfeign-core, so ClassNotFoundException is right behavior(optional dependency not include in final jar).

So my question is: Why IntelliJ IDEA can run without any error? I try both IntelliJ IDEA run and mvn spring-boot:run, both work fine.

update: add example

After more study, I found out this only happen when the class not called.

        try {
            System.out.println("not important code");
        } catch (Exception e) {
            throw new EncodeException("not exist class");
        }

In this example, the try catch never throw an exception. And the EncodeException class is in an optional dependency. This code run well in IntelliJ IDEA, but fail when run as java -jar xxx.jar

========== update again with minimal demo

I create a minimal demo to reproduce this issue.

  • a standalone demo-module
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
            <version>10.10.1</version>
            <optional>true</optional>
        </dependency>
import feign.codec.EncodeException;

/**
 * Hello world!
 */
public class App {

    public void testOptional() {
        try {
            System.out.println("test");
        } catch (Exception e) {
            throw new EncodeException("never throw this");
        }
    }
}
  • demo spring project(create by spring initializr and add a dependency)
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>demo-module</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
@Component
public class MyMain implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        new App().testOptional();
    }
}

Solution

  • There is an option called Enable launch optimization in IntelliJ IDEA run config, uncheck it and everything work as expected.