Skip to content

javafx.fxml.LoadException when trying to display a list of objects in a TableView JavaFX

I am trying to display a list of objects in a JavaFX table but I keep running into a JavaFX exception when looping through the objects to add to the table, does anybody know what might be causing this, I’ve tried several different implementations of ObservableLists but they all see to produce the same result, my conclusion is that there could be an error with the class or the .fxml file. Thanks in advance.

JavaFX:

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

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

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="HomePageController">
   <left>
      <AnchorPane prefHeight="400.0" prefWidth="200.0" style="-fx-background-color: #c7a4ff;" BorderPane.alignment="CENTER">
         <children>
            <Label fx:id="userLabel" alignment="TOP_CENTER" contentDisplay="CENTER" text="Hello &lt;User&gt;" textAlignment="CENTER" textFill="WHITE">
               <font>
                  <Font name="Segoe UI Semilight" size="24.0" />
               </font>
               <padding>
                  <Insets bottom="10.0" left="25.0" right="25.0" top="10.0" />
               </padding>
            </Label>
               <padding>
                  <Insets bottom="10.0" left="25.0" right="25.0" top="10.0" />
               </padding>
            </Label>
            <Button layoutY="60.0" mnemonicParsing="false" onAction="#MenuSwitch" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #aa80ff;" text="Home" textFill="WHITE">
               <font>
                  <Font size="14.0" />
               </font>
            </Button>
            <Button layoutY="120.0" mnemonicParsing="false" onAction="#MenuSwitch" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #aa80ff;" text="Diet" textFill="WHITE">
               <font>
                  <Font size="14.0" />
               </font>
            </Button>
            <Button layoutY="180.0" mnemonicParsing="false" onAction="#MenuSwitch" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #aa80ff;" text="Workout" textFill="WHITE">
               <font>
                  <Font size="14.0" />
               </font>
            </Button>
            <Button layoutY="240.0" mnemonicParsing="false" onAction="#MenuSwitch" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #aa80ff;" text="Groups" textFill="WHITE">
               <font>
                  <Font size="14.0" />
               </font>
            </Button>
            <Button layoutY="300.0" mnemonicParsing="false" onAction="#MenuSwitch" prefHeight="50.0" prefWidth="200.0" style="-fx-background-color: #aa80ff;" text="User Information" textFill="WHITE">
               <font>
                  <Font size="14.0" />
               </font>
            </Button>
         </children>
      </AnchorPane>
   </left>
   <right>
      <AnchorPane prefHeight="400.0" prefWidth="394.0" BorderPane.alignment="CENTER">
         <children>
            <Label alignment="TOP_CENTER" contentDisplay="CENTER" layoutX="148.0" text="Home" textAlignment="CENTER" textFill="#aa80ff">
               <font>
                  <Font name="Segoe UI Semilight" size="24.0" />
               </font>
               <padding>
                  <Insets bottom="10.0" left="10.0" right="25.0" top="10.0" />
               </padding>
            </Label>
            <Label alignment="TOP_CENTER" contentDisplay="CENTER" layoutX="14.0" layoutY="55.0" text="My Goals" textAlignment="CENTER" textFill="#aa80ff">
               <font>
                  <Font name="Segoe UI Semilight" size="18.0" />
               </font>
               <padding>
                  <Insets bottom="10.0" left="10.0" right="25.0" top="10.0" />
               </padding>
            </Label>
            <TableView fx:id="tbData" layoutX="14.0" layoutY="102.0" prefHeight="200.0" prefWidth="360.0" style="-fx-background-color: #ffffff;">
              <columns>
                 <TableColumn fx:id="goalName" prefWidth="160.0" text="Name" />
                 <TableColumn fx:id="goalDate" prefWidth="50.0" text="Date" />
                 <TableColumn fx:id="goalStatus" prefWidth="75.0" text="Status" />
                 <TableColumn fx:id="goalGroups" prefWidth="10.0" text="Groups"/>
              </columns>
            </TableView>
         </children>
      </AnchorPane>
   </right>
   <bottom>
      <AnchorPane prefHeight="50.0" prefWidth="600.0" style="-fx-background-color: #c7a4ff;" BorderPane.alignment="CENTER">
         <children>
            <ImageView fitHeight="30.0" fitWidth="30.0" layoutX="380.0" layoutY="10.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@img/add_box.png" />
               </image>
            </ImageView>
            <Button graphicTextGap="0.0" layoutX="380.0" layoutY="10.0" mnemonicParsing="false" onAction="#openSelectGoalTypePage" opacity="0.0" prefHeight="30.0" prefWidth="30.0" />
            <ImageView fitHeight="30.0" fitWidth="30.0" layoutX="300.0" layoutY="10.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@img/mode_edit.png" />
               </image>
            </ImageView>
            <Button graphicTextGap="0.0" layoutX="300.0" layoutY="10.0" mnemonicParsing="false" onAction="#openEditGoalPage" opacity="0.0" prefHeight="30.0" prefWidth="30.0" />
            <ImageView fitHeight="30.0" fitWidth="30.0" layoutX="460.0" layoutY="10.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@img/delete.png" />
               </image>
            </ImageView>
            <Button graphicTextGap="0.0" layoutX="460.0" layoutY="10.0" mnemonicParsing="false" onAction="#removeTableItem" opacity="0.0" prefHeight="30.0" prefWidth="30.0" />
         </children>
      </AnchorPane>
   </bottom>
