JavaFx 奇怪的异常!应用程序启动方法中的异常

JavaFx Weird Exception !! Exception in Application start method

我希望你在这个困难时期过得很好,

我正在为我的其余 Web 服务开发一个 JavaFx 客户端,而 运行 我的应用程序有一个奇怪的异常指向我的 LoginPresenter class,我检查了所有源路径但是没有什么信号,所以我来这里寻求帮助,这是错误:

    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(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.NullPointerException: inputStream is null.
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2480)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2450)
    at fr.orleans.univ.projet/fr.orleans.univ.projet.view.LoginPresenter.getInstance(LoginPresenter.java:39)
    at fr.orleans.univ.projet/fr.orleans.univ.projet.PrimaryController.showLogin(PrimaryController.java:22)
    at fr.orleans.univ.projet/fr.orleans.univ.projet.App.start(App.java:30)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop(GtkApplication.java:277)
    ... 1 more
Exception running application fr.orleans.univ.projet.App

这是我的代码:

控制器PrimaryController.class

public class PrimaryController {

    private Stage stage;
    private Service service;

    public PrimaryController(Stage stage, Service service) {
        this.stage = stage;
        this.service = service;
    }

    public void showLogin(){
        LoginPresenter login = LoginPresenter.getInstance(this);
        Scene scene = new Scene(login.getRoot());
        stage.setScene(scene);
        stage.show();
    }

    public void tenteLogin(String username, String password) {
        service.login(username,password);
        if(service.isAuthenticated()){
            System.out.println("Connecté!");
        }
    }
}

这是我的LoginPresenter.class

public class LoginPresenter {

    private PrimaryController primaryController;

    public void setPrimaryController(PrimaryController primaryController){
        this.primaryController=primaryController;
    }

    @FXML
    private TextField username;
    @FXML
    private PasswordField password;
    @FXML
    private Parent root;

    public Parent getRoot(){
        return root;
    }

    public void login(ActionEvent actionEvent)  {
        primaryController.tenteLogin(username.getText(),password.getText());
    }

    public  static LoginPresenter getInstance(PrimaryController primaryController){
        FXMLLoader loader = new FXMLLoader();
        try {
            Parent root = loader.load(LoginPresenter.class.getResourceAsStream("login.fxml"));
        } catch (IOException e){
            e.printStackTrace();
        }
        LoginPresenter instance = loader.getController();
        instance.setPrimaryController(primaryController);

        return instance;
    }
}

这是我的App.class

public class App extends Application {

   // private static Scene scene;


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


    @Override
    public void start(Stage stage) {
        Service service = new ServiceProxy();
        PrimaryController primaryController = new PrimaryController(stage,service);
        primaryController.showLogin();
    }
}

最后这是我的 login.fxml

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

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

<BorderPane fx:id="root" prefHeight="200.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.orleans.univ.projet.view.LoginPresenter">
   <top>
      <Label text="Login" BorderPane.alignment="CENTER">
         <font>
            <Font size="24.0" />
         </font>
      </Label>
   </top>
   <center>
      <GridPane BorderPane.alignment="CENTER">
         <columnConstraints>
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="94.0" minWidth="10.0" prefWidth="72.0" />
            <ColumnConstraints hgrow="SOMETIMES" maxWidth="158.0" minWidth="10.0" prefWidth="128.0" />
         </columnConstraints>
         <rowConstraints>
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
         </rowConstraints>
         <children>
            <Label focusTraversable="false" text="Username" />
            <Label focusTraversable="false" text="Password" GridPane.rowIndex="1" />
            <TextField fx:id="username" GridPane.columnIndex="1" />
            <PasswordField fx:id="password" GridPane.columnIndex="1" GridPane.rowIndex="1" />
         </children>
      </GridPane>
   </center>
   <bottom>
      <Button defaultButton="true" mnemonicParsing="false" onAction="#login" text="Login" BorderPane.alignment="CENTER">
         <opaqueInsets>
            <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
         </opaqueInsets></Button>
   </bottom>
</BorderPane>

你的 LoginPresenter class 在包 fr.orleans.univ.projet.view.

中(根据堆栈跟踪)

使用 LoginPresenter.class.getResourceAsStream("login.fxml") 将在 LoginPresenter 所在的同一包中查找资源 login.fxml。根据您的评论,您将 login.fxml 放在源中文件夹 src/main/java/resources(我假设 "ressources" 是一个拼写错误),它(在大多数 IDE 或构建工具中使用标准配置)将把它放在构建的默认包中。

您可以解决此问题

  1. 通过提供 FXML 文件的绝对路径。因为你在默认包中有这个,这意味着使用

    LoginPresenter.class.getResourceAsStream("/login.fxml")
    

    (注意前导/

  2. 或者将 login.fxml 放在同一个包中,您可以将其放在源文件夹 src/main/java/resources/fr/orleans/univ/projet/view 中。

总的来说,我认为后一种解决方案更好。

您还需要确保在构建期间部署了 FXML 文件;如果您使用的是 Maven 或 Gradle 等构建工具,则默认情况下会发生这种情况;如果您使用的是 IDE 的原始版本,您可能需要对其进行配置以确保发生这种情况。

如果您需要进一步的故障排除,您应该检查 buid 文件夹(不是源文件夹)的布局。根据您的构建工具或 IDE,这可以是 buildbintargettarget/classes 等之一。查看构建文件夹并检查LoginPresenter.classlogin.fxml.

之间的关系

稍微有点跑题的地方;我强烈建议使用资源 URL 来加载 FXML,而不是流;即使用

LoginPresenter.class.getResource(...)

而不是

LoginPresenter.class.getResourceAsStream(...)

原因是stream版本的load方法没有设置FXMLLoaderlocation 属性(因为没有指定位置);因此,例如,location resolution 在 FXML 文件中将不起作用。