I originally had this application working, but after refactoring, it's got a bug. There are 2 classes involved, fairly simple. Controller and DBController. Controller is responsible for handling the User Interface. DBController is responsible for accessing the database supplied, and returning the necessary objects back to Controller for processing.

Expected Results


Actual Results


Previously, Controller.connect() handled both the database access, ResultSet processing and the UI updating. Here was it's code. (this code produces the desired results)
Controller.connect()
PHP Code:
    private void connect() {
        
StringBuilder dbUrl = new StringBuilder("jdbc:sqlite:");
        if (
dbUrlTxt.getText().isEmpty()) {
            new 
Alert(Alert.AlertType.ERROR"Database url must be specified.").showAndWait();
        } else {
            try {
                
connection getConnection(dbUrl.append(dbUrlTxt.getText()).toString());
            } catch (
SQLException e) {
                
e.printStackTrace();
            }
            
String tableQuery "SELECT * FROM sqlite_master WHERE type='table' ORDER BY name";
            try (
PreparedStatement tableQueryPS connection.prepareStatement(tableQuery)) {
                
ResultSet tableNames tableQueryPS.executeQuery();

                while (
tableNames.next()) {

                    
Tab tab = new Tab(tableNames.getString("name"));
                    
tabPane.getTabs().add(tab);

                    
TableView<ObservableListtableView = new TableView<>();
                    
tab.setContent(tableView);

                    
String dataQuery "SELECT * from " tableNames.getString("name");
                    
ResultSet tableValues connection.createStatement().executeQuery(dataQuery);

                    for (
int i 0tableValues.getMetaData().getColumnCount(); i++) {
                        final 
int j i;
                        
int dataValue tableValues.getMetaData().getColumnType(1);
                        
// I need to use some generics here on the TableColumn to get rid of the Unchecked call to setCellValueFactory()
                        
TableColumn tableColumn = new TableColumn(tableValues.getMetaData().getColumnName(1));
                        if (
dataValue == 4) {
                            
tableColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableListInteger>, ObservableValue<String>>) param ->
                                    
new SimpleStringProperty(param.getValue().get(j).toString()));
                        } else if (
dataValue == 7) {
                            
tableColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableListDouble>, ObservableValue<String>>) param ->
                                    
new SimpleStringProperty(param.getValue().get(j).toString()));
                        } else if (
dataValue == 12) {
                            
tableColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableListString>, ObservableValue<String>>) param ->
                                    
new SimpleStringProperty(param.getValue().get(j).toString()));
                        }
                        
tableView.getColumns().addAll(tableColumn);
                    }

                    
ObservableList<ObservableListdata FXCollections.observableArrayList();

                    while (
tableValues.next()) {
                        
ObservableList<Stringrow FXCollections.observableArrayList();
                        for (
int i 1<= tableValues.getMetaData().getColumnCount(); i++) {
                            
row.add(tableValues.getString(i));
                        }
                        
data.add(row);
                    }
                    
tableValues.close();
                    
tableView.getItems().addAll(data);
                }
                
tableNames.close();

            } catch (
SQLException tableQueryException) {
                
System.err.println(tableQueryException.toString());
            }
            
connectBtn.setDisable(true);
            
disconnectBtn.setDisable(false);
            
addBtn.setDisable(false);
            
updateBtn.setDisable(false);
            
deleteBtn.setDisable(false);
            
saveBtn.setDisable(false);
        }
    } 
Now Controller.handleConnect() is in charge, along with an instance of DBController

