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

升级Java8到11后,如何让GraalVM原生镜像使用外部JavaFX SDK?

问题描述

将Java 8项目升级到Java 11后,使用GraalVM构建原生镜像时遇到以下问题:

  • 编译链接成功,但运行时出现警告 JavaFx configuration: classes were loaded from unnamed module
  • IDE中通过VM参数 --module-path javafx-sdk-19/lib --add-modules javafx.fxml,javafx.controls,javafx.graphics 可解决该警告,但添加到GluonFX插件的runtimeArgs后,原生镜像仍无法正常运行
  • 同时抛出Resteasy相关初始化错误:Invalid bundle interface org.jboss.resteasy.resteasy_jaxrs.i18n.Messages (implementation not found)

相关Maven插件配置:

addjars-maven-plugin配置

<plugin>
    <groupId>com.googlecode.addjars-maven-plugin</groupId>
    <artifactId>addjars-maven-plugin</artifactId>
    <version>1.0.2</version>
    <executions>
        <execution>
            <goals>
                <goal>add-jars</goal>
            </goals>
            <configuration>
                <resources>
                    <resource>
                        <directory>${basedir}/libs</directory>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

GluonFX插件配置

<plugin>
    <groupId>com.gluonhq</groupId>
    <artifactId>gluonfx-maven-plugin</artifactId>
    <version>1.0.15</version>
    <configuration>
        <mainClass>com.proj.main.Main</mainClass>
        <reflectionList>com.proj.main.PaxUtils</reflectionList>
        <reflectionList>com.proj.JsonUtil</reflectionList>
        <nativeImageArgs>
            <arg>+EagerJVMCI</arg>
            <arg>-Dgraal.PrintConfiguration=info</arg>
        </nativeImageArgs>
    </configuration>
</plugin>

错误日志

WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @7e0babb1'

Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
    at java.lang.Thread.run(Thread.java:829)
    at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
    at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
Caused by: java.lang.ExceptionInInitializerError
    at org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:164)
    at org.jboss.resteasy.spi.ResteasyProviderFactory.createProviderInstance(ResteasyProviderFactory.java:2835)
    at org.jboss.resteasy.spi.ResteasyProviderFactory.addMessageBodyReader(ResteasyProviderFactory.java:1068)
    at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:1841)
    at org.jboss.resteasy.spi.ResteasyProviderFactory.registerProvider(ResteasyProviderFactory.java:1769)
    at org.jboss.resteasy.plugins.providers.RegisterBuiltin.registerProviders(RegisterBuiltin.java:148)
    at org.jboss.resteasy.plugins.providers.RegisterBuiltin.register(RegisterBuiltin.java:54)
    at org.jboss.resteasy.plugins.providers.RegisterBuiltin.register(RegisterBuiltin.java:40)
    at org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder.getProviderFactory(ResteasyClientBuilder.java:456)
    at org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder.buildOld(ResteasyClientBuilder.java:464)
    at org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder.build(ResteasyClientBuilder.java:496)
    at org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder.build(ResteasyClientBuilder.java:50)
    at javax.ws.rs.client.ClientBuilder.newClient(ClientBuilder.java:114)
    at com.xylo.client.xpos.service.XWebServiceClient.init(XWebServiceClient.java:41)
    at com.xylo.client.xpos.service.XWebServiceClient.<init>(XWebServiceClient.java:31)
    at com.xylo.client.xpos.POSSettings.fillSettings(POSSettings.java:181)
    at com.xylo.client.xpos.main.Main.start(Main.java:45)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.security.AccessController.executePrivileged(AccessController.java:169)
    at java.security.AccessController.doPrivileged(AccessController.java:91)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_VA_LIST_Runnable_run_16403f8d32adb631126daa893e5e80085c5d6325(JNIJavaCallWrappers.java:0)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(GtkApplication.java)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:316)
    ... 3 more
