Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用GluonHQ客户端、本机映像和GraalVM解决已编译JavaFX项目中的fxml加载异常?_Java_Linux_Maven_Javafx_Graalvm - Fatal编程技术网

如何使用GluonHQ客户端、本机映像和GraalVM解决已编译JavaFX项目中的fxml加载异常?

如何使用GluonHQ客户端、本机映像和GraalVM解决已编译JavaFX项目中的fxml加载异常?,java,linux,maven,javafx,graalvm,Java,Linux,Maven,Javafx,Graalvm,这是问题的后续问题 我正在尝试将一个JavaFX项目编译成一个本机映像,这样它就可以在不需要安装Java的用户的情况下本机运行。JavaFX和反射的问题已经用GluonHQ客户端插件解决了,因此编译现在是成功的 我已经设法获得了一个简单的JavaFX项目(IntelliJ在创建JavaFX项目时生成的示例),以便使用Gluon客户端maven插件进行编译。但是,在命令行上运行本机映像时,会出现JavaFXML加载异常: Exception in thread "main" j

这是问题的后续问题

我正在尝试将一个JavaFX项目编译成一个本机映像,这样它就可以在不需要安装Java的用户的情况下本机运行。JavaFX和反射的问题已经用GluonHQ客户端插件解决了,因此编译现在是成功的

我已经设法获得了一个简单的JavaFX项目(IntelliJ在创建JavaFX项目时生成的示例),以便使用Gluon客户端maven插件进行编译。但是,在命令行上运行本机映像时,会出现JavaFXML加载异常:

Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
        at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
        at java.lang.Thread.run(Thread.java:834)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:518)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
Caused by: javafx.fxml.LoadException: 
sample.fxml:8

        at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2629)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2607)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2470)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3241)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3198)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3167)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3140)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3117)
        at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3110)
        at sample.Main.start(Main.java:13)
        at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
        at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
        at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
        at java.security.AccessController.doPrivileged(AccessController.java:101)
        at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
        at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
        at com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_VA_LIST:Ljava_lang_Runnable_2_0002erun_00028_00029V(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:277)
        ... 3 more
Caused by: com.sun.javafx.fxml.PropertyNotFoundException: Property "alignment" does not exist or is read-only.
        at javafx.fxml.FXMLLoader$Element.processValue(FXMLLoader.java:355)
        at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:332)
        at javafx.fxml.FXMLLoader$Element.processInstancePropertyAttributes(FXMLLoader.java:242)
        at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:775)
        at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2842)
        at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2561)
        ... 20 more
只有通过从以下位置更改sample.fxml,才能使本机映像正常工作:

<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<GridPane fx:controller="sample.Controller"
          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
</GridPane>

为此(删除路线、hgap和vgap属性):


然后重新编译。然后,编译后的二进制文件按预期运行

对于POM.xml中的Gluon插件,反射配置如下:

<plugin>
    <groupId>com.gluonhq</groupId>
    <artifactId>client-maven-plugin</artifactId>
    <version>0.1.30</version>
    <configuration>
        <mainClass>sample.NewMain</mainClass>
        <reflectionList>
            <list>sample.Main</list>
            <list>sample.NewMain</list>
            <list>sample.Controller</list>
            <list>javafx.fxml.FXMLLoader</list>
        </reflectionList>
    </configuration>
</plugin>

com.gloonhq
客户端maven插件
0.1.30
示例:NewMain
主样本
示例:NewMain
样本控制器
javafx.fxml.FXMLLoader

一旦编译了一个较大的项目JavaFX项目并配置了反射,这些FXML加载异常就相同了。异常总是说由以下原因引起的
:com.sun.javafx.fxml.PropertyNotFoundException:Property[X]不存在或是只读的。
两个项目在JVM上都运行良好,没有引发异常。My IDE无法检测代码错误。

您必须将更多通过FXML加载的类添加到反射列表中。例如,我还必须添加
javafx.geometry.HPos
javafx.geometry.VPos
。这是复杂的事实,这是不一致的。默认情况下,某些类已经包含,而其他类则没有。你需要在这里做一些实验。有时,如果已经定义了属性,我甚至必须指定类的父类。出于我自己的目的,我编写了一个小工具来简化这个过程:

我将进一步扩展@mipa的答案

您可能知道,FXML完全是关于反射的:我们有一个(f)xml文件和一个解析器(
FXMLLoader
),它查找类(
GridPane
)和属性名(
alignment
),在解析该文件时解析为方法名(and)

默认情况下,客户端为您提供一个
reflectionConfig.json
文件,其中包含您在FXML文件中可能使用的大多数JavaFX类和方法

如您所知,该文件是在运行
mvn-client:compile
(或
mvn-client:link
)时生成的,可以在
target/client/$arch-$os/gvm/reflectionconfig-$arch-$os.json
下找到(带有目标体系结构和操作系统名称)

