javafx 8 compatibility issues – FXML static fields or methods

It sounds like you are trying to inject a TextField into a static field. Something like

@FXML
private static TextField myTextField ;

This apparently worked in JavaFX 2.2. It doesn’t work in JavaFX 8. Since no official documentation ever supported this use, it’s doesn’t really violate backward compatibility, though in fairness the documentation on exactly what the FXMLLoader does is pretty woeful.

It doesn’t really make much sense to make @FXML-injected fields static. When you load an FXML file, it creates new objects for each of the elements in the FXML file. A new controller instance is associated with each call to FXMLLoader.load(...) and the fields in that controller instance are injected with the corresponding objects created for the FXML elements. So the injected fields are necessarily specific to the controller instance. If you had a static injected fields in the controller, and you loaded the same FXML file twice and displayed it twice in the UI, then you would have no way of referencing both sets of controls.


@FXML marked static methods referenced from FXML also will not work.

For instance, with:

@FXML
private static void changeUser(ActionEvent e) {
    // System.out.println("test");
}

And:

<Button text="Change User" onAction="#changeUser"/>

This will fail with:

javafx.fxml.LoadException: Error resolving onAction='#changeUser', either the event handler is not in the Namespace or there is an error in the script.

To fix this, just remove the static modifier from the method specifcation.


Update: Response to question in comments

In particular, don’t use static fields just to enable them to be accessible from outside the class. A static field has a single value belonging to the class, instead of a value for each instance of the class, and the decision to make fields static should only be made if that makes sense. In other words, static defines scope, not accessibility. To allow access to instance data, you just have to have a reference to the instance. The FXMLLoader has a getController() method that allows you to retrieve a reference to the controller.

A related point: it’s also not a good idea to expose the UI controls from the controller. You should instead expose the data. For example, instead of defining a getTextField() method in the controller, instead define a textProperty() method that returns a StringProperty representing the contents of the TextField. The reason for this is that when your boss comes to the office and tells you he wants the TextField to be replaced by a TextArea, or a ComboBox<String>, or some other control, then it’s going to be a lot harder if classes outside of the controller are using your TextField. The structure of the data represented by your controller is much less likely to change than the implementation of how that data is presented to the user.

For some examples

Leave a Comment