IllegalArgumentException:在 JavaFX 中加载 FXML 文件时找不到无效的 URL 或资源

0 java javafx intellij-idea maven fxml

对于上下文,我在 Intellij 中有一个Maven 项目结构,还有/target/classes/

我收到错误的代码:

@Override
    public void start(Stage stage) throws IOException {

        Parent root;
        FXMLLoader fxmlLoader = new FXMLLoader();

        // Below line has the problem of loading image inside fxml file.
        root = fxmlLoader.load(getClass().getClassLoader().getResourceAsStream("AuthorizationPage.fxml"));

        // not used in code but below line returns inputstream object which is not null so the image loads fine
           when independently verified.
        // System.out.println(Objects.isNull(getClass().getClassLoader().getResourceAsStream("sign-up-logo.png")));

        //Below Line works fine and loads fxml file correctly with images.
        root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/AuthorizationPage.fxml")));

        Scene scene = new Scene(root);
        stage.setScene(scene);

        SceneManager sceneManager = SceneManager.getInstance(stage);
        sceneManager.addScene("/AuthorizationPage.fxml", "User Authorization");

        if (!SessionManager.hasUserSessionFromLocalFileExpired()) {

            sceneManager = SceneManager.getInstance(stage);
            sceneManager.addScene("/convertor.fxml", "Convert Pdf Documents");
            sceneManager.activateScene("Convert Pdf Documents", "Convert Pdf Documents", true, true);
        } else {

            sceneManager.activateScene("User Authorization", "User Authorization", false, false);
        }
    }
Run Code Online (Sandbox Code Playgroud)

异常的堆栈跟踪:

null/images/sign-up-logo.png
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:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:465)
    at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:364)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1082)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javafx.fxml.LoadException: 
unknown path:33

    at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2714)
    at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2692)
    at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2539)
    at com.javafxapp.javafxapplication/com.app.convertor.authorization.Main.start(Main.java:39)
    at javafx.graphics@19.0.2/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at javafx.graphics@19.0.2/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at javafx.graphics@19.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at javafx.graphics@19.0.2/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at javafx.graphics@19.0.2/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics@19.0.2/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics@19.0.2/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
    ... 1 more
Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found
    at javafx.graphics@19.0.2/javafx.scene.image.Image.validateUrl(Image.java:1138)
    at javafx.graphics@19.0.2/javafx.scene.image.Image.<init>(Image.java:695)
    at javafx.fxml@19.0.2/com.sun.javafx.fxml.builder.JavaFXImageBuilder.build(JavaFXImageBuilder.java:47)
    at javafx.fxml@19.0.2/com.sun.javafx.fxml.builder.JavaFXImageBuilder.build(JavaFXImageBuilder.java:37)
    at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:774)
    at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2961)
    at javafx.fxml@19.0.2/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2646)
    ... 11 more
Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found
    at javafx.graphics@19.0.2/javafx.scene.image.Image.validateUrl(Image.java:1123)
    ... 17 more
Exception running application com.app.convertor.authorization.Main

Process finished with exit code 1
Run Code Online (Sandbox Code Playgroud)

fxml 片段:

<HBox prefHeight="100.0" prefWidth="200.0">
                     <children>
                        <AnchorPane prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
                           <children>
                              <ImageView fitHeight="108.0" fitWidth="101.0" layoutX="270.0" pickOnBounds="true" preserveRatio="true">
                                 <image>
                                    <Image url="@images/sign-up-logo.png" />
                                 </image>
                              </ImageView>
                           </children>
                        </AnchorPane>
                     </children>
                  </HBox>
Run Code Online (Sandbox Code Playgroud)

Maven pom 文件片段:

<resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>src/main/resources/com/app/convertor/config</directory>
            </resource>
            <resource>
                <directory>src/main/resources/com/app/convertor/fxml/images</directory>
            </resource>
            <resource>
                <directory>src/main/resources/com/app/convertor/fxml</directory>
            </resource>
</resources>
Run Code Online (Sandbox Code Playgroud)

为什么使用方法加载图像失败,getResourcesAsStream()但使用getResources()方法却可以正常工作?我检查了 if getResourcesAsStream()returns null,但它从资源文件夹中正确识别了 fxml 文件。我出了什么问题,我应该怎么做才能正确加载 fxml 文件?有人问过类似的问题,但没有一个对我有帮助。

Jam*_*s_D 5

为什么使用方法加载图像失败,getResourcesAsStream()但使用getResources()方法却可以正常工作?

在 FXML 文件中使用 URL位置解析:

<Image url="@images/sign-up-logo.png" />
Run Code Online (Sandbox Code Playgroud)

将尝试解析相对于正在解析的 FXML 文件位置的 URL。

仅当您使用指定位置的 FXML 加载方法之一时,才会设置该位置,例如

URL url = ... ;
FMXLLoader.load(url);
Run Code Online (Sandbox Code Playgroud)

或者

URL url = ... ;
FXMLLoader loader = new FXMLLoader(url);
loader.load();
Run Code Online (Sandbox Code Playgroud)

ETC。

如果加载指定 的InputStreamFXML (例如由 返回getClass().getResourceAsStream()),则将FXMLLoader不会指定location,并且无法解析其中指定的任何 URL。(理论上,流甚至可以动态生成,甚至可能根本不对应于位置。)

您可以从堆栈跟踪的一部分看到这一点:

null/images/sign-up-logo.png
Run Code Online (Sandbox Code Playgroud)

这里FXMLLoader附加/images/sign-up-logo.png到 FXML 的位置;由于该位置null(因为您正在通过指定流加载),因此该位置没有任何意义,并且无法加载图像。

解决方案只是指定 URL(例如使用getClass().getResource()),而不是指定流(例如使用getClass().getResourceAsStream())。

如果由于某种原因您确实需要传递流,并且您在 FXML 文件中使用位置解析,则以下内容应该有效:

String loc = ... ;
URL location = getClass().getResource(loc);
InputStream stream = getClass().getResourceAsStream(loc);
FXMLLoader loader = new FXMLLoader();
loader.setLocation(location);
Parent root = loader.load(stream);
Run Code Online (Sandbox Code Playgroud)

然而,这是一个奇怪的用法。上面的代码相当于

String loc = ... ;
URL location = getClass().getResource(loc);
FXMLLoader loader = new FXMLLoader(loc);
Parent root = loader.load();
Run Code Online (Sandbox Code Playgroud)

我认为这是更可取的。