im trying to populate data from DB(using MySQL) into TableView, the problem i get is, whenever there is a NULL data in some column there will be an error NullPointerException, before using FX im using SWING component and there is no problem with my code, its kinda hard for me to porting it. im using NetBeans IDE and Gluon Scene Builder. the NULL data on DB are used purposedly for some conditional situation to create view in my DB. i think i know my problem are located in populating data in my HandlerComponent.java but i dont know what to do.
this is the code TableController.java
public class TableController implements Initializable {
Connection CONN;
Database DB = new Database();
HandlerComponent COMP_HANDLER;
@FXML
private TableView tblView;
@FXML
private Button btnLoad;
@FXML
private TextField txTable;
@FXML
private Label lblKolom1;
@FXML
private TextField txKolom1;
@FXML
private Label lblKolom2;
@FXML
private TextField txKolom2;
@FXML
private Button btnTambah;
@FXML
private Button btnHapus;
@FXML
private Button btnReset;
@Override
public void initialize(URL url, ResourceBundle rb) {
try {
COMP_HANDLER = new HandlerComponent();
tblView = COMP_HANDLER.iniTable(tblView, "SELECT * FROM items", DB);
} catch (Exception ex) {
ex.printStackTrace();
}
}
@FXML
public void loadTable() {
try {
tblView.getColumns().clear();
tblView = COMP_HANDLER.iniTable(tblView, "SELECT * FROM "+txTable.getText(), DB);
tblView.refresh();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@FXML
public void getDataTable(javafx.scene.input.MouseEvent e) {
if(e.getClickCount() == 2 && !e.isConsumed()) {
System.out.println("double Clicked");
}
}
}
Table.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorPane" prefHeight="513.0" prefWidth="600.0" style="-fx-background-color: #123456;" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.TableController">
<stylesheets>
<URL value="@designskena.css" />
</stylesheets>
<children>
<VBox prefHeight="497.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<FlowPane prefHeight="79.0" prefWidth="600.0">
<children>
<Button fx:id="btnLoad" mnemonicParsing="false" onAction="#loadTable" prefHeight="58.0" prefWidth="92.0" text="Load Data">
<FlowPane.margin>
<Insets />
</FlowPane.margin>
</Button>
<TextField fx:id="txTable" prefHeight="58.0" prefWidth="431.0" text="Table">
<FlowPane.margin>
<Insets left="25.0" />
</FlowPane.margin>
</TextField>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
<padding>
<Insets bottom="25.0" left="25.0" right="25.0" top="25.0" />
</padding></FlowPane>
<TableView fx:id="tblView" onMouseClicked="#getDataTable" prefHeight="258.0" prefWidth="600.0" style="-fx-background-color: black;" stylesheets="@designskena.css">
<VBox.margin>
<Insets left="25.0" right="25.0" />
</VBox.margin>
</TableView>
<Pane prefHeight="165.0" prefWidth="600.0">
<children>
<Label fx:id="lblKolom1" layoutX="25.0" layoutY="14.0" prefHeight="17.0" prefWidth="58.0" text="Kolom 1" />
<TextField fx:id="txKolom1" layoutX="25.0" layoutY="38.0" />
<Label fx:id="lblKolom2" layoutX="206.0" layoutY="14.0" prefHeight="17.0" prefWidth="58.0" text="Kolom 2" />
<TextField fx:id="txKolom2" layoutX="206.0" layoutY="38.0" />
<Button fx:id="btnTambah" layoutX="25.0" layoutY="86.0" mnemonicParsing="false" text="Tambah" />
<Button fx:id="btnHapus" layoutX="99.0" layoutY="86.0" mnemonicParsing="false" text="Hapus" />
<Button fx:id="btnReset" layoutX="163.0" layoutY="86.0" mnemonicParsing="false" text="Reset" />
</children>
<padding>
<Insets bottom="25.0" left="25.0" right="25.0" top="25.0" />
</padding>
</Pane>
</children>
</VBox>
</children>
</AnchorPane>
and this is the HandlerComponent.java
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.ResultSet;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.util.Callback;
/**
* Class untuk membantu konfigurasi setiap COMPONENT JavaFX
* yang terdapat pada java dengan koneksi Database.
* @author RHS
* @version 0.1a
*/
public class HandlerComponent {
protected Connection H_CONN;
protected ResultSet H_RESULTSET;
// Properti yang dibutuhkan untuk Handler Tabel
public String[] COLUMN_TYPE, COLUMN_NAME;
public Object[] OBJ_DATA;
/**
* <b>Constructor</b> untuk kelas <i>HandlerComponent</i>, akan memanggil metode untuk
* koneksi driver database pada kelas database, dengan menyimpan
* koneksi pada variable <i><b>H_CONN</b></i>
* @throws SQLException
*/
public HandlerComponent() throws SQLException {
H_CONN = new Database().inisiasiDB();
}
public TableView iniTable(TableView TABLE, String SQL, Database DBClass) {
ObservableList<ObservableList> DATA = FXCollections.observableArrayList();
try
{
//H_CONN = new DBClass().inisiasiDB();
H_RESULTSET = DBClass.getSQL(SQL);
int count = H_RESULTSET.getMetaData().getColumnCount();
COLUMN_NAME = new String[count];
COLUMN_TYPE = new String[count];
OBJ_DATA = new Object[count];
/**
* ======================================
* Pembuatan Kolom tabel secara dinamis *
* ======================================
*/
for(int x=0; x<count; x++) {
final int j = x;
// pengecekan nama-kolom pada database untuk digenerate pada
// tabel yang dituju serta pengecekan tipedata pada tiap kolom
// yang kemudian akan disimpan pada variable String array
// COLUMN_NAME[] dan COLUMN_TYPE
COLUMN_NAME[x] = H_RESULTSET.getMetaData().getColumnName(x+1);
COLUMN_TYPE[x] = H_RESULTSET.getMetaData().getColumnTypeName(x+1);
System.out.print(COLUMN_TYPE[x]);
// pembuatan kolom tabel berdasarkan COLUMN_NAME
// yang telah dibuat
TableColumn col = new TableColumn(COLUMN_NAME[x]);
// this is where the NullPointerException are triggered
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
// Menambahkan kolom yang sudah di generate sebelumnya
// ke dalam tabel tabel tujuan
TABLE.getColumns().addAll(col);
System.out.println(" | Column [" + x + "] "+col);
}
/**
* ============================
* Penambahan Data pada tabel *
* ============================
*/
while(H_RESULTSET.next()) {
// pembuatan tipe data ObservableList untuk digunakan
// dalam menampung data yang akan dimasukan dalam tabel perbarisnya
ObservableList<Object> row = FXCollections.observableArrayList();
for (int x = 1; x <= count; x++) {
// pengecekan data pada setiap kolom yang ada di database
// pada baris yang sama untuk disesuaikan tipedata yg nantinya
// akan disimpan dalam tipedata Object
switch(COLUMN_TYPE[x-1]) {
case "INT" :
OBJ_DATA[x-1] = H_RESULTSET.getInt(x);
break;
case "DOUBLE" :
OBJ_DATA[x-1] = H_RESULTSET.getDouble(x);
break;
case "FLOAT" :
OBJ_DATA[x-1] = H_RESULTSET.getFloat(x);
break;
case "VARCHAR" :
OBJ_DATA[x-1] = H_RESULTSET.getString(x);
break;
case "CHAR" :
OBJ_DATA[x-1] = H_RESULTSET.getString(x);
break;
case "TEXT" :
OBJ_DATA[x-1] = H_RESULTSET.getString(x);
break;
case "DATE" :
OBJ_DATA[x-1] = H_RESULTSET.getString(x);
break;
default :
OBJ_DATA[x-1] = "Unkown Datatype (HandlerComponent.Java)";
break;
}
//
row.add(OBJ_DATA[x-1]);
}
System.out.println("Row [1] added " + row);
DATA.add(row);
}
TABLE.setItems(DATA);
} catch (SQLException ex) {
ex.printStackTrace();
System.out.println("Error on Building Data");
}
return TABLE;
}
}
this is Database.java
import com.mysql.jdbc.Driver;
import java.sql.Connection; import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.PreparedStatement;
import java.sql.Statement; import java.sql.SQLException;
import javax.swing.JOptionPane;
public class Database {
private static Connection config;
private Connection CONFIG;
private static Driver DRIVER_MANAGER;
private static String PARAMETER_CONN;
public static String DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASS, STMT, LOG;
public ResultSet RES;
public Statement STM;
public PreparedStatement PREP;
public Database() {
Database.setDB_HOST("localhost");
Database.setDB_NAME("rab");
Database.setDB_USER("root");
Database.setDB_PASS("");
Database.setDB_PORT("3306");
}
public Database(String db_name, String user, String pass) {
Database.DB_NAME = db_name; Database.DB_USER = user;
Database.DB_PASS = pass;
}
public static void setDB_HOST(String DB_HOST) {
Database.DB_HOST = DB_HOST;
}
public static void setDB_PORT(String DB_PORT) {
Database.DB_PORT = DB_PORT;
}
public static void setDB_NAME(String DB_NAME) {
Database.DB_NAME = DB_NAME;
}
public static void setDB_USER(String DB_USER) {
Database.DB_USER = DB_USER;
}
public static void setDB_PASS(String DB_PASS) {
Database.DB_PASS = DB_PASS;
}
public static void setConfig(Connection config) {
Database.config = config;
}
public void setConfigs(Connection config) {
CONFIG = config;
}
public static void setSTMT(String STMT) {
Database.STMT = STMT;
}
public Connection getConfig() {
return config;
}
protected String getLog() {
return LOG;
}
protected void setLog(String Description) {
Database.LOG = ("\nQuery Performed :"+Description+" =========================================\n"
+ Database.STMT
+ "\n========================================================\n");
}
protected void setLog(String Description, String SQL) {
Database.LOG = ("\nQuery Performed :"+Description+" =========================================\n"
+ SQL
+ "\n========================================================\n");
}
/**
* Query Select untuk SQL
* dengan syarat harus memberikan query pada property STMT
* e.g. "<i>SELECT * FROM <b>namaTable</b></i>"<br> atau "<i>SELECT * FROM <b>namaTable</b> WHERE <b>kolom</b> = "<u>kondisi</u>"</i>"
* @return ResultSet executeQuery();
* @throws SQLException
* @see setSTMT();
*/
public ResultSet getSQL() throws SQLException {
checkConnection();
STM = Database.config.createStatement();
LOG = Database.STMT;
RES = STM.executeQuery(Database.STMT);
setLog("Getting Data");
System.out.println(getLog());
return RES;
}
/**
* Query Select untuk SQL dengan Custom Parameter
* @param Query String SQL
* e.g. "<i>SELECT * FROM <b>namaTable</b></i>"<br> atau "<i>SELECT * FROM <b>namaTable</b> WHERE <b>kolom</b> = "<u>kondisi</u>"</i>"
* @return ResultSet executeQuery();
* @throws SQLException
*/
public ResultSet getSQL(String Query) throws SQLException {
//checkConnection();
STM = Database.config.createStatement();;
setLog("Getting Data", Query);
System.out.println(getLog());
return (RES = STM.executeQuery(Query));
}
public int insertSQL(Object[] DATA, String TABLE, String PRIMARY_KEY) throws SQLException {
String[] SQL = Database.STMT.split("\\s");
int result = 0;
// pengecualian table cek
if( (searchIndexDB(DATA[0].toString(),PRIMARY_KEY,TABLE) == -1)
|| (SQL[0].equalsIgnoreCase("UPDATE"))
|| (TABLE.equalsIgnoreCase("orderdetail"))
|| (TABLE.equalsIgnoreCase("recipe"))) {
//System.out.println("Data ["+DATA[0]+"] belum ada di DB");
PREP = Database.config.prepareStatement(STMT);
String typedata = "";
int pointer = 0;
if(SQL[0].equalsIgnoreCase("UPDATE")){
setLog("Update Data");
result = 2;
}
else {
setLog("Insert Data");
result = 1;
}
System.out.println(getLog());
for (Object temp : DATA) {
typedata = temp.getClass().getSimpleName();
System.out.println(temp.getClass().getSimpleName()+" : "+DATA[pointer]);
switch (typedata) {
case "String" :
PREP.setString(pointer+1, DATA[pointer].toString());
break;
case "Integer" :
PREP.setInt(pointer+1, Integer.parseInt(DATA[pointer].toString()));
break;
case "Float" :
PREP.setFloat(pointer+1, Float.parseFloat(DATA[pointer].toString()));
break;
case "Double" :
PREP.setDouble(pointer+1,Double.parseDouble(DATA[pointer].toString()));
break;
}
pointer++;
}
PREP.executeUpdate();
return result;
}else{
System.out.println("Data ["+DATA[0]+"] Sudah ada di DB\n"
+ "Silahkan Gunakan fitur Update");
JOptionPane.showMessageDialog(null, "Ooppss!. Data tersebut sudah ada\n"
+ "Silahkan gunakan Fitur UPDATE","Warning",1);
return result;
}
}
public int deleteSQL(String KEY) throws SQLException{
checkConnection();
PREP = Database.config.prepareStatement(STMT);
PREP.setString(1, KEY);
setLog("Delete Data");
System.out.println(getLog());
return (PREP.executeUpdate());
}
public int deleteSQL(String KEY, String SQL) throws SQLException{
checkConnection();
setSTMT(SQL);
setLog("Delete Data");
System.out.println(getLog());
PREP = Database.config.prepareStatement(STMT);
PREP.setString(1, KEY);
return (PREP.executeUpdate());
}
/**
* Metode untuk mencari adanya data dalam DB
* e.g. searchIndexDB(<u>textField.getText(), "kolom", "table"</u>) atau<br>
* searchIndexDB(<u>txID.getText(), "id", "user"</u>)
* @param SEARCH data yang ingin dicari
* @param FIELD kolom field yang dicari
* @param TABLE table yang dicari
* @return mengembalikan tipedata Integer, bernilai -1 jika tidak ditemukan,<br>dan akan mengembalikan nilai index jika ditemukan dalam DB;
* @throws SQLException
*/
public int searchIndexDB(String SEARCH, String FIELD, String TABLE) throws SQLException {
int index = -1, i = 0;
//Database.setSTMT("SELECT "+FIELD+" FROM "+TABLE+" ORDER BY "+FIELD+" ASC");
RES = getSQL("SELECT "+FIELD+" FROM "+TABLE+" ORDER BY "+FIELD+" ASC");
while (RES.next()) {
if(true == RES.getString(1).equalsIgnoreCase(SEARCH)) {
index = i;
break;
}
i++;
}
setLog("Search Index");
System.out.println(getLog());
return index;
}
public static Connection inisiasiDB() throws SQLException {
if ((Database.DB_NAME == null) || (Database.DB_USER == null) || (Database.DB_PASS == null) || (Database.DB_PORT == null) || (Database.DB_HOST == null)) {
JOptionPane.showMessageDialog(null,"Database Belum disetting");
if (Database.DB_NAME == null) {
String DBname = JOptionPane.showInputDialog("Nama Database");
Database.DB_NAME = DBname;
}
if (Database.DB_USER == null) setDB_USER(JOptionPane.showInputDialog("User"));
if (Database.DB_PASS == null) Database.DB_PASS = JOptionPane.showInputDialog("Password");
if (Database.DB_PORT == null) Database.DB_PORT = JOptionPane.showInputDialog("Port");
if (Database.DB_HOST == null) Database.DB_HOST = JOptionPane.showInputDialog("Host");
Database.PARAMETER_CONN = "jdbc:mysql://"+Database.DB_HOST+":"+Database.DB_PORT+"/"+Database.DB_NAME;
}
try {
Database.DRIVER_MANAGER = new com.mysql.jdbc.Driver();
Database.PARAMETER_CONN = "jdbc:mysql://"+Database.DB_HOST+":"+Database.DB_PORT+"/"+Database.DB_NAME;
DriverManager.registerDriver(DRIVER_MANAGER);
setConfig(DriverManager.getConnection(Database.PARAMETER_CONN,Database.DB_USER, Database.DB_PASS));
System.out.println("Koneksi Sukses ========================\n DB_NAME : "+DB_NAME);
} catch (SQLException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null,"Driver untuk Koneksi database tidak ada\nSilahkan nyalakan services MySQL pada XAMPP");
}
return config;
}
public Connection inisiasiDBnoStatic() throws SQLException {
if ((Database.DB_NAME == null) || (Database.DB_USER == null) || (Database.DB_PASS == null) || (Database.DB_PORT == null) || (Database.DB_HOST == null)) {
JOptionPane.showMessageDialog(null,"Database Belum disetting");
if (Database.DB_NAME == null) {
String DBname = JOptionPane.showInputDialog("Nama Database");
Database.DB_NAME = DBname;
}
if (Database.DB_USER == null) setDB_USER(JOptionPane.showInputDialog("User"));
if (Database.DB_PASS == null) Database.DB_PASS = JOptionPane.showInputDialog("Password");
if (Database.DB_PORT == null) Database.DB_PORT = JOptionPane.showInputDialog("Port");
if (Database.DB_HOST == null) Database.DB_HOST = JOptionPane.showInputDialog("Host");
Database.PARAMETER_CONN = "jdbc:mysql://"+Database.DB_HOST+":"+Database.DB_PORT+"/"+Database.DB_NAME;
}
try {
Database.DRIVER_MANAGER = new com.mysql.jdbc.Driver();
Database.PARAMETER_CONN = "jdbc:mysql://"+Database.DB_HOST+":"+Database.DB_PORT+"/"+Database.DB_NAME;
DriverManager.registerDriver(DRIVER_MANAGER);
setConfigs(DriverManager.getConnection(Database.PARAMETER_CONN,Database.DB_USER, Database.DB_PASS));
System.out.println("Koneksi Sukses ========================\n DB_NAME : "+DB_NAME);
} catch (SQLException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null,"Driver untuk Koneksi database tidak ada\nSilahkan nyalakan services MySQL pada XAMPP");
}
return CONFIG;
}
private void checkConnection() throws SQLException{
if(getConfig() == null) {
setConfig(inisiasiDB());
}
}
public int lastInventID(){
int result= -1;
try {
checkConnection();
setSTMT("SELECT no FROM inventory ORDER BY no ASC");
RES = getSQL(); RES.last();
result = RES.getInt(1);
result++;
} catch (SQLException ex){
ex.printStackTrace();
}
return result;
}
public String generateOrderID() {
try {
checkConnection();
String temp;
RES = getSQL("SELECT orderID FROM orderhead ORDER BY orderID");
LOG = STMT;
RES.last();
temp = RES.getString("orderID");
int increase = Integer.parseInt(temp);
int digit = String.valueOf(increase).length();
switch (digit) {
case 1: {increase++;temp = "000"+increase;}
break;
case 2: {increase++;temp = "00"+increase;}
break;
case 3: {increase++;temp = "0"+increase;}
break;
default: {increase++;temp = ""+increase;}
break;
}
RES.close();
return temp;
} catch(SQLException ex) {
ex.printStackTrace();
}
return "";
}
}
Exception Stack
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at Model.HandlerComponent$1.call(HandlerComponent.java:67)
at Model.HandlerComponent$1.call(HandlerComponent.java:65)