</BorderPane>

The Controller:

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class HomePageController extends BaseController implements Initializable {

    @FXML
    private TableView<Goal> tbData = new TableView<>();

    @FXML
    public TableColumn<Goal, String> goalName;

    @FXML
    public TableColumn<Goal, String> goalDate;

    @FXML
    public TableColumn<Goal, String> goalStatus;

    @FXML
    public TableColumn<Goal, String> goalGroups;

    /*@FXML
    private Label userLabel;*/

    //allow user to select a table item/row and delete it using the delete button
    public void removeTableItem(){

    }

    public void openSelectGoalTypePage(javafx.event.ActionEvent actionEvent) throws IOException {
        root = FXMLLoader.load(getClass().getResource("SelectGoalType.fxml"));
        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public void openAddGoalPage(javafx.event.ActionEvent actionEvent) throws IOException {
        //if user selects weight goal then open AddWeightGoal page
        //else if user selects workout goal then open AddWorkoutGoal page
        root = FXMLLoader.load(getClass().getResource("AddWeightGoal.fxml"));
        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public void openEditGoalPage(javafx.event.ActionEvent actionEvent) throws IOException {
        root = FXMLLoader.load(getClass().getResource("EditGoal.fxml"));
        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {



        tbData = new TableView<>();
        TableColumn<Goal, String> goalName = new TableColumn<>("GoalName");
        goalName.setCellValueFactory(new PropertyValueFactory<>("goalName"));
        TableColumn<Goal, String> goalDate = new TableColumn<>("GoalDate");
        goalDate.setCellValueFactory(new PropertyValueFactory<>("goalDate"));
        TableColumn<Goal, String> goalStatus = new TableColumn<>("GoalStatus");
        goalDate.setCellValueFactory(new PropertyValueFactory<>("goalStatus"));
        TableColumn<Goal, String> goalGroups = new TableColumn<>("GoalGroups");
        goalGroups.setCellValueFactory(new PropertyValueFactory<>("goalGroups"));
        tbData.getColumns().add(goalName);
        tbData.getColumns().add(goalDate);
        tbData.getColumns().add(goalStatus);
        tbData.getColumns().add(goalGroups);

        tbData.setItems(getGoals());

    }


    private ObservableList<Goal> getGoals(){
        ObservableList<Goal> goals = FXCollections.observableArrayList();
        for(int i = 0; i < user.getGoals().size(); i++){
            goals.add(user.getGoals().get(i));
        }
        return goals;
    }
}

Goal Class:

import java.io.Serial;
import java.io.Serializable;

public class Goal implements Serializable {

    @Serial
    private static final long serialVersionUID = 1L;

    public String getGoalName() {
        return goalName;
    }

    public void setGoalName(String goalName) {
        this.goalName = goalName;
    }



    public String getGoalDate() {
        return goalDate;
    }

    public void setGoalDate(String goalDate) {
        this.goalDate = goalDate;
    }

    public String getGoalStatus() {
        return goalStatus;
    }

    public void setGoalStatus(String goalStatus) {
        this.goalStatus = goalStatus;
    }

    public String getGoalGroups() {
        return goalGroups;
    }

    public void setGoalGroups(String goalGroups) {
        this.goalGroups = goalGroups;
    }

    public Goal(String goalName, String goalDate, String goalStatus, String goalGroups) {
        this.goalName = goalName;
        this.goalDate = goalDate;
        this.goalStatus = goalStatus;
        this.goalGroups = goalGroups;
    }

    String goalName;
    String goalDate;
    String goalStatus;
    String goalGroups;
} 

Edit:

I’ve done some more debugging and it seems when I surround it with a try-catch block it’s pointing to my user object from the base controller being null, even though I believe I pass it to the controller here’s the base controller which holds the user object, and the call I use to pass the user object (confirmed the user is fine before the passing as a parameter). The only stack trace I seem to get is the loader one and this from a try catch:java.lang.NullPointerException: Cannot invoke "User.getGoals()" because "this.user" is null :

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.stage.Stage;

import java.io.IOException;

public class BaseController {

    User user;

    Parent root;
    Stage stage;
    Scene scene;
    @FXML
    Label userLabel;

    //default constructor
    public BaseController(){

    }

    void setUser(User user){
        this.user = user;
        userLabel.setText(user.getUsername());
    }

    //connect to current user once logged in
    /*
    public BaseController(User user){
        displayUsername(User);
    }*/

    //display current logged in user's first name
    /*
    private void displayUsername(User user){
        userLabel.setText(user.firstName);
    }*/

    /**
     * Menu Functions just in case
     */
//    public void openHomePage(javafx.event.ActionEvent actionEvent) throws IOException {
//        root = FXMLLoader.load(getClass().getResource("HomePage.fxml"));
//        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
//        scene = new Scene(root);
//        stage.setScene(scene);
//        stage.show();
//    }
//
//    public void openDietPage(javafx.event.ActionEvent actionEvent) throws IOException {
//        root = FXMLLoader.load(getClass().getResource("DietPage.fxml"));
//        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
//        scene = new Scene(root);
//        stage.setScene(scene);
//        stage.show();
//    }
//
//    public void openWorkoutPage(javafx.event.ActionEvent actionEvent) throws IOException {
//        root = FXMLLoader.load(getClass().getResource("WorkoutPage.fxml"));
//        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
//        scene = new Scene(root);
//        stage.setScene(scene);
//        stage.show();
//    }
//
//    public void openGroupsPage(javafx.event.ActionEvent actionEvent) throws IOException {
//        root = FXMLLoader.load(getClass().getResource("GroupsPage.fxml"));
//        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
//        scene = new Scene(root);
//        stage.setScene(scene);
//        stage.show();
//    }
//
//    public void openUserPage(javafx.event.ActionEvent actionEvent) throws IOException {
//        root = FXMLLoader.load(getClass().getResource("UserPage.fxml"));
//        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
//        scene = new Scene(root);
//        stage.setScene(scene);
//        stage.show();
//    }

    public void MenuSwitch(javafx.event.ActionEvent actionEvent) throws IOException{
        String text = ((Button)actionEvent.getSource()).getText();
        String filename="";
        switch(text){
            case "Home":
                filename="HomePage.fxml";break;
            case "Diet":
                filename="DietPage.fxml";break;
            case "Workout":
                filename="WorkoutPage.fxml";break;
            case "Groups":
                filename="GroupsPage.fxml";break;
            case "User Information":
                filename="UserPage.fxml";break;
            case "Edit group":
                filename="EditGroupPage.fxml"; break;
            case "Create group":
                filename="CreateGroupPage.fxml";break;
            case "Add Diet Item":
                filename="AddDietItemPage.fxml"; break;
            case "EditWorkoutPage":
                filename="EditWorkoutPage.fxml";break;
            case "AddWorkoutPage":
                filename="AddWorkoutPage.fxml";break;
            case "EditUserPage":
                filename="EditUserPage.fxml";break;
        }
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(filename));

        Parent root = (Parent) fxmlLoader.load();

        BaseController baseController = fxmlLoader.getController();

        System.out.println(user);

        baseController.setUser(user);

        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();

    }
}

From the previous controller that passes the user object:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("HomePage.fxml"));

                    Parent root = (Parent) fxmlLoader.load();

                    HomePageController controller = fxmlLoader.getController();

                    controller.setUser(newUser);

                    stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
                    scene = new Scene(root);
                    stage.setScene(scene);
                    stage.show();

Thanks!

Edit II: Full stack trace:

java.lang.NullPointerException: Cannot invoke "User.getGoals()" because "this.user" is null
java.lang.NullPointerException: Cannot invoke "User.getGoals()" because "this.user" is null
    at HomePageController.initialize(HomePageController.java:75)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2655)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2517)
    at UserLoginController.login(UserLoginController.java:108)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:273)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1857)
    at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1729)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8886)
    at javafx.controls/javafx.scene.control.Button.fire(Button.java:203)
    at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:208)
    at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
    at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3856)
    at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1851)
    at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2584)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:409)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:299)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:447)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:412)
    at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:446)
    at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
    at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277)
    at java.base/java.lang.Thread.run(Thread.java:832)
