0

i'm new to JavaFX and i want to print some BigDecimal and Bean in TableColumn in my TableView. The issue is that i get a NullPointerExceptionexception when i try to setItems of the TableView.

Just to be clear i'm using the fxml with scenario builder for the graphic (panel, tableView, etc.) and the java class for link the bean's data to the tableView. I'm using the ObservableList for get the change, and the Bean has the correct getter that return ObjectProperty<BigDecimal> or ObjectProperty<ContoBean>.

I don't know if what i'm using for setCellValueFactory is correct, i've tryed to follow the tutorial here, but in this tutorial the TableColumn are set only as String. I've read some example for do the the setCellValueFactory, but as far as i can see the best procedure is to avoid using PropertyValueFactory and trying to stick to lambda expressions (more safe and keep the data type intact using a cellFactory, correct me if i'm wrong).

My question are: What's the best practies for use setCellValueFactory of TableColumn with BigDecimal and Bean? The best way is to create the TableColumns with scenario builder and link them with the controller or create only the TableView, in scenario builder, and create each single TableColumn in the java controller? If i'm using a Bean that contains other Beans, how the TableColumn will represent the information? Which variable will be used for view the information, all of the Bean's variable or only a single one?

MovimentoOverview.fxml

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

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="900.0" prefWidth="1400.0" stylesheets="@DarkTheme.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="it.evil.money.view.MovimentoOverviewController">
   <children>
      <SplitPane dividerPositions="0.12857142857142856" prefHeight="300.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <items>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
               <children>
                  <TreeView layoutX="-9.0" layoutY="14.0" prefHeight="891.0" prefWidth="200.0" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0" />
               </children>
            </AnchorPane>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" styleClass="background">
               <children>
                  <Label layoutX="14.0" layoutY="7.0" styleClass="label-header" text="Person Details" AnchorPane.leftAnchor="5.0" AnchorPane.topAnchor="5.0">
                     <font>
                        <Font size="18.0" />
                     </font></Label>
                  <ToolBar layoutX="216.0" layoutY="258.0" prefHeight="40.0" styleClass="background" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0">
                    <items>
                      <Button mnemonicParsing="false" onAction="#handleNewMovimento" text="New.." />
                        <Button mnemonicParsing="false" onAction="#handleEditMovimento" text="Edit.." />
                        <Button alignment="CENTER_RIGHT" mnemonicParsing="false" onAction="#handleDeleteMovimento" text="Delete.." textAlignment="CENTER" />
                    </items>
                  </ToolBar>
                  <TableView layoutX="5.0" layoutY="55.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="60.0">
                    <columns>
                      <TableColumn fx:id="idColumn" prefWidth="75.0" text="ID" />
                      <TableColumn fx:id="contoColumn" prefWidth="75.0" text="Conto" />
                        <TableColumn fx:id="dataColumn" prefWidth="75.0" text="Data" />
                        <TableColumn fx:id="valutaColumn" prefWidth="75.0" text="Valuta" />
                        <TableColumn fx:id="importoColumn" prefWidth="75.0" text="Importo" />
                        <TableColumn fx:id="quotaTicketColumn" prefWidth="75.0" text="Quota Ticket" />
                        <TableColumn fx:id="causaleColumn" prefWidth="75.0" text="Causale" />
                        <TableColumn fx:id="noteColumn" prefWidth="75.0" text="Note" />
                        <TableColumn fx:id="tipoPagamentoColumn" prefWidth="75.0" text="Tipo Pagamento" />
                        <TableColumn fx:id="tipoMovimentoColumn" prefWidth="75.0" text="Tipo Movimento" />
                        <TableColumn fx:id="spesaInComuneColumn" prefWidth="75.0" text="Spesa in Comune" />
                        <TableColumn fx:id="spesaPerLavoroColumn" prefWidth="75.0" text="Spesa per Lavoro" />
                        <TableColumn fx:id="utenteColumn" prefWidth="75.0" text="Utente" />
                        <TableColumn fx:id="tagColumn" prefWidth="75.0" text="Tag" />
                        <TableColumn fx:id="bustaPagaColumn" prefWidth="75.0" text="Busta Paga" />
                    </columns>
                  </TableView>
               </children>
            </AnchorPane>
        </items>
      </SplitPane>
   </children>
</AnchorPane>

MovimentoOverviewController

package it.evil.money.view;

import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;

import java.math.BigDecimal;
import java.time.LocalDate;

import it.evil.money.MainApp;
import it.evil.money.model.BustaPagaBean;
import it.evil.money.model.CausaleBean;
import it.evil.money.model.ContoBean;
import it.evil.money.model.MovimentoBean;
import it.evil.money.model.TagBean;
import it.evil.money.model.TipoMovimentoBean;
import it.evil.money.model.TipoPagamentoBean;
import it.evil.money.model.UtenteBean;
import it.evil.money.util.DateUtil;

public class MovimentoOverviewController {

    @FXML
    private TableView<MovimentoBean> movimentoTable;
    @FXML
    private TableColumn<MovimentoBean, BigDecimal> idColumn;
    @FXML
    private TableColumn<MovimentoBean, ContoBean> contoColumn;
    @FXML
    private TableColumn<MovimentoBean, LocalDate> dataColumn;
    @FXML
    private TableColumn<MovimentoBean, String> valutaColumn;
    @FXML
    private TableColumn<MovimentoBean, BigDecimal> importoColumn;
    @FXML
    private TableColumn<MovimentoBean, BigDecimal> quotaTicketColumn;
    @FXML
    private TableColumn<MovimentoBean, CausaleBean> causaleColumn;
    @FXML
    private TableColumn<MovimentoBean, String> noteColumn;
    @FXML
    private TableColumn<MovimentoBean, TipoPagamentoBean> tipoPagamentoColumn;
    @FXML
    private TableColumn<MovimentoBean, TipoMovimentoBean> tipoMovimentoColumn;
    @FXML
    private TableColumn<MovimentoBean, Boolean> spesaInComuneColumn;
    @FXML
    private TableColumn<MovimentoBean, Boolean> spesaPerLavoroColumn;
    @FXML
    private TableColumn<MovimentoBean, BustaPagaBean> bustaPagaColumn;
    @FXML
    private TableColumn<MovimentoBean, UtenteBean> utenteColumn;
    @FXML
    private TableColumn<MovimentoBean, TagBean> tagColumn;


    @FXML
    private Label idLabel;
    @FXML
    private Label contoLabel;
    @FXML
    private Label dataLabel;
    @FXML
    private Label valutaLabel;
    @FXML
    private Label importoLabel;

    // Reference to the main application.
    private MainApp mainApp;



    public MovimentoOverviewController() {
    }


    @FXML
    private void initialize() {
        idColumn.setCellValueFactory(cellData -> cellData.getValue().idProperty() );
        contoColumn.setCellValueFactory(cellData -> cellData.getValue().contoProperty() );
        dataColumn.setCellValueFactory(cellData -> cellData.getValue().dataProperty() );
        valutaColumn.setCellValueFactory(cellData -> cellData.getValue().valutaProperty() );
        importoColumn.setCellValueFactory(cellData -> cellData.getValue().importoProperty() );

        quotaTicketColumn.setCellValueFactory(cellData -> cellData.getValue().quotaTicketProperty() );
        causaleColumn.setCellValueFactory(cellData -> cellData.getValue().causaleProperty() );
        noteColumn.setCellValueFactory(cellData -> cellData.getValue().noteProperty() );
        tipoPagamentoColumn.setCellValueFactory(cellData -> cellData.getValue().tipoPagamentoProperty() );
        tipoMovimentoColumn.setCellValueFactory(cellData -> cellData.getValue().tipoMovimentoProperty() );
        spesaInComuneColumn.setCellValueFactory(cellData -> cellData.getValue().spesaInComuneProperty() );
        spesaPerLavoroColumn.setCellValueFactory(cellData -> cellData.getValue().spesaPerLavoroProperty() );
        bustaPagaColumn.setCellValueFactory(cellData -> cellData.getValue().bustaPagaProperty() );
        utenteColumn.setCellValueFactory(cellData -> cellData.getValue().utenteProperty() );
        tagColumn.setCellValueFactory(cellData -> cellData.getValue().tagProperty() );

    }

    public void setMainApp(MainApp mainApp) {
        this.mainApp = mainApp;
        movimentoTable.setItems(mainApp.getMovimentoData());
    }

}

MainApp

package it.evil.money;

import java.io.IOException;

import it.evil.money.dao.DatabaseManager;
import it.evil.money.dao.MovimentoDao;
import it.evil.money.model.*;
import it.evil.money.view.*;
import javafx.application.Application;
import javafx.collections.*;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class MainApp extends Application {

    private Stage primaryStage;
    private BorderPane rootLayout;

    private ObservableList<MovimentoBean> movimentoData = FXCollections.observableArrayList();
    private MovimentoDao movimentoDao;

    public MainApp() {
        movimentoDao = new MovimentoDao(DatabaseManager.getConnection());

        // Instead of use a empty bean...
        // movimentoData.add(new MovimentoBean());

        // I get the data for db
        movimentoData.addAll(this.movimentoDao.getAll());

        this.movimentoDao.distruttore();
    }

    public ObservableList<MovimentoBean> getMovimentoData() {
        return movimentoData;
    }


    @Override
    public void start(Stage primaryStage) {
        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("AddressApp");
        this.primaryStage.getIcons().add(new Image("file:resources/images/address_book_32.png"));

        initRootLayout();

        showMovimentoOverview();
    }

    public void initRootLayout() {
        try {
            // Load root layout from fxml file.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
            rootLayout = (BorderPane) loader.load();

            // Show the scene containing the root layout.
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void showMovimentoOverview() {
        try {
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(MainApp.class.getResource("view/MovimentoOverview.fxml"));
            AnchorPane personOverview = (AnchorPane) loader.load();
            rootLayout.setCenter(personOverview);
            MovimentoOverviewController controller = loader.getController();
            controller.setMainApp(this);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Stage getPrimaryStage() {
        return primaryStage;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

MovimentoBean

package it.evil.money.model;

import java.time.LocalDate;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import java.math.BigDecimal;

public class MovimentoBean {

    private final  ObjectProperty<BigDecimal>        id;
    private final  ObjectProperty<ContoBean>         conto;
    private final  ObjectProperty<LocalDate>         data;
    private final  StringProperty                    valuta;
    private final  ObjectProperty<BigDecimal>        importo;
    private final  ObjectProperty<BigDecimal>        quotaTicket;
    private final  ObjectProperty<CausaleBean>       causale;
    private final  StringProperty                    note;
    private final  ObjectProperty<TipoPagamentoBean> tipoPagamento;
    private final  ObjectProperty<TipoMovimentoBean> tipoMovimento;
    private final  BooleanProperty                   spesaInComune;
    private final  BooleanProperty                   spesaPerLavoro;
    private final  ObjectProperty<BustaPagaBean>     bustaPaga;
    private final  ObjectProperty<UtenteBean>        utente;
    private final  ObjectProperty<TagBean>           tag;

    public MovimentoBean() {
        this(null, null, null, null, null, null, null, null, null, null, false, false, null, null, null);
    }

    public MovimentoBean(BigDecimal id, ContoBean conto, LocalDate data, String valuta, BigDecimal importo, 
            BigDecimal quotaTicket, CausaleBean causale, String note, TipoPagamentoBean tipoPagamento, 
            TipoMovimentoBean tipoMovimento, boolean spesaInComune, boolean spesaPerLavoro, BustaPagaBean bustaPaga, 
            UtenteBean utente, TagBean tag) {

        this.id = new SimpleObjectProperty<BigDecimal>(id);
        this.conto = new SimpleObjectProperty<ContoBean>(conto);
        this.data = new SimpleObjectProperty<LocalDate>(data);
        this.valuta = new SimpleStringProperty(valuta);
        this.importo = new SimpleObjectProperty<BigDecimal>(importo);
        this.quotaTicket = new SimpleObjectProperty<BigDecimal>(quotaTicket);
        this.causale = new SimpleObjectProperty<CausaleBean>(causale);
        this.note = new SimpleStringProperty(note);
        this.tipoPagamento = new SimpleObjectProperty<TipoPagamentoBean>(tipoPagamento);
        this.tipoMovimento = new SimpleObjectProperty<TipoMovimentoBean>(tipoMovimento);
        this.spesaInComune = new SimpleBooleanProperty(spesaInComune);
        this.spesaPerLavoro = new SimpleBooleanProperty(spesaPerLavoro);
        this.bustaPaga = new SimpleObjectProperty<BustaPagaBean>(bustaPaga);
        this.utente = new SimpleObjectProperty<UtenteBean>(utente);
        this.tag = new SimpleObjectProperty<TagBean>(tag);

    }

    public BigDecimal getId(){
        return this.id.get();
    }

    public void setId(BigDecimal id){
        this.id.set(id);
    }

    public ObjectProperty<BigDecimal> idProperty(){
        return id;
    }
......

When i start the program i get this error:

Exception in Application start method
java.lang.reflect.InvocationTargetException
.......
Caused by: java.lang.NullPointerException
    at it.evil.money.view.MovimentoOverviewController.setMainApp(MovimentoOverviewController.java )
    at it.evil.money.MainApp.showMovimentoOverview(MainApp.java )
    at it.evil.money.MainApp.start(MainApp.java )
  • See [this question](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it). If you are still having trouble, please specify the exact line where you get the error (The line number should be shown in the stack trace, and you can use your IDE to find the exact line) – Itai Sep 19 '16 at 08:32
  • Consider adding the `fx:id` attribute to the `TableView` in the fxml... – fabian Sep 19 '16 at 08:47
  • after i modify the declaration of `TableView` into `private TableView movimentoTable = new TableView();` i don't get the nullpointer exception. The error was on the `movimentoTable.setItems(mainApp.getMovimentoData());` line. – evil.security Sep 19 '16 at 08:49
  • Thanks fabian, as you suggested i can either set the `fx:id` attribute to the `TableView` or iniatilize the variable with `new TableView();`. Now i'ts working !!!! – evil.security Sep 19 '16 at 09:04

0 Answers0