Search code examples
javajavafxfxmlaccess-modifiers

Access modifiers in JavaFx and @FXML


I am new to JavaFx and in a few tutorials I've seen, there were some differences. In one of the tutorials, he always used private as the access modifier in the controller class and wrote it this way:

@FXML private Button button;

But the other tutorial always used public and didn't include @FXML in the controller class. Both of these seem to work fine but is there an actual difference between them that I should know?


Solution

  • From Introduction to FXML:

    @FXML

    Note that, in the previous examples, the controller member fields and event handler methods were declared as public so they can be set or invoked by the loader. In practice, this is not often an issue, since a controller is generally only visible to the FXML loader that creates it. However, for developers who prefer more restricted visibility for controller fields or handler methods, the javafx.fxml.FXML annotation can be used. This annotation marks a protected or private class member as accessible to FXML. If the class being annotated is in a named module, the module containing that class must open the containing package to at least the javafx.fxml module.

    In other words, the @FXML annotation is only required if the field or method is non-public (i.e. is protected, package-private, or private) yet needs to be accessible to FXML. Within the context of FXML, there is no difference between a public field/method with no (or even with an) @FXML annotation and a non-public field/method with said annotation. The only difference in general is the visibility of the field/method to other code.

    That said, it's typically considered good practice to only make something as visible as it needs to be. An FXML-injected field normally has no reason to be public. Neither do event-handler methods nor does the initialize method1. They're all implementation details.

    Note the @FXML annotation doesn't do anything special on a language level. The presence of the annotation simply tells the FXMLLoader it's okay to try and reflectively access the field or method even though it's not public. It's also a good hint to the developer that the field or method is handled by FXML (for instance, FXML-injected fields should virtually never be manually initialized or reassigned).


    1. The no-argument initialize() method. Not the one you have to override when implementing Initializable, which of course must be public. Note it's recommended to use the no-argument method instead of implementing that interface, injecting the location and resource bundle the same as other FXML-injected fields if needed. Why the interface hasn't been deprecated yet, I don't know.