Skip to content

How to package JavaFX + Spring Boot application via jpackage correctly?

I’m having trouble packaging my project using jpackage by badass jlink plugin. Project contains Spring Boot, which works with JavaFX via FXVeawer. And with Spring Data application works with Database.

My build.gradle:

plugins {
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.10'
id 'org.beryx.jlink' version '2.24.1'
}

group = 'spring.geodemo'
version = '0.1.7'
sourceCompatibility = '17'


application {
mainModule = 'spring.geodemo'
mainClass = 'spring.geodemo.GeoDemoApplication'
}

repositories {
mavenCentral()
}

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

implementation 'javax.servlet:javax.servlet-api:4.0.1'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.17.2'


implementation group: 'org.springframework', name: 'spring-jdbc', version: '5.3.16'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-jdbc', 
version: '2.6.3'
implementation group: 'org.springframework', name: 'spring-core', version: '5.3.16'

implementation group: 'io.projectreactor.tools', name: 'blockhound', version: 
'1.0.6.RELEASE'


testImplementation 'org.springframework.boot:spring-boot-starter-test'

implementation 'net.rgielen:javafx-weaver-spring-boot-starter:1.3.0'
implementation 'org.postgresql:postgresql:42.3.1'
}

javafx {
version = '17.0.1'
modules = ['javafx.controls', 'javafx.fxml']
}

jlink {
imageZip = 
project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
    name = 'Geo'
}

jpackage {
    forceMerge('log4j-api')
}
}

Application is packaging, but due to error Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.IllegalAccessException-->module spring.geodemo does not open spring.geodemo to unnamed module @39cd0bac does not start.

I have no idea what caused that unnamed module @39cd0bac to appear.

Source code: on GitHub

Answer

Explaining the error

Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.IllegalAccessException
  module spring.geodemo does not open spring.geodemo to unnamed module @39cd0bac

See

The cglib is used by spring for byte code manipulation to support core spring tasks like dependency injection. This requires access permissions in a modular app. The cglib is running on the class path and trying to manipulate byte code in your module which is on the module path. Such access is restricted and not allowed under your current runtime configuration.

You can’t currently use jlink

Spring boot is not currently configured for modular builds using jlink, that won’t happen until spring boot 3 is released.

So you need to package your app as a non modular application which runs off the class path and the spring libraries should also be on the class path. The JavaFX libraries should be on the module path.

To create such a build, do not use the badass-jlink-plugin, as jlink assumes everything is a well defined and non automatic module. So that isn’t going to work for spring boot 2, which currently relies on automatic modules.

Use the runtime plugin and a non modular app instead

Your non modular app will be on the class path as will the spring dependent libs such as cglib, so there will be no access error.

As you are using gradle and jpackage, use the badass-runtime-plugin, which is able to use jpackage to package non modular applications.

Read, understand and apply its complex documentation.

Review the sample projects, especially the JavaFX app examples, that use it, which are listed on its github site

Completely documenting this process is beyond the scope of a StackOverflow answer.