我在通过Gluon客户端插件运行GraalVM(基于JDK 11构建的最新GraalVM)生成的本地镜像时遇到了一个错误。
javafx.fxml.LoadException: onAction='#loginAction'解析错误,要么是事件处理程序不在Namespace中,要么是脚本中出现了错误。
编译步骤工作正常。
mvn clean client:build
我看到二进制文件在一个名为""的文件夹中。项目名称目标客户端x86_64-linuxbinaryname"
当我通过".binaryname "运行可执行文件时,产生了上述错误。binaryname"
其在第17行抱怨的FXML代码行是。
<Button fx:id="_loginButton" layoutX="516.0" layoutY="174.0" mnemonicParsing="false" onAction="#loginAction" prefHeight="28.0" prefWidth="94.0" text="Login" />
后台代码逻辑如下,并用@FXML标记。
@FXML
void loginAction(ActionEvent event) throws InterruptedException {
LoginService loginservice = new LoginService(_usernameTextField.getText(), _passwordTextField.getText());
根据JavaFX常见的错误列表,问题通常是由于onAction事件的名称与控制器中指定的名称不一样-------------------------------------------------。JavaFX初学者介绍 - 第27页 . 然而事实并非如此,我程序的命名是准确的。使用JavaFX maven插件(与GluonClient分开),使用
maven javafx:run
程序正常启动,并按预期工作。如果我需要发布更多信息,请告诉我。
这是我的pom.xml(我只替换了下面的包名)
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>com-demo-management-ui</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<client.plugin.version>0.1.26</client.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.3</version>
<configuration>
<mainClass>com.demo.Launcher</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>client-maven-plugin</artifactId>
<version>${client.plugin.version}</version>
<configuration>
<!-- Uncomment to run on iOS: -->
<!-- <target>ios</target> -->
<mainClass>com.demo.Launcher</mainClass>
<graalvmHome>/opt/graalvm-ce-java11-20.2.0-dev/</graalvmHome>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>gluon-releases</id>
<url>http://nexus.gluonhq.com/nexus/content/repositories/releases/</url>
</pluginRepository>
</pluginRepositories>
最后,这里是我设置控制器的代码(这是一个方法调用,我在需要时交换我的视图,因此控制器是作为创建视图的参数传递的)。
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/"+baseController.getFxmlFile()));
fxmlLoader.setController(baseController);
Parent parent = fxmlLoader.load();
Scene scene = new Scene(parent);
Stage stage = new Stage();
stage.setFullScreen(fullScreen);
stage.setMaximized(setMaximized);
stage.setScene(scene);
stage.show();
如果你看一下 HelloFXML
抽中 客户端样品库你会看到它使用的是典型的带有控制器的FXML文件。
<AnchorPane fx:id="pane" ... fx:controller="hellofx.HelloController">
在你的例子中,你没有在FXML文件中加入控制器,但你提供了这样的控制器。
fxmlLoader.setController(new hellofx.HelloController());
如你所知 FXMLLoader
使用反射来实例化在解析FXML文件时发现的控制器、控件和方法。
不管是哪种方式,当你点击按钮触发了 loginAction
方法,FXMLLoader进程与这个 召唤:
MethodHelper.invoke(method, controller, params);
使用反射来处理这种事件。
有了GraalVM。反思 是一个问题,你必须 "帮助 "它一下,通过提供将在某些时候被反思使用的classesmethodsfields。查找更多关于它的信息 此处.
客户端插件已经为你添加了JavaFX核心类和方法。你可以看到添加的内容 target/client/x86_64-darwin/gvm/reflectionconfig-x86_64-darwin.json
.
然而,你的自定义类必须被添加到该文件中。有两种方法可以做到这一点。
reflectionList
你将提供将被反射使用的自定义类。<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>client-maven-plugin</artifactId>
<version>${client.plugin.version}</version>
<configuration>
<reflectionList>
<list>hellofx.HelloController</list> <!-- your custom classes -->
</reflectionList>
<mainClass>${mainClassName}</mainClass>
</configuration>
</plugin>
这样做的效果是打开所有类的方法栏进行反射。你将在json文件中看到结果。
{
"name" : "hellofx.HelloController",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredFields" : true,
"allPublicFields" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
}
...
这应该足以解决你的问题。
reflectionconfig.json
)至 META-INF/substrate/config
而不是。[
{
"name":"hellofx.HelloController",
"methods":[{"name":"loginAction","parameterTypes":["javafx.event.ActionEvent"] }]
}
]
这样也能解决这个问题 当然,这可能需要在控制器中添加其他方法(如 initialize
).
这样就会只开放给反射这个方法,所以在内存占用上影响较小,并且遵循插件对JavaFX核心类的处理。