java.sql.SQLException: The prepared statement has been finalized

Answer

The controller’s initialize() method is called during the execution of FXMLLoader.load(), so initialize(), and consequently getGoals() are called before you call setUser(...). So user is null at the time you try to call user.getGoals().

To fix this within the structure you have set up, you need to populate the table list when setUser(...) is called. You could do this with an overridden setUser(...) method in your subclass.

Also note it’s always a mistake to initialize @FXML-annotated fields (because they are initialized by the FXMLLoader to the elements defined in the FXML file). So your controller should look something like this:

public class HomePageController extends BaseController implements Initializable {

    @FXML
    private TableView<Goal> tbData ;

    @FXML
    public TableColumn<Goal, String> goalName;

    @FXML
    public TableColumn<Goal, String> goalDate;

    @FXML
    public TableColumn<Goal, String> goalStatus;

    @FXML
    public TableColumn<Goal, String> goalGroups;

    /*@FXML
    private Label userLabel;*/

    //allow user to select a table item/row and delete it using the delete button
    public void removeTableItem(){

    }

    public void openSelectGoalTypePage(javafx.event.ActionEvent actionEvent) throws IOException {
        root = FXMLLoader.load(getClass().getResource("SelectGoalType.fxml"));
        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public void openAddGoalPage(javafx.event.ActionEvent actionEvent) throws IOException {
        //if user selects weight goal then open AddWeightGoal page
        //else if user selects workout goal then open AddWorkoutGoal page
        root = FXMLLoader.load(getClass().getResource("AddWeightGoal.fxml"));
        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public void openEditGoalPage(javafx.event.ActionEvent actionEvent) throws IOException {
        root = FXMLLoader.load(getClass().getResource("EditGoal.fxml"));
        stage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {



        goalName.setCellValueFactory(new PropertyValueFactory<>("goalName"));
        goalDate.setCellValueFactory(new PropertyValueFactory<>("goalDate"));
        goalDate.setCellValueFactory(new PropertyValueFactory<>("goalStatus"));
        goalGroups.setCellValueFactory(new PropertyValueFactory<>("goalGroups"));


    }

    @Override
    void setUser(User user){
        super.setUser(user);
        tbData.setItems(getGoals());
    }

    private ObservableList<Goal> getGoals(){
        return FXCollections.observableList(user.getGoals());
    }
}

A more standard approach would be to use a MVC-type design, where the user is represented by an ObjectProperty<User> and you observe it for changes. E.g.

public class BaseController {

    private final ObjectProperty<User> user;

    // ...

    //default constructor
    public BaseController(){
        user = new SimpleObjectProperty();
        user.addListener((obs, oldUser, newUser) ->
            userLabel.setText(newUser == null ? "" : newUser.getUsername()));
    }

    public ObjectProperty<User> userProperty() {
        return user ;
    }

    public final User getUser() {
        return userProperty().get();
    }

    public final void setUser(User user) {
        userProperty().set(user);
    }

    // ...
}

and

public class HomePageController extends BaseController implements Initializable {

    @FXML
    private TableView<Goal> tbData ;

    @FXML
    public TableColumn<Goal, String> goalName;

    @FXML
    public TableColumn<Goal, String> goalDate;

    @FXML
    public TableColumn<Goal, String> goalStatus;

    @FXML
    public TableColumn<Goal, String> goalGroups;

    public HomePageController() {
        userProperty().addListener((obs, oldUser, newUser) -> {
            if (newUser == null) {
                tbData.setItems(FXCollections.observableArrayList());
            } else {
                tbData.setItems(getGoals());
            }
        });
    }

    // ...

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        goalName.setCellValueFactory(new PropertyValueFactory<>("goalName"));
        goalDate.setCellValueFactory(new PropertyValueFactory<>("goalDate"));
        goalDate.setCellValueFactory(new PropertyValueFactory<>("goalStatus"));
        goalGroups.setCellValueFactory(new PropertyValueFactory<>("goalGroups"));


    }

    

    private ObservableList<Goal> getGoals(){
        return FXCollections.observableList(user.getGoals());
    }
}

Typically here the user would not be the only value you would need to observe, so it would be factored out into a model somewhere. See, for example, Applying MVC With JavaFx