现在,它包含大约290个类(Java和JavaFX),带有字段和方法

如果您检查它,您将看到,对于给定的
GridPane
类:

,
  {
    "name" : "javafx.scene.layout.GridPane",
    "methods":[
      {"name":"<init>","parameterTypes":[] },
      {"name":"setRowIndex","parameterTypes":["javafx.scene.Node","java.lang.Integer"] },
      {"name":"getRowIndex","parameterTypes":["javafx.scene.Node"] },
      {"name":"setColumnIndex","parameterTypes":["javafx.scene.Node","java.lang.Integer"] },
      {"name":"getColumnIndex","parameterTypes":["javafx.scene.Node"] },
      {"name":"setColumnSpan","parameterTypes":["javafx.scene.Node","java.lang.Integer"] },
      {"name":"getColumnSpan","parameterTypes":["javafx.scene.Node"] },
      {"name":"setRowSpan","parameterTypes":["javafx.scene.Node","java.lang.Integer"] },
      {"name":"getRowSpan","parameterTypes":["javafx.scene.Node"] },
      {"name":"getRowConstraints","parameterTypes":[] },
      {"name":"getColumnConstraints","parameterTypes":[] },
      {"name":"setHgrow","parameterTypes":["javafx.scene.Node","javafx.scene.layout.Priority"] },
      {"name":"getHgrow","parameterTypes":["javafx.scene.Node"] },
      {"name":"setVgrow","parameterTypes":["javafx.scene.Node","javafx.scene.layout.Priority"] },
      {"name":"getVgrow","parameterTypes":["javafx.scene.Node"] },
      {"name":"setMargin","parameterTypes":["javafx.scene.Node","javafx.geometry.Insets"] },
      {"name":"getMargin","parameterTypes":["javafx.scene.Node"] }
    ]
  }
,
但是,
alignment
方法不包括在内,这就是fxml失败的原因

有两种可能的解决方案:

1。配置文件

在本节之后,您可以将自己的文件添加到项目中,并添加缺少的方法:

  • src/main/resources/META-INF/subscriber/config/

  • 添加缺少的方法:

  • 再次运行
    mvn客户机:构建客户机:运行
    ,这次应该可以运行了
如果您再次检查
target/client/$arch-$os/gvm/reflectionconfig-$arch-$os.json
文件,您将看到json文件的内容已包含在最后,现在所有使用的
GridPane
方法都可用于反射

2。反映列表

或者,您可以简单地将整个类添加到reflectionList:

<reflectionList>
    <list>javafx.scene.layout.GridPane</list>
</reflectionList>
选项1的不同之处在于,现在您告诉GraalVM将该类的所有已声明和公共构造函数、字段和方法添加到其反射列表中,不管它们是否被使用,这可能会对编译时间和内存占用产生(小)影响。理想情况下,上述方案1优于方案2


只提供所需的类/方法将是最好的,但正如@mipa所指出的,这将需要一些能够发现哪些是这些类/方法的工具。同时,您必须运行一些迭代,以确定默认json文件是否包含FXML文件中使用的所有类/方法,并将缺少的类/方法添加到反射文件中(或者简单地将类名添加到反射列表中).

我只想在José的回答中添加一个更具体的案例,也许他也可以澄清这一点

另一个恼人的问题是,有时仅仅将要加载的类放入反射列表是不够的。例如,如果要加载ProgressBar并将该类放入反射列表中,仍会出现以下错误:
ProgressBar属性“progress”不存在或是只读的
。原因是属性“ProgressBar”是在ProgressBar的超类中定义的,因此您还必须将ProgressIndicator添加到列表中


为什么会这样?它能被某种方式阻止吗?

这很令人沮丧,但最后我把一切都搞定了,这里有一些建议。 如果您有fxml文件,并且该文件已加载到控制器中,只需在reflectionList中添加控制器即可。 resourceReflection.json不包含javafx类的所有属性,请检查是否在json中添加了所有属性,如果不只是在reflectionList中添加fx类,请添加 javafx.scene.layout.GridPane 将添加GridPane的所有属性。 检查fxml中的导入类,一些
<GridPane>
    <Label text="a label" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
</GridPane>
[
  {
    "name" : "javafx.scene.layout.GridPane",
    "methods":[
      {"name":"setAlignment","parameterTypes":["javafx.geometry.Pos"] },
      {"name":"getAlignment","parameterTypes":[] },
      {"name":"setHgap","parameterTypes":["double"] },
      {"name":"getHgap","parameterTypes":[] },
      {"name":"setVgap","parameterTypes":["double"] },
      {"name":"getVgap","parameterTypes":[] }
    ]
  }
]
<reflectionList>
    <list>javafx.scene.layout.GridPane</list>
</reflectionList>
  {
    "name" : "javafx.scene.layout.GridPane",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true
  }