1 year ago

#318250

test-img

Pavel Taruts

Running a spring-boot-gradle-plugin fat jar with named application modules at runtime?

I've got a simplest modular sample application made with Gradle and Spring Boot, and I'm having trouble to launch it with the modules being full-fledged named modules at runtime.

My questions are the following

  1. Can spring-boot-gradle-plugin build fat jars that you can run with full-fledged named modules at runtime?
  2. If it can, then how do you make it build the jar, and how do you run it?
  3. If it cannot, then what do I do to have modules at runtime in a Spring Boot app?

The Gradle version is 7.2

The source

(You can get it here as well: https://github.com/ptrts/modules-bootRun-bug)

settings.gradle

rootProject.name = 'app'

build.gradle

plugins {
    id 'org.springframework.boot' version '2.6.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'application'
}

group = 'we'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
}

application {
    mainModule = 'app'
    mainClass = 'app.Main'
}

src/main/java/module-info.java

module app {
    requires spring.boot;
    requires spring.boot.autoconfigure;
    requires java.annotation;
    exports app;
}

src/main/java/app/Main

package app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        
        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        // Output the module name
        System.out.println("Module name = " + Main.class.getModule().getName());
        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        SpringApplication.run(Main.class, args);
    }
}

As you can see the app outputs to stdout the module name of the Main class when launched

The resulting fat jar layout

org/springframework/boot/loader
    Spring Boot bootstrapping stuff
META-INF/MAINIFEST.MF
    ...
    Main-Class: org.springframework.boot.loader.JarLauncher
    Start-Class: app.Main
    ...
BOOT-INF
    lib
        dependency libs
    classes
        app/Main.class **the package is deep in the JAR**
module-info.class **the module descriptor is in the JAR root**

How I tried to launch the application

I tried three different ways of launching the app

  • ./gradlew bootRun -i (-i is for INFO logging level)
  • java -jar build/libs/app.jar
  • java --module-path build/libs/app.jar --module app/app.Main

Launching with ./gradlew bootRun -i

The app prints out Module name = null

In the gradle logs we can see the command line used to launch the JVM, which also tells us that everything is in the class path Here it is with some extra line brakes which I added for readability

C:\Program Files\Java\jdk-17.0.1\bin\java.exe
    ...
    -cp
        C:\data\projects\modules-bootRun-bug\build\classes\java\main;
        C:\data\projects\modules-bootRun-bug\build\resources\main;
        C:\Users\pavel\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-autoconfigure\2.6.4\36e75a2781fc604ac042945eed8be2fe049731df\spring-boot-autoconfigure-2.6.4.jar;
    ...
    app.Main

Launching with java -jar build/libs/app.jar

The app prints out Module name = null

Launching with java --module-path build/libs/app.jar --module app/app.Main

Error occurred during initialization of boot layer
java.lang.module.FindException: Error reading module: app.jar
Caused by: java.lang.module.InvalidModuleDescriptorException: Package app not found in module

This is of course expectable, since module-info.class is in the jar root and it's package is somewhere deeper in the jar

java

spring

spring-boot

gradle

java-platform-module-system

0 Answers

Your Answer

Accepted video resources