Home > Net >  ClassNotFoundException while running spring boot multi release jar with java 11
ClassNotFoundException while running spring boot multi release jar with java 11

Time:10-07

While trying to run the spring boot application (with multi release jar) against different versions of java [java 8 (default) and java 11]

The project is running fine when ran with Java 8. However, upon running the application with java 11 getting ClassNotFoundException

The Project Structure:

enter image description here

pom.xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.5</version>
    <relativePath/> 
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
    <java.version>1.8</java.version>
    <start.class>com.example.demo.DemoApplication</start.class>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.inq</groupId>
        <artifactId>touchsocial-stress-testing</artifactId>
        <version>4.0-SNAPSHOT</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-toolchains-plugin</artifactId>
            <version>3.0.0</version>
            <configuration>
                <toolchains>
                    <jdk>
                        <version>zulu-11</version>
                    </jdk>
                </toolchains>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>toolchain</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <executions>
                <execution>
                    <id>default-compile</id>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                    <configuration>
                        <release>8</release>
                    </configuration>
                </execution>
                <execution>
                    <id>compile-java-11</id>
                    <phase>compile</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                    <configuration>
                        <release>11</release>
                        <compileSourceRoots>
                            <compileSourceRoot>${project.basedir}/src/main/java</compileSourceRoot>
                        </compileSourceRoots>
                        <multiReleaseOutput>true</multiReleaseOutput>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <archive>
                    <manifestEntries>
                        <Multi-Release>true</Multi-Release>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>${start.class}</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

after adding the <start-class> mentioned in enter image description here

for java 8 (java_home), everything seems fine

enter image description here

Note: For POC purpose the contents of both the DemoApplication.java is exactly the same

CodePudding user response:

Your Maven configuration is packaging your multi-release classes in the root of the jar. This means that they're loaded by the system class loader. The system class loader cannot see any of the dependencies packaged in BOOT-INF/lib so SpringApplication cannot be loaded.

You need to configure your app to package the multi-release classes beneath BOOT-INF/classes. One way to do that is to configure the compile task's output directory:

<execution>
    <id>compile-java-11</id>
    <phase>compile</phase>
    <goals>
        <goal>compile</goal>
    </goals>
    <configuration>
        <release>11</release>
        <compileSourceRoots>
            <compileSourceRoot>${project.basedir}/src/main/java</compileSourceRoot>
        </compileSourceRoots>
        <outputDirectory>${project.build.outputDirectory}/BOOT-INF/classes/</outputDirectory>
        <multiReleaseOutput>true</multiReleaseOutput>
    </configuration>
</execution>

If you do a clean build after making this change, the Java 11-specific class will now be packaged beneath BOOT-INF/classes/META-INF/versions/11/. As a result, it'll be loaded by Spring Boot's class loader and will be able to access classes from the jars packaged in BOOT-INF/lib.

This feels like something that Spring Boot's Maven plugin should take care of for you. I've opened https://github.com/spring-projects/spring-boot/issues/28234.

  • Related