Reputation: 27
I am creating an app as my homework that takes in customer information and register it using derby database and javafx. Once registered, the new customer will appear on a tableview. I've been trying to add rows to tableview but java.lang.reflect.InvocationTargetException
keeps popping up and I have no idea what is going on. I want to retrieve data from my derby database and show it in a tableview in my app. When you open the app, there is an option to add new customer. When clicked on the option to add new customer, a new window will pop up that asks for the new customer's information. I have made a separate FXML file for the new customer entry window and a separate controller for it (neither are shown here). After entering all of the required information on the customer entry window, you click on the submit button and the entered information will be inserted into the derby database, then the NewCustomerEntryController class will call the "handleNewSubmit" method in the "RetailSystemController" class (shown below). Please see my code below and the exception that pops up.
This is the main class that overrides the start method of javafx and I have set up my driver and URL connection for derby in this class
package retailsystem;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.DatabaseMetaData;
public class main extends Application {
private static Connection conn;
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("retailsystem.fxml"));
primaryStage.setTitle("Retail System Management");
primaryStage.setScene(new Scene(root, 600, 400));
setUpDB();
primaryStage.show();
}
private void setUpDB() throws Exception {
String driver = "org.apache.derby.jdbc.EmbeddedDriver";
String dbName = "RetailSystemDB";
String connectionURL = "jdbc:derby:" + dbName + ";create=true";
String createCustomerString = "CREATE TABLE Customer (FirstName VARCHAR (50) NOT "
+ "NULL, LastName VARCHAR(50) NOT NULL, StreetAddress VARCHAR(50) "
+ "NOT NULL, City VARCHAR(20) NOT NULL, State VARCHAR(12) NOT NULL, "
+ "Zipcode VARCHAR(5), Gender VARCHAR(6))";
Class.forName(driver);
conn = DriverManager.getConnection(connectionURL);
Statement stmt = conn.createStatement();
DatabaseMetaData dbm = conn.getMetaData();
ResultSet checkCustomer = dbm.getTables(null, null, "CUSTOMER", null);
if (!checkCustomer.next()) {
stmt.executeUpdate(createCustomerString);
}
stmt.close();
}
public static Connection getConn() {
return conn;
}
public static void main(String[] args) {
launch(args);
}
}
The code below is the controller for the new customer entry window:
package retailsystem;
import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Scanner;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.stage.Stage;
import java.sql.Connection;
import java.sql.PreparedStatement;
import javafx.scene.control.TableView;
public class CustomerInformationController implements Initializable {
@FXML
private TextField fEntry;
@FXML
private TextField lEntry;
@FXML
private TextField aEntry;
@FXML
private TextField cEntry;
@FXML
private ComboBox<String> sEntry;
@FXML
private RadioButton male;
@FXML
private RadioButton female;
@FXML
private TextField zEntry;
@FXML
private Button submitBTN;
@FXML
private Button cancelBtn;
private static person customer;
ToggleGroup group = new ToggleGroup();
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
String[] stateList = getStateList();
for (int i = 0; i < stateList.length; i++) {
sEntry.getItems().add(stateList[i]);
}
sEntry.setValue(stateList[0]);
male.setToggleGroup(group);
female.setToggleGroup(group);
}
@FXML
private void handleSubmit(ActionEvent event) throws Exception {
RadioButton selectedBtn = (RadioButton) group.getSelectedToggle();
customer = new person(fEntry.getText(), lEntry.getText(),
aEntry.getText(), cEntry.getText(), sEntry.getValue(), zEntry.getText(),
selectedBtn.getText());
Connection conn = main.getConn();
PreparedStatement psInsert = conn.prepareStatement("INSERT INTO CUSTOMER "
+ "(FirstName, LastName, StreetAddress, City, State, Zipcode, "
+ "Gender) VALUES(?,?,?,?,?,?,?)");
psInsert.setString(1, customer.getFirstName());
psInsert.setString(2, customer.getLastName());
psInsert.setString(3, customer.getAddress());
psInsert.setString(4, customer.getCity());
psInsert.setString(5, customer.getState());
psInsert.setString(6, customer.getZipcode());
psInsert.setString(7, customer.getGender());
psInsert.executeUpdate();
RetailSystemController retailcontroller = new RetailSystemController();
retailcontroller.handleNewSubmit();
psInsert.close();
}
}
The code below is my fxml file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<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="retailsystem.RetailSystemController">
<center>
<TableView fx:id="tView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn fx:id="fName" prefWidth="90.0" text="First Name" />
<TableColumn fx:id="lName" prefWidth="90.0" text="Last Name" />
<TableColumn fx:id="address" prefWidth="147.0" text="Street Address" />
<TableColumn fx:id="city" prefWidth="87.0" text="City" />
<TableColumn fx:id="state" prefWidth="64.0" text="State" />
<TableColumn fx:id="zip" prefWidth="62.0" text="Zip Code" />
<TableColumn fx:id="gender" prefWidth="70.0" text="Gender" />
</columns>
</TableView>
</center>
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="Customer">
<items>
<MenuItem mnemonicParsing="false" onAction="#handleCustomerAddNew" text="Add New" />
<MenuItem mnemonicParsing="false" onAction="#handleCustomerListAll" text="List All" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Employee">
<items>
<MenuItem mnemonicParsing="false" onAction="#handleEmployeeAddNew" text="Add New " />
<MenuItem mnemonicParsing="false" onAction="#handleEmployeeListAll" text="List All" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Merchandise">
<items>
<MenuItem mnemonicParsing="false" onAction="#handleMerchandiseAddNew" text="Add New" />
<MenuItem mnemonicParsing="false" onAction="#handleMerchandiseListAll" text="List All" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
The code below is the controller class for the above noted fxml file, there are quite a few handlers in this class but I am just focussed on the "handleCustomerAddnew" and "handleNewSubmit" for now as I haven't written much code for the others. The problem happens in the handleNewSubmit method in this class:
package retailsystem;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
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 javafx.stage.Window;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class RetailSystemController implements Initializable {
@FXML
private TableColumn fName;
@FXML
private TableColumn lName;
@FXML
private TableColumn address;
@FXML
private TableColumn city;
@FXML
private TableColumn state;
@FXML
private TableColumn zip;
@FXML
private TableColumn gender;
@FXML
private TableView<person> tView;
public void initialize(URL url, ResourceBundle rb) {
//ToDo
fName.setCellValueFactory(new PropertyValueFactory<person, String>("firstName"));
lName.setCellValueFactory(new PropertyValueFactory<person, String>("lastName"));
address.setCellValueFactory(new PropertyValueFactory<person, String>("address"));
city.setCellValueFactory(new PropertyValueFactory<person, String>("city"));
state.setCellValueFactory(new PropertyValueFactory<person, String>("state"));
zip.setCellValueFactory(new PropertyValueFactory<person, String>("Zipcode"));
gender.setCellValueFactory(new PropertyValueFactory<person, String>("gender"));
}
@FXML
private void handleCustomerAddNew(ActionEvent event) {
Parent root;
try {
root = FXMLLoader.load(getClass().getResource("customerinformation.fxml"));
Stage stage = new Stage();
stage.setTitle("Customer Information");
stage.setScene(new Scene(root, 400, 340));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void handleNewSubmit() {
System.out.println("beginning of handleNewSubmit");
ArrayList<person> registeredPersons=new ArrayList<person>();
Connection conn = main.getConn();
String query = "SELECT * FROM CUSTOMER";
try{
PreparedStatement stmt = conn.prepareStatement(query);
ResultSet resultset = stmt.executeQuery();
while(resultset.next()){
System.out.println(resultset.getString("FirstName")+" "+resultset.getString("LastName"));
registeredPersons.add(new person(resultset.getString("FirstName"),resultset.getString("LastName"), resultset.getString("StreetAddress"),
resultset.getString("City"),resultset.getString("State"),resultset.getString("Zipcode"),resultset.getString("Gender")));
}}
catch (Exception e){
e.printStackTrace();
}
ObservableList<person> items = FXCollections.observableArrayList(registeredPersons);
System.out.println("before adding to tView");
tView.setItems(items);
System.out.println("after adding to tView");
}
}
Errors:
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: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:8885)
at javafx.controls/javafx.scene.control.Button.fire(Button.java:203)
at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
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:3890)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1885)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2618)
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.mac.MacView.notifyMouse(MacView.java:127)
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 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:1782)
... 44 more
Caused by: java.lang.NullPointerException
at retailsystem.RetailSystemController.handleNewSubmit(RetailSystemController.java:127)
at retailsystem.CustomerInformationController.handleSubmit(CustomerInformationController.java:102)
... 55 more
Upvotes: 0
Views: 203
Reputation: 209225
The NullPointerException
is occurring on the line
tView.setItems(items);
tView
is a TableView
defined in your FXML file; it will be initialized in the controller when the FXML file is loaded. The reason it is null when you call handleNewSubmit()
is that you are not calling that method on the controller, but on an arbitrary object you created (of the same class as the controller):
private void handleSubmit(ActionEvent event) throws Exception {
// ...
RetailSystemController retailcontroller = new RetailSystemController();
retailcontroller.handleNewSubmit();
// ...
}
The best way to solve this is simply to pass the table's items list to the CustomerInformationController
when you show the customerinformation.fxml
file. That way the CustomerInformationController
can update the table data directly. Right now you are trying to load all the data from the database again when you add a new item: that seems pretty unnecessary; all you need to do is add the new item to the list, if the database update is successful.
So you can do:
public class RetailSystemController implements Initializable {
// ...
@FXML
private void handleCustomerAddNew(ActionEvent event) {
Parent root;
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("customerinformation.fxml"));
root = loader.load();
CustomerInformationController ciController = loader.getController();
ciController.setDataList(tbl.getItems());
Stage stage = new Stage();
stage.setTitle("Customer Information");
stage.setScene(new Scene(root, 400, 340));
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void handleNewSubmit() {
// you probably don't need this method any more
}
// ...
}
And then:
public class CustomerInformationController implements Initializable {
// ...
private ObservableList<person> dataList ;
public void setDataList(ObservableList<person> dataList) {
this.dataList = dataList();
}
// ...
@FXML
private void handleSubmit(ActionEvent event) throws Exception {
RadioButton selectedBtn = (RadioButton) group.getSelectedToggle();
customer = new person(fEntry.getText(), lEntry.getText(),
aEntry.getText(), cEntry.getText(), sEntry.getValue(), zEntry.getText(),
selectedBtn.getText());
Connection conn = main.getConn();
PreparedStatement psInsert = conn.prepareStatement("INSERT INTO CUSTOMER "
+ "(FirstName, LastName, StreetAddress, City, State, Zipcode, "
+ "Gender) VALUES(?,?,?,?,?,?,?)");
psInsert.setString(1, customer.getFirstName());
psInsert.setString(2, customer.getLastName());
psInsert.setString(3, customer.getAddress());
psInsert.setString(4, customer.getCity());
psInsert.setString(5, customer.getState());
psInsert.setString(6, customer.getZipcode());
psInsert.setString(7, customer.getGender());
psInsert.executeUpdate();
// RetailSystemController retailcontroller = new RetailSystemController();
// retailcontroller.handleNewSubmit();
psInsert.close();
dataList.add(customer) ;
}
// ...
}
Obviously, in a real application, you would move the database code to a separate class, and handle exceptions appropriately, etc.
If you really do need to reload the entire list from the database again, after adding a new entry, then you can do that in the handleSubmit()
method, and just use dataList.setAll(...)
to replace the existing items, etc. But again, since you know what changes you just made to the database, you can just make the identical change to the table's backing list.
Upvotes: 1