Issue
I am relatively new to JavaFX, FXML and SceneBuilder in general. I am working on a project for uni where I have to build an application which includes the functionality of displaying different lecture profiles. The different profiles are stored in a database and are all instances of a class called "Lecture". I built a first simple scene for the class with SceneBuilder and also created a controller class. The idea now is that whenever a lecture should be displayed the according object is loaded from the database and used to adjust attributes in the controller class which cause the Scene to change. I simulated this by instantiating a Lecture object in my start() method and passing it to a getter-like method which was supposed to change the text of a first label attribute displaying the name of the lecturer. Unfortunately this causes a NullPointerException. All research couldn't help which is why I am here now. I am grateful for any help!
Picture of the GUI:
Error message with stacktrace:
> Task :Main.main() FAILED
Juni 23, 2022 12:16:04 AM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @1796cf6c'
Unsupported JavaFX configuration: classes were loaded from 'unnamed module @1796cf6c'
Juni 23, 2022 12:16:04 AM javafx.fxml.FXMLLoader$ValueElement processValue
WARNING: Loading FXML document with JavaFX API of version 18 by JavaFX runtime of version 17.0.1
Exception in Application start method
Loading FXML document with JavaFX API of version 18 by JavaFX runtime of version 17.0.1
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot invoke "unihub.userapplicationsystem.LectureProfileController.loadLecture(unihub.serversystem.model.Lecture)" because "lectureProfileController" is null
at unihub.userapplicationsystem.GUI.start(GUI.java:25)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
Caused by: java.lang.NullPointerException: Cannot invoke "unihub.userapplicationsystem.LectureProfileController.loadLecture(unihub.serversystem.model.Lecture)" because "lectureProfileController" is null
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Execution failed for task ':Main.main()'.
> Process 'command '/Library/Java/JavaVirtualMachines/jdk-17.0.1.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
JavaFX application class:
package unihub.userapplicationsystem;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import unihub.serversystem.model.Lecture;
import java.net.URL;
public class GUI extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
URL lectureProfileStageUML = ClassLoader.getSystemResource("LectureProfileStage.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
Parent root = fxmlLoader.load(lectureProfileStageUML);
Lecture testLecture = new Lecture(1, "EIST", "Krusche");
LectureProfileController lectureProfileController = fxmlLoader.getController();
lectureProfileController.loadLecture(testLecture);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Main class:
public class Main {
public static void main(String[] args) {
GUI.main(args);
}
}
FXML controller class:
package unihub.userapplicationsystem;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import unihub.serversystem.model.Lecture;
public class LectureProfileController {
private Lecture lecture;
@FXML
private Label lecturerNameLabel;
public void loadLecture(Lecture lecture) {
lecturerNameLabel.setText("lecturer:\n" + lecture.getLecturer());
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?>
<ScrollPane prefHeight="500.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="unihub.userapplicationsystem.LectureProfileController">
<content>
<FlowPane prefHeight="500.0" prefWidth="400.0">
<children>
<StackPane prefHeight="100.0" prefWidth="400.0">
<children>
<ImageView fitHeight="100.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="false">
<image>
<Image url="@LectureBanner.jpg" />
</image>
</ImageView>
<Label text="lecture name here" translateX="-85.0" translateY="-20.0" StackPane.alignment="BOTTOM_CENTER">
<font>
<Font name="SansSerif Bold" size="21.0" />
</font>
</Label>
</children>
</StackPane>
<GridPane alignment="BOTTOM_RIGHT" hgap="10.0" nodeOrientation="LEFT_TO_RIGHT" prefHeight="150.0" prefWidth="400.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="188.0" minWidth="10.0" prefWidth="167.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="173.0" minWidth="10.0" prefWidth="173.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 text="lecturer: -lecturer here- " GridPane.halignment="LEFT" fx:id="lecturerNameLabel"/>
<Label text="lecture-ID: -lecture-ID here-" GridPane.halignment="LEFT" GridPane.rowIndex="1" />
<Label text="teaching language: -language here-" GridPane.halignment="LEFT" GridPane.rowIndex="2" />
<Label text="weekly hours: -hours here-" GridPane.columnIndex="1" GridPane.halignment="LEFT" GridPane.rowIndex="1" />
<Label text="number of credits: -credits here-" GridPane.columnIndex="1" GridPane.halignment="LEFT" />
<Button alignment="CENTER" mnemonicParsing="false" prefHeight="10.0" prefWidth="101.0" text="Enroll" GridPane.columnIndex="1" GridPane.rowIndex="2">
<font>
<Font name="SansSerif Regular" size="11.0" />
</font>
</Button>
</children>
<padding>
<Insets left="25.0" right="25.0" top="20.0" />
</padding>
</GridPane>
</children>
</FlowPane>
</content>
</ScrollPane>
Solution
The FXMLLoader.load(URL)
method is a static method. So your code compiles to
URL lectureProfileStageUML = ClassLoader.getSystemResource("LectureProfileStage.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
Parent root = FXMLLoader.load(lectureProfileStageUML);
It's obvious from this equivalent version of the code that the instance you defined, fxmlLoader
, has not been used to load an FXML file. Consequently it never initializes its controller, and
LectureProfileController lectureProfileController = fxmlLoader.getController();
returns null, resulting in a null pointer exception when you try to do
lectureProfileController.loadLecture(testLecture);
Instead, you should set the location of fxmlLoader
and call the no-argument, instance method fxmlLoader.load()
:
@Override
public void start(Stage primaryStage) throws Exception {
URL lectureProfileStageUML = ClassLoader.getSystemResource("LectureProfileStage.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(lectureProfileStageUML);
// or just:
// FXMLLoader fxmlLoader = new FXMLLoader(lectureProfileStageUML);
// Note no URL is passed here:
Parent root = fxmlLoader.load();
Lecture testLecture = new Lecture(1, "EIST", "Krusche");
LectureProfileController lectureProfileController = fxmlLoader.getController();
lectureProfileController.loadLecture(testLecture);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
As an aside, the construction of your URL is probably wrong. See How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?
And as a second aside, it never makes sense to call a static method from an instance variable. Most IDEs warn you (or at the very least can be configured to warn you) when you accidentally do this. I recommend configuring your IDE to provide a warning (and not ignoring the warning). It was a poor design decision to allow that as valid syntax (the language designers were copying what happens in C++).
Answered By - James_D
Answer Checked By - Katrina (JavaFixing Volunteer)