java - 应用程序启动方法中出现异常。 OpenJFX 13 与 Maven

标签 java maven javafx openjfx

我尝试使用 OpenJFX 模块和 Maven 启动一个新项目。我关注的是:https://openjfx.io/openjfx-docs/ (转到 JavaFX with Maven -> Modular with Maven),但在应用程序启动方法中出现异常。

错误:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalStateException: Location is not set.
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2459)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2435)
    at org.openjfx/org.openjfx.App.loadFXML(App.java:31)
    at org.openjfx/org.openjfx.App.start(App.java:20)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    ... 1 more
Exception running application org.openjfx.App

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 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.openjfx</groupId>
    <artifactId>Oblig1</artifactId>
    <version>1.0-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>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>13</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>13</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <release>11</release>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>0.0.1</version>
            <configuration>
                <mainClass>org.openjfx.App</mainClass>
            </configuration>
        </plugin>
        </plugins>
    </build>
</project>

应用程序.java

package org.openjfx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

/**
 * JavaFX App
 */
public class App extends Application {

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException {
        scene = new Scene(loadFXML("/org.openjfx/primary"));
        stage.setScene(scene);
        stage.show();
    }

    static void setRoot(String fxml) throws IOException {
        scene.setRoot(loadFXML(fxml));
    }

    private static Parent loadFXML(String fxml) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

    public static void main(String[] args) {
        launch();
    } 

}

primary.fxml:

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" 
xmlns:fx="http://javafx.com/fxml/1" fx:controller="kristoffer.PrimaryController">
   <children>
      <Label text="Primary View" />
      <Button fx:id="primaryButton" text="Switch to Secondary View" onAction="#switchToSecondary"/>
   </children>
   <padding>
      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
   </padding>
</VBox>

PrimaryController.java:

package org.openjfx;

import java.io.IOException;
import javafx.fxml.FXML;

public class PrimaryController {

}

辅助.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" spacing="20.0" 
xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" 
fx:controller="org.openjfx.SecondaryController">
    <children>
        <Label text="Secondary View" />
        <Button fx:id="secondaryButton" text="Switch to Primary View" 
onAction="#switchToPrimary" />
    </children>
    <padding>
        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
    </padding>
</VBox>

SecondaryController.java:

package org.openjfx;

import java.io.IOException; 
import javafx.fxml.FXML;

public class SecondaryController {

    @FXML
    private void switchToPrimary() throws IOException {
        App.setRoot("PrimaryController");
    }
}

目录:

    src
        main
            java
                org.openjfx
                    App.java
                    PrimaryController.java
                    SecondaryController.java
            resources 
                org.openjfx
                    primary.fxml
                    secondary.fxml

jar -tf Oblig1.jar:

我认为这可能与 FXML 加载器中的链接有关,我看到其他人也有类似的问题( like this one ),但我的目录有与他们不同的资源文件夹。感谢任何帮助,谢谢。

最佳答案

错误信息

java.lang.IllegalStateException: Location is not set.

表示您提供给 FXMLLoader 构造函数的 URL 为 null。如果找不到指定的资源,Class.getResource(...) 方法会默默返回 null

发生这种情况是因为您向 loadFXML 方法以及最终向 App.class.getResource(...) 提供的资源名称不正确。您提供给 Class.getResource(...) 的值是一个资源名称,其详细信息记录在 here 中。 .

资源名称由“类的包的完全限定名称组成,但转换为 所有句点 (.) 到斜杠 (/)”(见下文)。如果不至少查看 buid 文件夹和/或 jar 文件的结构,就不可能确切地知道出了什么问题,但它可能应该是

scene = new Scene(loadFXML("/org/openjfx/primary"));

由于您的 FXML 文件和执行此代码的类位于同一个包中,因此您也可以只使用

scene = new Scene(loadFXML("primary"));

该文档的一些相关部分:

Resources, names, and contexts

