0
public class AccountOverviewController {

//declarations ...

@FXML
private Button undoButton;

@FXML
private Button redoButton;

@FXML
private void initialize() {
    transactionsTable.getSelectionModel().setSelectionMode(
            SelectionMode.MULTIPLE);

    dateColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getDateProperty());
    payeeColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getPayeeProperty());
    categoryColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getCategoryProperty());
    inflowColumn.setCellValueFactory(dataValue -> dataValue.getValue()
            .getInflowProperty());

    deleteButton.disableProperty().bind(Bindings.isEmpty(transactionsTable.getSelectionModel().getSelectedItems()));

    editButton.disableProperty().bind(Bindings.size(transactionsTable.getSelectionModel().getSelectedItems()).isNotEqualTo(1));

    undoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getCommandStack()));
    redoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getUndoCommandStack()));
}

//handlers&setters ...
}

These two lines at the end are causing error. I want to disable buttons when the commands stacks are empty. I don't know why. For example same button disabling for Delete/Edit button works fine. Whole application without these two works perfectly fine.

Exception chain:

javafx.fxml.LoadException: 
/home/simon/eclipse/java-neon-workspace/to2/lab2/cw3/bin/pl/edu/agh/iisg/to/javafx/cw3/view/AccountOverviewPane.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2571)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at pl.edu.agh.iisg.to.javafx.cw3.presenter.AccountPresenter.initRootLayout(AccountPresenter.java:35)
    at pl.edu.agh.iisg.to.javafx.cw3.Main.start(Main.java:20)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$106(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$119(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$117(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$118(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$450(GtkApplication.java:139)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2566)
    ... 13 more
Caused by: java.lang.NullPointerException
    at pl.edu.agh.iisg.to.javafx.cw3.view.AccountOverviewController.initialize(AccountOverviewController.java:97)
    ... 23 more

Both of stacks are declared like this in CommandRegistry class

private ObservableList<Command> commandStack = FXCollections.observableArrayList();

and getters are returning themselves naturally. What could possibly go wrong here?

ssukienn
  • 558
  • 6
  • 22
  • Could you please add the full code for `AccountOverviewController`? Your trace says `NullPointerException`, are you sure `commandRegistry` is initialized? – beatngu13 Oct 21 '16 at 21:38
  • So which line is line 97? – James_D Oct 21 '16 at 21:59
  • In this particular example it is this with `undoButoon.disablePrope...`. But everyone of them cause same exception chain. Here is whole [project](https://github.com/Sukiennik/JavaFX-Projects/tree/master/pl/edu/agh/iisg/to/javafx/cw3) and here [AccountOverviewController](http://pastebin.com/cvGRY5z5) – ssukienn Oct 21 '16 at 22:00
  • So presumably `undoButton` is null? – James_D Oct 21 '16 at 22:25
  • It seems like you're accessing `commandRegistry` without initializing it. – beatngu13 Oct 21 '16 at 23:37
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – fabian Oct 22 '16 at 10:12
  • @beatngu13 But it is initialized inside `AccountPresenter` class as class variable (then when class is launched). This class is instantiated in `start()` method before using `commandRegistry`. – ssukienn Oct 22 '16 at 12:11
  • That doesn't necessarily mean that `AccountOverviewController` has that (or another) instance, too. As I said before, you have to include the full sources of that class. Otherwise it's hard to tell what exactly went wrong. – beatngu13 Oct 22 '16 at 12:55
  • @beatngu13 I gave link to github project above. I'm seriously unable to find the problem here. – ssukienn Oct 22 '16 at 13:09
  • My bad, didn't see that. – beatngu13 Oct 22 '16 at 13:12

1 Answers1

1

After looking at your project, especially AccountOverviewController and AccountPresenter, I'd say you get that NullPointerException because the controller tries to access commandRegistry within initialize() before the class has an instance of CommandRegistry.

Have a look at lines 38 – 41 of AccountPresenter:

AccountOverviewController controller = loader.getController();
controller.setPresenter(this);
controller.setData(DataGenerator.generateAccountData());
controller.setCommandRegistry(commandRegistry);

You create your controller and set commandRegistry afterwards. But initialize() is invoked directely after calling the constructor of AccountOverviewController (check out this question for details). At this time, commandRegistry is null.

One way to fix this is by moving the bindings into the setter:

public void setCommandRegistry(CommandRegistry commandRegistry) {
    this.commandRegistry = commandRegistry;

    undoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getCommandStack()));
    redoButton.disableProperty().bind(Bindings.isEmpty(commandRegistry.getUndoCommandStack()));

    commandLogView.setItems(commandRegistry.getCommandStack());
    commandLogView.setCellFactory(lv -> new ListCell<Command>() {
        protected void updateItem(Command item, boolean empty) {
            super.updateItem(item, empty);
            setText((item != null && !empty) ? item.getName() : null);
        };
    });
}
Community
  • 1
  • 1
beatngu13
  • 7,201
  • 6
  • 37
  • 66
  • Thank you, I understand it now. How then bindings work on `transactionsTable` if it also isn't initialized during calling controller yet. For example `editButton` or `deleteButton`. – ssukienn Oct 22 '16 at 13:36
  • 1
    @Saris Because all dependencies are already there. `editButton` and `deleteButton` need `transactionTable`. All of these fields are annotated with `@FXML`, which is invoked before. All you have to remeber is this execution order: 1. Constructor, 2. `@FXML`, 3. `initialize()`. – beatngu13 Oct 22 '16 at 13:42
  • Thank you for your help and patience. – ssukienn Oct 22 '16 at 13:47