Search code examples
javafxcode-generationfxml

Can I automatically generate controller classes from FXML?


As I understand it, when using FXML to describe a Java FX scene, the controller class is written manually and it's member variables and methods can then be referenced from the .fxml file. When loading the scene using the FXMLLoader, member variables are set to the corresponding scene elements and methods are wired up to the corresponding events automatically. This works but is very cumbersome as changes need to be done in two places and any mistakes will only show up at runtime.

I've seen other GUI frameworks that allow you to instead generate the controller from a scene description as an abstract class which needs to be implemented to access the scene elements and handle the events. An example of what I mean:

I would create the following .fxml file (e.g. using the JavaFX Scene Builder):

<AnchorPane ... >
  <children>
     <Button fx:id="button" ... text="Button" onAction="#buttonPressed" />
  </children>
</AnchorPane>

Somewhere in my build process, the following .java file would be created (e.g. using a Maven plugin):

abstract class TestController {
    protected final Parent root;
    protected final Button button;

    {
        // Load test.fxml file
        // Assign scene elements to root and button
        // Attach event handler to the button that calls buttonClicked()
    }

    protected abstract void buttonClicked(ActionEvent event);
}

I could then, possibly multiple times, create a concrete implementation of that controller:

final class TestControllerImpl extends TestController {
    TestControllerImpl(String buttonLabel) {
        button.setText(buttonLabel);
    }

    @Override
    protected void buttonClicked(ActionEvent event) {
        button.setText("I've been clicked! What a great day!");
    }
}

Is there a project with the goal to do this? Or is there a problem with this approach applied to FXML?

I see the following benefits from this approach:

  • Declarations for member variables and methods for the controller are automatically generated.
  • All member variables are final and protected instead of non-final and either public or annotated.
  • The same for methods, they are protected instead of either public or annotated.
  • Not implementing a method or misspelling it's name will lead to a compiler error.
  • Programmatic setup of the scene can be done in the constructor instead of an initialize() method because the constructor will run after the scene has been loaded and its elements assigned to the member variables.

Solution

  • Update Nov 2020

    This answer is now outdated.

    As various more recent answers have pointed out, there are now a variety of additional different tools available for automatically generating FXML controller classes from FXML documents. Many of these are targeted as extensions, features or plugins to existing development tools, such as SceneBuilder, Idea, Eclipse or NetBeans.

    I suggest that interested readers review both this answer and other answers to this question, then look at their individual use-case and toolset chain and choose the solution which is most appropriate for them from the available choices.


    There is nothing I know that does exactly what you propose in your question.

    Likely this answer will probably end up pretty outdated over time.

    Alternate Technologies

    JRuby achieves most of your outlined benefits using a slightly different approach - it uses jRuby's dynamic programming magic to automatically create Ruby class members from the FXML dynamically a runtime.

    Tom Schindl wrote a tool which generates Java code from FXML. Of the approaches listed in this answer, Tom's tool seems closest to your question.

    SceneBuilder Skeletons

    A similar Java code generator from FXML is available in SceneBuilder View | Show Sample Controller Skeleton feature, which is described in this blog post. When I use SceneBuilder, I use this feature all the time and try to keep my controllers really light so they are almost all auto generated code from the SceneBuilder skeleton feature.

    It is slightly annoying though because it doesn't achieve a clean separation of generated code from hand written code, so you need to be careful when you do updates to the FXML and want to generate a new skeleton and copy and paste it over parts of your existing Controller (plus that is a slightly error prone manual operation that takes a little bit of developer time).

    Source code for SceneBuilder is available if you want to see how it works.

    Potential Build Tool Plugins

    Such a code generation feature might make a worthwhile addition to some of the existing build tools in the JavaFX ecosystem, such as the JavaFX Maven plugin or JavaFX Gradle plugin (or a separate plugin in it's own right).

    Future Development

    I believe that Oracle are also working on a feature extension for FXML for a future JavaFX release (post Java 8) which compiles FXML directly to Java byte code (class files), bypassing the Java source code step. This kind of feature would probably achieve most of your outlined benefits.