A resource is identified by a string consisting of a sequence of substrings, delimited by slashes (/), followed by a resource name. Each substring must be a valid Java identifier. The resource name is of the form shortName or shortName.extension. Both shortName and extension must be Java identifiers.

The name of a resource is independent of the Java implementation; in particular, the path separator is always a slash (/). However, the Java implementation controls the details of how the contents of the resource are mapped into a file, database, or other object containing the actual resource.

The interpretation of a resource name is relative to a class loader instance. Methods implemented by the ClassLoader class do this interpretation.

...

Resource Names

A common convention for the name of a resource used by a class is to use the fully qualified name of the package of the class, but convert all periods (.) to slashes (/), and add a resource name of the form name.extension. To support this, and to simplify handling the details of system classes (for which getClassLoader returns null), the class Class provides two convenience methods that call the appropriate methods in ClassLoader.

The resource name given to a Class method may have an initial starting "/" that identifies it as an "absolute" name. Resource names that do not start with a "/" are "relative".

因此 "/org.openjfx/primary" 不是有效的资源名称,因为 "org.openjfx" 不是有效的 Java 标识符。

在您的结构中,请注意 org.openjfx 不是一个文件夹,而是一个。 IDE 和构建工具会将其转换为文件系统上的文件夹层次结构,并最终转换为 jar 文件内的文件夹层次结构,其中包-子包结构将被文件夹和子文件夹替换。因此,在源代码结构中,您将有一个“java”文件夹,其中包含“org”子文件夹、“openjfx”子文件夹,其中包含 org.openjfx 包中类的 Java 源文件。在“resources”文件夹中,您还将有一个“org”子文件夹、一个“openjfx”子文件夹以及您创建的资源文件(包括 FMXL 文件)。

构建工具(Maven 或只是您的 IDE)可以识别特定的源文件夹;这些在您的情况下配置为包括“java”和“资源”。构建应用程序时,将在构建目标中重新创建源文件夹下结构的并集;在这里,这只会产生一个 org 文件夹和 openjfx 子文件夹。任何Java源文件都会编译为类文件;任何其他文件都只是复制。最后,整个内容被捆绑到一个 jar 文件中(本质上只是一个 zip 存档)。

如果您在文件系统上找到了 jar 文件(默认情况下 Maven 会将其放置在名为“target”的文件夹中,该文件夹位于“src”文件夹旁边),您可以使用以下命令检查其内容

jar -tf Oblig1-1.0-SNAPSHOT.jar

(我认为 Oblig1-1.0-SNAPSHOT.jar 是生成的 jar 文件的名称,但如果需要,显然可以调整它)。您应该看到我概述的文件夹结构,并且输出应包括

/org/openjfx/App.class
/org/openjfx/PrimaryController.class
/org/openjfx/SecondaryController.class
/org/openjfx/primary.fxml
/org/openjfx/secondary.fxml

(相同的结构应该存在于 target/classes 文件夹下,尽管文件夹命名和位置再次取决于您的 Maven 设置。)

顺便说一句,你真的不应该使用 org.openjfx 作为你自己的包名称和 Maven 组 ID;使用针对您自己或您的组织的特定内容。

关于java - 应用程序启动方法中出现异常。 OpenJFX 13 与 Maven,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60321474/

相关文章:

java - BufferedImage getRGB 与 Raster getSample

java - 用java解析Ofx文件

java - 如何使用 Eclipse 为 Java 项目创建 pom.xml

java - 如何在 FXML 应用程序中主类和 Controller 类之间进行通信

java - 在java中实现kruskals算法

java - JPanel 中的 JButton 方向

scala - 在 Java、Scala 或 Kotlin 的生态系统中,是否有一种可靠的方法来重新打包库依赖项以避免版本冲突?

java - 为什么我会收到带有方法名的 PropertyReferenceException?

java - 将 JavaFX 项目导出到 android

java - 无法在 JavaFX 中加载图像