You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX+jlink构建后遇ProviderNotFoundException及栈追踪问题求助

问题:jlink构建JavaFX应用后Jar文件处理异常及栈追踪无代码行问题

背景信息

使用jlink将JavaFX应用与openjdk-18.0.2.1组件一同构建,构建脚本如下:

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'
}

构建镜像后应用可正常启动,但处理Jar文件时抛出异常:

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 com.prototype.catassistant@1.0/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);
    }
}

同时,构建后所有栈追踪均显示(Unknown Source)而非具体代码行,需一并解决。


解决方案

1. 解决ProviderNotFoundException异常

问题根源是jlink构建的运行时镜像默认未包含jdk.zipfs模块,该模块负责提供Zip/Jar文件系统的实现,而IDEA运行时使用完整JDK,因此不会出现此问题。

修复方式:

在jlink配置中添加jdk.zipfs模块,修改jlink任务的配置:

jlink {
    imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
    options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
    // 添加需要包含的模块
    modules += ['jdk.zipfs']
    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'
    }
}

或者,在你的模块描述文件module-info.java中添加对jdk.zipfs的依赖:

module com.prototype.catassistant {
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.web;
    // 添加这一行
    requires jdk.zipfs;
    // 其他requires声明...
}

2. 解决栈追踪显示(Unknown Source)问题

这是因为jlink的options中设置了--strip-debug参数,该参数会移除所有调试信息(包括行号)。

修复方式:

移除--strip-debug参数,或者替换为保留行号的调试信息选项:

jlink {
    imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
    // 移除--strip-debug,或者替换为--strip-native-debug-symbols(仅移除本地调试符号,保留Java行号)
    options = ['--compress', '2', '--no-header-files', '--no-man-pages']
    // 或者:options = ['--strip-native-debug-symbols', '--compress', '2', '--no-header-files', '--no-man-pages']
    jpackage {
        // 原jpackage配置...
    }
    launcher {
        name = 'CatAssistant'
    }
}

注意:移除--strip-debug会使镜像体积略有增大,但能保留完整的调试信息;使用--strip-native-debug-symbols则可以在保留Java代码行号的同时,移除不影响Java调试的本地符号,平衡体积和调试需求。


内容的提问来源于stack exchange,提问作者The Prototype

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 09:36:24