Caused by: java.lang.IllegalArgumentException: Invalid bundle interface org.jboss.resteasy.resteasy_jaxrs.i18n.Messages (implementation not found)
    at org.jboss.logging.Messages.doGetBundle(Messages.java:92)
    at org.jboss.logging.Messages.getBundle(Messages.java:59)
    at org.jboss.logging.Messages.getBundle(Messages.java:46)
    at org.jboss.resteasy.resteasy_jaxrs.i18n.Messages.<clinit>(Messages.java:31)
    ... 30 more
解决方案

1. 正确配置JavaFX模块到原生镜像构建参数

IDE中的VM参数是给JVM运行时用的,原生镜像构建时需要将这些参数传递给GraalVM的native-image工具,因此要添加到GluonFX插件的nativeImageArgs中,而不是runtimeArgs:

<plugin>
    <groupId>com.gluonhq</groupId>
    <artifactId>gluonfx-maven-plugin</artifactId>
    <version>1.0.15</version>
    <configuration>
        <mainClass>com.proj.main.Main</mainClass>
        <reflectionList>com.proj.main.PaxUtils</reflectionList>
        <reflectionList>com.proj.JsonUtil</reflectionList>
        <nativeImageArgs>
            <arg>+EagerJVMCI</arg>
            <arg>-Dgraal.PrintConfiguration=info</arg>
            <!-- 替换为你的JavaFX SDK实际路径 -->
            <arg>--module-path=${basedir}/javafx-sdk-19/lib</arg>
            <arg>--add-modules=javafx.fxml,javafx.controls,javafx.graphics</arg>
            <!-- 可选:添加模块导出,解决可能的内部API访问问题 -->
            <arg>--add-exports=javafx.graphics/com.sun.javafx.application=ALL-UNNAMED</arg>
        </nativeImageArgs>
    </configuration>
</plugin>

2. 替换addjars为Maven依赖管理(推荐)

addjars-maven-plugin会将JavaFX的模块Jar当作普通Jar处理,导致原生镜像无法识别模块结构。建议直接通过Maven依赖引入JavaFX,GluonFX插件会自动处理模块配置:

<dependencies>
    <!-- 根据你的操作系统选择classifier:linux/win/mac -->
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>19</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>19</version>
        <classifier>linux</classifier>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-graphics</artifactId>
        <version>19</version>
        <classifier>linux</classifier>
    </dependency>
</dependencies>

之后移除addjars-maven-plugin中对JavaFX Jar的引用,避免冲突。

3. 修复Resteasy的反射与资源缺失问题

错误日志显示Resteasy的国际化消息类无法找到实现,这是因为GraalVM原生镜像不会自动包含反射和资源文件,需要手动配置:

方式一:添加反射配置到GluonFX插件

<plugin>
    <groupId>com.gluonhq</groupId>
    <artifactId>gluonfx-maven-plugin</artifactId>
    <version>1.0.15</version>
    <configuration>
        <!-- 原有配置 -->
        <reflectionList>org.jboss.resteasy.resteasy_jaxrs.i18n.Messages</reflectionList>
        <reflectionList>org.jboss.resteasy.resteasy_jaxrs.i18n.Messages_$bundle</reflectionList>
        <!-- 包含Resteasy的资源文件 -->
        <resourceList>
            <resource>org/jboss/resteasy/resteasy_jaxrs/i18n/Messages.properties</resource>
        </resourceList>
    </configuration>
</plugin>

方式二:使用反射配置文件

在src/main/resources下创建reflection-config.json:

[
    {
        "name": "org.jboss.resteasy.resteasy_jaxrs.i18n.Messages",
        "allDeclaredConstructors": true,
        "allPublicConstructors": true,
        "allDeclaredMethods": true,
        "allPublicMethods": true
    },
    {
        "name": "org.jboss.resteasy.resteasy_jaxrs.i18n.Messages_$bundle",
        "allDeclaredConstructors": true,
        "allPublicConstructors": true,
        "allDeclaredMethods": true,
        "allPublicMethods": true
    }
]

然后在GluonFX插件中引用该文件:

<nativeImageArgs>
    <!-- 原有参数 -->
    <arg>-H:ReflectionConfigurationFiles=${basedir}/src/main/resources/reflection-config.json</arg>
</nativeImageArgs>

内容的提问来源于stack exchange,提问作者Yousef Hamarsheh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:10:58