Issue
I am building my JavaFX application together with the required JVM (openjdk-18.0.2.1) components using in jlink. The build script is almost no different from being created using IDEA by default.
import org.gradle.internal.os.OperatingSystem
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.13'
id 'org.beryx.jlink' version '2.25.0'
}
group 'com.prototype'
version '1.0'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.9.0'
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(18))
}
//withSourcesJar()
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'com.prototype.catassistant'
mainClass = 'com.prototype.catassistant.CatAssistantApplication'
}
javafx {
version = '18.0.1'
modules = ['javafx.controls', 'javafx.fxml', 'javafx.web']
}
dependencies {
// https://mvnrepository.com/artifact/org.jetbrains/annotations
implementation 'org.jetbrains:annotations:23.0.0'
implementation('org.controlsfx:controlsfx:11.1.1')
// https://www.benf.org/other/cfr/api/index.html
// https://mvnrepository.com/artifact/org.benf/cfr
implementation 'org.benf:cfr:0.152'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
implementation 'com.google.code.gson:gson:2.9.1'
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
jpackage {
def currentOs = OperatingSystem.current()
def imgType = currentOs.windows ? 'ico' : currentOs.macOsX ? 'icns' : 'png'
icon = "src/main/resources/java.$imgType"
if (currentOs.windows) {
installerOptions += ['--win-per-user-install', '--win-dir-chooser', '--win-menu', '--win-shortcut', '--vendor', 'Prototype']
imageOptions += ['--win-console',/* '--icon', 'src/main/resources/icon.ico'*/]
}
}
launcher {
name = 'CatAssistant'
}
}
jlinkZip {
group = 'distribution'
}
After building the image, I successfully run it and it works, but when it comes to working with jar files, I get an incomprehensible error: java.nio.file.ProviderNotFoundException: Provider not found Everything works fine from IDEA. I am also confused by the fact that after the build, "(Unknown Source)" is written in the entire stacktrace instead of lines of code, if there is such a possibility, I would like to fix it.
Caused by: java.nio.file.ProviderNotFoundException: Provider not found
at java.base/java.nio.file.FileSystems.newFileSystem(Unknown Source)
at java.base/java.nio.file.FileSystems.newFileSystem(Unknown Source)
at [email protected]/com.prototype.catassistant.helper.FileHelper.readJarFile(Unknown Source)
FileHelper#readJarFile
// https://stackoverflow.com/a/37413531/10663941
public static void readJarFile(JarFile jar) {
try (FileSystem system = FileSystems.newFileSystem(jar.getPath())) { // <- exception
for (Path directory : system.getRootDirectories()) {
try (Stream<Path> stream = Files.walk(directory)) {
stream.filter(Predicate.not(Files::isDirectory))
.forEach(path -> jar.addEntry(path, read(system.getPath(path.toString()))));
}
}
} catch (IOException ex) {
AlertUtil.showExceptionDialog(ex);
throw new RuntimeException(ex);
}
}
I need help in solving this problem
Solution
ProviderNotFoundException
Most likely the java.nio.file.ProviderNotFoundException
error is caused by the jdk.zipfs
module not being included in the run-time image created by jlink
/ jpackage
1. That module is a "provider module" for the java.nio.file.FileSystemProvider
SPI. As such, I suspect none of the other modules that are part of your application directly or indirectly require the jdk.zipfs
module. Typically, modules do not requires
provider modules, as that defeats the purpose of the uses
/ provides
mechanism of the Java Platform Module System (see the links in the second solution below for an explanation).
There are three ways you can fix this:
Use
--bind-services
when invokingjlink
. This will causejlink
to look at all the required modules to see if any of themuses
an SPI. If they do, then it will look for all available modules whichprovides
implementations of the SPI and include them. Unfortunately, this will cause a lot of other modules to be included in your custom run-time image that you don't necessarily need.Modify your module-info descriptor to add a
requires jdk.zipfs
directive. However, as noted in the documentation, having an "application module" require a "provider module" is not recommended.Include an
--add-modules jdk.zipfs
argument when invokingjlink
. This will forcejlink
to include thejdk.zipfs
module without the unfortunate side-effects of the previous two solutions. Personally, I recommend using this solution in your case.
Unkown Source
The "Unknown Source" bits in the stack trace are caused by the --strip-debug
argument which, unsurprisingly, removes debugging information from the byte-code. That includes the source file names and line numbers. Having --strip-debug
reduces the size of the compiled code, which is good for the deployment version of your application.
1. You've confirmed this.
Answered By - Slaw
Answer Checked By - Marie Seifert (JavaFixing Admin)