2

I keep getting a java.lang.NullPointerException when running case 0 on run time. The issue seems to be linked to setting the prompt text for my TextField. However, the problem doesn't return when I switch tabs. The GUI was built in Scene Builder. How do i initialize the TextField to a non-null value.

public class BackEndController implements Initializable{

@FXML
private TabPane tabPane;
@FXML
private Tab bookingTab;
@FXML
private Tab waitListTab;
@FXML
private Tab excursionsTab;
@FXML
private TextField searchEntry;

@Override
public void initialize(URL location, ResourceBundle resources) {
    searchEntry.setPromptText("");

}

@FXML
public void switchTabs() {

    int selectedTab = tabPane.getSelectionModel().getSelectedIndex();
    switch (selectedTab){
        case 0:
            searchEntry.setPromptText("Enter booking ID");
            break;
        case 1:
            searchEntry.setPromptText("Enter event name");
            break;
        case 2:
            searchEntry.setPromptText("Enter list ID");
            break;
    }

}

This is the exact error code

    Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1787)
    at javafx.fxml/javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1670)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    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.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.controls/javafx.scene.control.Tab$1.invalidated(Tab.java:215)
    at javafx.base/javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
    at javafx.base/javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
    at javafx.controls/javafx.scene.control.Tab.setSelected(Tab.java:189)
    at javafx.controls/javafx.scene.control.TabPane$TabPaneSelectionModel.select(TabPane.java:738)
    at javafx.controls/javafx.scene.control.TabPane$TabPaneSelectionModel.select(TabPane.java:751)
    at javafx.controls/javafx.scene.control.TabPane$TabPaneSelectionModel.findNearestAvailableTab(TabPane.java:810)
    at javafx.controls/javafx.scene.control.TabPane$TabPaneSelectionModel.lambda$new$0(TabPane.java:707)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
    at javafx.base/javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
    at javafx.base/javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
    at javafx.base/javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
    at javafx.base/javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
    at javafx.base/javafx.collections.ModifiableObservableListBase.add(ModifiableObservableListBase.java:155)
    at java.base/java.util.AbstractList.add(AbstractList.java:111)
    at javafx.fxml/javafx.fxml.FXMLLoader$Element.add(FXMLLoader.java:175)
    at javafx.fxml/javafx.fxml.FXMLLoader$PropertyElement.add(FXMLLoader.java:1415)
    at javafx.fxml/javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:796)
    at javafx.fxml/javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2838)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2557)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2466)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3253)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3210)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3179)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3152)
    at javafx.fxml/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3129)
    at javafx.fxml/javafx.fxml.FXMLLoader.load(FXMLLoader.java:3122)
    at com.main.backend.BackEnd.start(BackEnd.java:18)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:919)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$11(PlatformImpl.java:449)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$9(PlatformImpl.java:418)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:417)
    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:175)
    at java.base/java.lang.Thread.run(Thread.java:844)
Caused by: 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:564)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:76)
    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:564)
    at javafx.base/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:83)
    at javafx.fxml/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1784)
    ... 47 more
Caused by: java.lang.NullPointerException
    at com.main.backend.BackEndController.switchTabs(BackEndController.java:58)
    ... 59 more

My FXML file

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