Controller.handleConnect()
PHP Code:
    private void handleConnect() {
        if (
dbUrlTxt.getText().isEmpty() && !Main.debug) {
            new 
Alert(Alert.AlertType.ERROR"Database url must be specified.").showAndWait();
        } else {
            
dbController = new DBController();
            
dbController.connect(dbUrlTxt.getText());
            
toggleButtons();

            
//process table
            
List<StringtableNames dbController.queryTables();

            
tableNames.forEach(tableName -> {
                if (
Main.debug) {
                    
System.out.println(tableName " table");
                    
System.out.println("-------------------------");
                }
                
Tab tab = new Tab(tableName);
                
tabPane.getTabs().add(tab);

                
TableView<ObservableListtableView = new TableView<>();
                
tab.setContent(tableView);

                
//process columns
                
Map<StringStringcolumns dbController.queryColumns(tableName);
                if (
Main.debug) {
                    
System.out.println("Column Name, Column Type");
                    
System.out.println("-------------------------");
                }
                
columns.forEach((columnNamecolumnType) -> {
                    if (
Main.debug) { System.out.println(columnName ", " columnType); }
                    
TableColumn tableColumn = new TableColumn(columnName);
                    switch (
columnType) {
                        case 
"INTEGER":
                            
tableColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableListInteger>, ObservableValue<String>>) param ->
                                    
new SimpleStringProperty(param.getValue().toString()));
                        case 
"REAL":
                            
tableColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableListDouble>, ObservableValue<String>>) param ->
                                    
new SimpleStringProperty(param.getValue().toString()));
                        case 
"TEXT":
                        case 
"NONE":
                        default:
                            
tableColumn.setCellValueFactory((Callback<TableColumn.CellDataFeatures<ObservableListString>, ObservableValue<String>>) param ->
                                    
new SimpleStringProperty(param.getValue().toString()));
                    }
                    
tableView.getColumns().addAll(tableColumn);
                });
                if (
Main.debug) { System.out.println(); }

                
// process rows
                
ObservableList<ObservableListrows dbController.queryRows(tableName);
                if (
Main.debug) {
                    
rows.forEach(row -> System.out.println(row));
                    
System.out.println();
                }
                
tableView.getItems().addAll(rows);
            });
        }
    } 
DBController
PHP Code:
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Alert;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class 
DBController {

    private 
Connection connection;

    
Connection getConnection() {
        return 
connection;
    }

    
void connect(String databaseURL) {
        
Connection connection null;
        
StringBuilder dbUrl = new StringBuilder("jdbc:sqlite:");
        
dbUrl.append(databaseURL);
        try {
            if (
Main.debug) {
                
connection DriverManager.getConnection("jdbc:sqlite:C:/products.sqlite");
                
System.out.println("Connection to C:/products.sqlite established\n");
            } else {
                
connection DriverManager.getConnection(dbUrl.toString());
            }
        } catch (
SQLException connectionException) {
            
System.err.println(connectionException.toString());
            new 
Alert(Alert.AlertType.ERROR"There was a problem connecting to the database. Please check that the url is correct.").showAndWait();
        }
        
this.connection connection;
    }

    List<
StringqueryTables() {
        
String statement "SELECT * FROM sqlite_master WHERE type='table' ORDER BY name";
        List<
StringtableNames = new ArrayList<>();
        try (
PreparedStatement preparedStatement connection.prepareStatement(statement)) {
            
ResultSet resultSet preparedStatement.executeQuery();
            while (
resultSet.next()) {
                
tableNames.add(resultSet.getString("name"));
            }
            
resultSet.close();
        } catch (
SQLException tableQueryException) {
            
System.err.println(tableQueryException.toString());
        }
        return 
tableNames;
    }

    
Map<StringStringqueryColumns(String tableName) {
        
String statement "PRAGMA table_info(" tableName ")";
        
Map<StringStringcolumns = new HashMap<>();
        try (
PreparedStatement preparedStatement connection.prepareStatement(statement)) {
            
ResultSet resultSet preparedStatement.executeQuery();
            while (
resultSet.next()) {
                
columns.put(resultSet.getString("name"), resultSet.getString("type"));
            }
            
resultSet.close();
        } catch (
SQLException columnQueryException) {
            
System.err.println(columnQueryException.toString());
        }
        return 
columns;
    }


    
ObservableList<ObservableListqueryRows(String tableName) {
        
String statement "SELECT * from " tableName;
        
ObservableList<ObservableListrows FXCollections.observableArrayList();
        try (
PreparedStatement preparedStatement connection.prepareStatement(statement)) {
            
ResultSet resultSet preparedStatement.executeQuery();
            while (
resultSet.next()) {
                
ObservableList<Stringrow FXCollections.observableArrayList();
                for (
int i 1<= resultSet.getMetaData().getColumnCount(); i++) {
                    
row.add(resultSet.getString(i));
                }
                
rows.add(row);
            }
            
resultSet.close();
        } catch (
SQLException rowQueryException) {
            
System.err.println(rowQueryException.toString());
        }
        return 
rows;
    }

    
void disconnect() {
        
this.connection null;
        if (
Main.debug) { System.out.println("Connection Closed"); }
    }


I know this is fairly complicated but please, any help would be greatly appreciated. I've been trying to fix this bug for over 2 weeks now, no one seems to be able to help. Full source code can be found here. https://github.com/elsheepo/SQLite-Database-Manager