BeanInfo for JavaFX

We proudly present the new JavaFX BeanInfo API. It’s available now from Maven central and its JavaDoc can be found here.

You can use this library to create a FXBeanInfo in order to provide information about properties and actions your JavaFX Bean offers.

Motivation

When I started developing with JavaFX I was surprised that there was no equivalent to the Java Beans BeanInfo class. BeanInfo classes allow tools and frameworks to get information about a Java object. This would for example come really handy when trying to set up bindings between a JavaFX Bean and a view based on FXML. However there is no standardized API for doing so. The JavaFX developers built their own system on annotations and (lots of) reflection and kept it implementation private. That’s not only slow and error prone, but also horrible to re-implement.

So when we decided to make embedding DukeScript in JavaFX simpler, we wanted to do it differently.

How it works

If you want to expose the properties and actions of your JavaFX Bean, you can implement FXBeanInfo.Provider, a single method interface. Here’s an example:

class HTMLController implements FXBeanInfo.Provider {

    private final StringProperty labelText = new SimpleStringProperty(this, "labelText", "");
    
    private final FXBeanInfo info = FXBeanInfo
            .newBuilder(this)
            .property(labelText)
            .build();
    
    @Override
    public FXBeanInfo getFXBeanInfo() {
        return info;
    }

}

FXBeanInfo supports the builder pattern for easily creating the FXBeanInfo using the actual properties of your bean. You’re not required to write getters and setters for your properties, since they can be accessed using the FXBeanInfo.

The consumer of the FXBeanInfo can simply call the method getProperties in order to get a Map of the available properties. It’s a map instead of a Set or List, so you can also easily access a property by its name.

It’s easy to see how using this could also improve the way the FXMLLoader currently works. Instead of scanning the controller via reflection for getters and setters of a bound Property, the loader could simply access the Property via the FXBeanInfo map. No reflection required at all - clean, fast and standardized access to all exposed properties.

Actions

Plain vanilla JavaFX uses the @FXML-Annotation to mark Functions that can be called from FXML. When a FXML file is loaded, the FXMLLoader scans the controller for this Annotation and routes Button clicks and similar events to the marked method. That’s slightly better than the purely reflection based guesswork when binding properties, but also not ideal.

With FXBeanInfo you can register actions in the same way as simple properties. This is how:

class HTMLController implements FXBeanInfo.Provider {

    private final StringProperty labelText = new SimpleStringProperty(this, "labelText", "");
    private final Property<EventHandler<ActionEvent>> action =
            new SimpleObjectProperty<EventHandler<ActionEvent>>(
                    this, "action",
                    (e) -> labelText.set("Hello World!"));
    
    private final FXBeanInfo info = FXBeanInfo
            .newBuilder(this)
            .action(action)
            .property(labelText)
            .build();
    
    @Override
    public FXBeanInfo getFXBeanInfo() {
        return info;
    }

}

That is really convenient. By wrapping the EventHandler in a Property we can use the exact same mechanism as for “plain” properties. FXBeanInfo has a method getActions which allows you to retrieve a Map of all Actions and access them by name.

Due to new regulations, I don’t dare to insert a meme here. So use your own imagination and depict Kermit the frog sipping on a cup of Lipton tea saying: “Using this would probably simplify the code for binding to FXML a lot, …but that’s none of my business.

What we use it for

We thought, we’d share this library with the JavaFX community; so if you think it could help your project feel free to use it. It is general enough to become a common ground for obtaining meta information about any JavaFX bean.

DukeScript uses the FXBeanInfo to make it easier for JavaFX developers to use HTML just like they use FXML:

WebView webview = new WebView();
FXBrowsers.load(webview, MainApp.class.getResource("/html/view.html"), () -> {
    HTMLController ui = new HTMLController();
    Models.applyBindings(ui);
});

This is the HTML for it:

<html>
   <body>
        <div class="flex-container">
            <div class="row"> 
                <div class="flex-item"><span data-bind="text: labelText"></span></div>
                <div class="flex-item"><button data-bind="click: action">Click me!</button></div>
            </div>
        </div>
    </body>
</html>

The data-bind attributes are used to bind the UI to the JavaFX properties and actions. DukeScript users know this syntax already. If you’re new to it, they are described here.

Use JavaFX properties and actions to control behavior inside of your own WebView in Java. No more JavaScript. JavaFX everywhere!

Use it

You’re free to use this library on it’s own, in order to provide a BeanInfo in your own framework, or as we use it, in conjunction with DukeScript. The project on github contains two demo projects. One for embedding a HTML UI in a JavaFX application, and one for using only an HTML UI with JavaFX properties.