<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXListView?>
<?import com.jfoenix.controls.JFXTabPane?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="810.0" prefWidth="1250.0" style="-fx-background-color: #FFFFFF;" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.main.backend.BackEndController">
   <children>
      <JFXTabPane fx:id="tabPane" layoutY="67.0" prefHeight="743.0" prefWidth="1250.0" stylesheets="@dark-theme.css">
         <tabs>
            <Tab fx:id="bookingTab" onSelectionChanged="#switchTabs" text="Bookings">
              <content>
                <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" style="-fx-background-color: #F7F7F9;" />
              </content>
            </Tab>
            <Tab fx:id="excursionsTab" onSelectionChanged="#switchTabs" text="Excursions">
              <content>
                <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" style="-fx-background-color: #F7F7F9;">
                     <children>
                        <AnchorPane layoutX="736.0" layoutY="16.0" prefHeight="672.0" prefWidth="501.0" style="-fx-background-color: #FFFFFF; -fx-border-color: #D4D6D8;">
                           <children>
                              <JFXTextField alignment="CENTER" layoutX="17.0" layoutY="85.0" prefHeight="33.0" prefWidth="135.0" promptText="Port ID" styleClass="main-text" stylesheets="@dark-theme.css">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </JFXTextField>
                              <Label alignment="CENTER" layoutX="12.0" layoutY="33.0" prefHeight="33.0" prefWidth="478.0" text="Label" textFill="#9f9f9f">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </Label>
                              <JFXButton layoutX="265.0" layoutY="178.0" prefHeight="33.0" prefWidth="174.0" style="-fx-background-color: #FA597A; -fx-border-color: #FA597A; -fx-border-radius: 30; -fx-background-radius: 30;" text="Delete Event" textFill="WHITE">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </JFXButton>
                              <JFXButton layoutX="17.0" layoutY="178.0" prefHeight="33.0" prefWidth="185.0" style="-fx-background-color: #FFFFFF; -fx-border-color: #214099; -fx-border-radius: 30; -fx-background-radius: 30;" text="Update Event" textFill="#214099">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </JFXButton>
                              <Separator layoutX="21.0" layoutY="272.0" prefHeight="13.0" prefWidth="460.0" />
                              <JFXTextField alignment="CENTER" layoutX="17.0" layoutY="321.0" prefHeight="33.0" prefWidth="468.0" promptText="Event Name" styleClass="main-text" stylesheets="@dark-theme.css">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </JFXTextField>
                              <JFXTextField alignment="CENTER" layoutX="19.0" layoutY="396.0" prefHeight="33.0" prefWidth="135.0" promptText="Port ID" styleClass="main-text" stylesheets="@dark-theme.css">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </JFXTextField>
                              <JFXButton layoutX="173.0" layoutY="470.0" prefHeight="33.0" prefWidth="185.0" style="-fx-background-color: #FFFFFF; -fx-border-color: #15d31e; -fx-border-radius: 30; -fx-background-radius: 30;" text="Add Event" textFill="#15d31e">
                                 <font>
                                    <Font name="System Bold" size="15.0" />
                                 </font>
                              </JFXButton>
                           </children>
                        </AnchorPane>
                        <JFXListView fx:id="excursionsList" layoutX="16.0" layoutY="16.0" prefHeight="672.0" prefWidth="711.0" styleClass="list-cell" stylesheets="@dark-theme.css" />
                     </children>
                  </AnchorPane>
              </content>
            </Tab>
            <Tab fx:id="waitListTab" onSelectionChanged="#switchTabs" text="Waiting List">
               <content>
                  <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" style="-fx-background-color: #F7F7F9;" />
               </content>
            </Tab>
         </tabs>
      </JFXTabPane>
      <JFXButton layoutX="609.0" layoutY="18.0" prefHeight="32.0" prefWidth="110.0" style="-fx-background-color: #214099; -fx-border-color: #214099; -fx-border-radius: 30; -fx-background-radius: 30;" text="Search" textFill="WHITE">
         <font>
            <Font name="System Bold" size="15.0" />
         </font>
      </JFXButton>
      <JFXButton layoutX="740.0" layoutY="18.0" prefHeight="32.0" prefWidth="99.0" style="-fx-background-color: #FFFFFF; -fx-border-color: #214099; -fx-border-radius: 30; -fx-background-radius: 30;" text="Reset" textFill="#214099">
         <font>
            <Font name="System Bold" size="15.0" />
         </font>
      </JFXButton>
      <JFXButton layoutX="1113.0" layoutY="18.0" prefHeight="32.0" prefWidth="116.0" style="-fx-background-color: #FA597A; -fx-border-color: #FA597A; -fx-border-radius: 30; -fx-background-radius: 30;" text="Sign Out" textFill="WHITE">
         <font>
            <Font name="System Bold" size="15.0" />
         </font>
      </JFXButton>
      <JFXTextField fx:id="searchEntry" layoutX="104.0" layoutY="20.0" prefHeight="32.0" prefWidth="449.0" promptText="Enter booking ID" styleClass="search-textfield" stylesheets="@dark-theme.css">
         <font>
            <Font name="System Bold" size="15.0" />
         </font>
      </JFXTextField>
   </children>
</AnchorPane>

The FXML file does have the correct controller attached

Edmund
  • 63
  • 7

1 Answers1

1

As the FXML is parsed, the FXMLLoader creates the TabPane, and creates the Tabs and adds them to the TabPane. When the first tab is added, it becomes selected, so its selected state changes and its onSelectionChanged handler is invoked. Since the TabPane appears in the FXML file before the searchEntry text field, this happens before searchEntry is initialized, and consequently your switchTabs() method throws a null pointer exception.

You could simply add a null check to the handler method:

@FXML
public void switchTabs() {

    if (searchEntry == null) {
        return ;
    }

    int selectedTab = tabPane.getSelectionModel().getSelectedIndex();
    switch (selectedTab){
        case 0:
            searchEntry.setPromptText("Enter booking ID");
            break;
        case 1:
            searchEntry.setPromptText("Enter event name");
            break;
        case 2:
            searchEntry.setPromptText("Enter list ID");
            break;
    }

}

Adding this code just to handle a special case that only occurs during loading is a little ugly. I would prefer just to register a handler in the initalize() method. Remove all the onSelectionChanged handlers from the tabs in the FXML file, and add the following to your controller's initialize() method:

@Override
public void initialize(URL location, ResourceBundle resources) {
    tabPane.getSelectionModel().selectedIndexProperty().addListener(
        (obs, oldIndex, newIndex) -> switchTabs());

    // initialize prompt text for initially-selected tab:
    switchTabs();
    // searchEntry.setPromptText("");

}
James_D
  • 177,111
  • 13
  • 247
  • 290