FX Experience Has Gone Read-Only

I've been maintaining FX Experience for a really long time now, and I love hearing from people who enjoy my weekly links roundup. One thing I've noticed recently is that maintaining two sites (FX Experience and JonathanGiles.net) takes more time than ideal, and splits the audience up. Therefore, FX Experience will become read-only for new blog posts, but weekly posts will continue to be published on JonathanGiles.net. If you follow @FXExperience on Twitter, I suggest you also follow @JonathanGiles. This is not the end - just a consolidation of my online presence to make my life a little easier!

tl;dr: Follow me on Twitter and check for the latest news on JonathanGiles.net.

JavaFX 2.0 shipped with a declarative XML-based language for defining user interfaces, called FXML. FXML is a key part of our strategy around making it easier to create user interfaces in Java. Certainly having a markup language has been attractive to web developers since it is a familiar and comfortable way to approach describing a user interface. But there are other key strategic reasons why FXML is important, how it fits into the broader JavaFX ecosystem, and how it helps you write testable user interfaces with minimal fuss. In essence, FXML helps you follow best practices while also making your life easier.

Quick Introduction

FXML is an XML-based language for describing UIs. This has become quite commonplace in the industry. Swing had several variants which did just this (including JDNC). Flex came with MXML and .NET and Silverlight came with XAML. And then of course the web has always had a non-XML based HTML markup and XML-based XHTML markup, as well as SVG and many other variants. So we’re not exactly treading new ground here, which is one of the great advantages to FXML. Whereas JavaFX 1.X forced everybody to learn a new language and new tools, with JavaFX 2.0 we explicitly decided to return to familiar languages and familiar tools.

FXML doesn’t have a schema. It does have some basic predefined structure, but what you can express in FXML and how it applies to constructing object graphs depends on the API of the objects you are trying to construct. It isn’t only for constructing UI graphs, you can also construct Services or Tasks or domain objects or whatnot. Heck, you can even use JavaScript or other scripting languages in FXML. However, from a Model-View-Controller perspective, FXML works best when simply representing the view in some declarative manner and you let your Java code (or other JVM language) handle the model and controller parts of the pattern.

Tools

FXML is a key part of our tooling strategy. One of the major drawbacks to Java RAD tools has been that they create (and sometimes) parse arbitrary Java code and then try to represent this in the GUI editor view. This proved to be so difficult, that nearly every Java RAD tool instead opted for a tool-specific XML file to describe the UI, and then do one-way code generation. The problem with this approach is that the only tool-independent representation of the UI is in Java code, so when you use one GUI builder you are essentially locked into using it, or having to write custom converters to convert from one tool to another. Needless to say, in a large team where people want to use different IDEs this puts up significant barriers to RAD tool adoption.

With JavaFX 2.0 and the introduction of FXML, we’re defining a standard interchange format which can be used by every RAD tool. Even better, it isn’t just a tooling format, but is also easy to read / write by hand. We’re working hard with our Scene Builder tool to make sure it produces clean FXML — the kind you would have done by hand had you decided to do so. This strategy is of course not new, both MXML and XAML are used in the same manner.

Because FXML doesn’t have a schema of its own, we anticipate IDEs will add specific FXML editor support such that you will get code completion and so forth when editing FXML by hand. As for myself, I hope to always use a RAD tool ๐Ÿ˜‰

Design Patterns

The terminology used with FXML is that of MVC. The idea being that the View is the FXML file itself, and should only really have a description of the user interface. The Controller is some Java class (optionally implementing Initializable) which is then declared in the FXML file as the controller for that FXML file. The Model is just some domain objects you have, probably defined on the Java side, that you then need to wire up to the view via the controller. It would look something like this:

Sample.FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlapp.Sample">
    <children>
        <TextField fx:id="firstNameField" onAction="#submit" />
        <Label fx:id="messageLabel" />
    </children>
</VBox>

Person.java

package fxmlapp;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
    private StringProperty firstName = new SimpleStringProperty(this, "firstName", "");
    public final String getFirstName() { return firstName.get(); }
    public final void setFirstName(String value) { firstName.set(value); }
    public final StringProperty firstNameProperty() { return firstName; }
}

Sample.java

package fxmlapp;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

public class Sample implements Initializable {
    
    private Person person = new Person();
    
    @FXML
    private TextField firstNameField;
    
    @FXML
    private Label messageLabel;
    
    @FXML
    private void submit(ActionEvent event) {
        messageLabel.setText(person.getFirstName());
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        firstNameField.textProperty().bindBidirectional(person.firstNameProperty());
    }    
}

In this example, the FXML document contains a TextField and Label. When the “enter” key is pressed while the TextField has focus, it will invoke the “submit” method on the controller. The controller, meanwhile, is going to update the label whenever the text is submitted.

One thing that is kind of awkward though is that all my binding is being done in Java code. The Controller facilities interaction between the View and Model, and therefore in the initialize method of the controller, you specify how to wire things up. The problem with this is that the RAD tools shouldn’t be generating Java code (or we’re back to the same troubles as with previous Java RAD tools), but should only use the FXML document. So that means your RAD tool won’t be able to do any binding for you.

I could turn things around a little bit and move the binding into the FXML document. This would allow tools to handle data binding in addition to layout. Note that the following code does not work today because bidirectional bindings are not supported in FXML, but we are working on fixing that.

Sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import fxmlapp.Model ?>

<VBox fx:id="root" xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlapp.Sample">
    <fx:define>
        <Model fx:id="model" />
    </fx:define>
    <children>
        <TextField fx:id="firstNameField" text="${model.person.firstName}" />
        <Label fx:id="messageLabel" text="${model.person.firstName}" />
    </children>
</VBox>

Model.java

package fxmlapp;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

public class Model {
    private ObjectProperty<Person> person = new SimpleObjectProperty<Person>(this, "person");
    public final Person getPerson() { return person.get(); }
    public final void setPerson(Person value) { person.set(value); }
    public final ObjectProperty<Person> personProperty() { return person; }
}

Sample.java

package fxmlapp;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;

public class Sample implements Initializable {

    @FXML private Model model;
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        model.setPerson(new Person());
    }    
}

Here the FXML document defines a local “Model” variable, to which it binds. The Model is nothing more than a class which then has a “Person” object on it, though it could have other state. In the Controller I then get the Model defined in the FXML document and give it the Person object it should operate on. The benefit here is that the controller no longer has any references to the GUI elements defined in the FXML document. This means it would be much easier for tooling support (no modification of the Java code). There is also an elegance to the fact that the State exists independently of the View, and the View just binds to the State.

As I mentioned above, this code does not work today because we don’t have bidirectional binding support in the FXML language, although that is high on the priority list since it would enable patterns like this to exist.

Unfortunately this fully MVC pattern is more verbose than necessary, because there are actually two different models. We have the “Person” object which is actually the domain data model, and then we have the “Model” class which is acting as a carrier — it is the way we declare in the FXML that some domain data will be declared in this “Model” so we can bind to it, but it isn’t actually adding value in and of itself. That is, it is an accidental creation in order to make the system happy, not some essential element in your application. Lets get rid of this boilerplate. Beside MVC there is another great pattern known as the Presentation Model.

The Presentation Model is another Smalltalk pattern for describing how to build a UI. From effective engineers I know who have used it in practice, the Presentation Model has significant advantages such as making testing easier. You really ought to go read a bit about it. The essence is very simple: there is a presentation (view), and a presentation model (view model). There is also a data model, it is true, but that becomes exposed to the view via the presentation model. In our terminology, the presentation is the FXML document, and the presentation model is an associated controller.

With this pattern, all the binding logic lives in the FXML document, while all the model data lives in the presentation model. One of the wonderful side effects of this pattern is that I no longer need to have @FXML annotated fields representing the different UI elements, or even have any @FXML annotated fields at all. This simplifies the Controller code, but also makes it easier to maintain because if I add new elements or remove elements or change the ids of the elements or whatnot, I don’t have to change the code. And remember that the RAD tool want’s to touch as little code as possible, so removing this tight coupling between sources and FXML is a big plus. In addition, everything is just easier to understand. And the Controller now takes on a significantly simpler and more powerful role.

Sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox fx:id="root" xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlapp.Sample">
    <children>
        <TextField fx:id="firstNameField" text="${controller.person.firstName}" />
        <Label fx:id="messageLabel" text="${controller.person.firstName}"/>
    </children>
</VBox>

Sample.java

package fxmlapp;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

public class Sample {
    private ObjectProperty<Person> person = new SimpleObjectProperty<Person>(this, "person");
    public final Person getPerson() { return person.get(); }
    public final void setPerson(Person value) { person.set(value); }
    public final ObjectProperty<Person> personProperty() { return person; }
}

As you can see, this is almost exactly like the previous version except now the model state is in the Sample PresentationModel/Controller rather than in the Model class or FXML document, and the FXML document no longer defines its own model variables, but just binds straight through the controller. This example is a proposal, it won’t work today. We are thinking about adding support for this in an upcoming update release. In particular, in addition to needing to add FXML language support for bidirectional binding, we also need to add support for an implicit “controller” variable.

The real power of the PresentationModel is that it gives you, the Java developer, the ability to do all the custom things you typically need to do in real world applications. Perhaps the data model comes to use as a single phone number and you need to split it into area code, high numbers, low numbers (555-223-2333 for example) for your UI. In this case, you write some code in the PresentationModel which does this, presenting three simple and straightforward properties that your UI will bidirectionally bind to. Or perhaps you are presenting a form, and you want people to enter items in the form and auto-validate the entire form together, but you don’t want to update the domain objects until the user “submits” the form. In such a case, you can take the domain object and have properties in the PresentationModel represent each individual field, essentially buffering changes from being put back into the domain object until the submit method is called. For example:

Sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<FlowPane fx:id="root" xmlns:fx="http://javafx.com/fxml" fx:controller="fxmlapp.Sample">
    <children>
        <TextField fx:id="firstNameField" text="${controller.areaCode}" />
        <TextField fx:id="firstNameField" text="${controller.highDigits}" />
        <TextField fx:id="firstNameField" text="${controller.lowDigits}" />
    </children>
</FlowPane>

Sample.java

package fxmlapp;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

public class Sample {
    public final StringProperty areaCode = new SimpleStringProperty("this", "areaCode", "");
    public final StringProperty highDigits = new SimpleStringProperty("this", "highDigits", "");
    public final StringProperty lowDigits = new SimpleStringProperty("this", "lowDigits", "");

    public void setPhoneNumber(String number) {
        // Of form xxx-xxx-xxxx
        final parts = number.split("-");
        areaCode.set(parts[0]);
        highDigits.set(parts[1]);
        lowDigits.set(parts[2]);
    }
}

(I used a public final property instead of getters and setters because, I’m lazy ;-). Since this part of the post is about futures, I figured, what the heck).

There are other ways this could be further simplified, if there were binding containers and auto-buffering properties and the like. But the key point here is that the Presentation Model pattern lets you do all this application specific manipulation of state in Java code, by the developer, while the designer is free to modify what the UI looks like or what fields are exposed via the FXML.

This much more interesting because the Presentation Model is also fully testable. You can easily write unit tests for the Presentation Model, to test that buffering is working as expected, validation is working as expected, loading of domain objects works as expected, and so forth. And all this done irrespective of what the actual UI looks like!

Now of course, we want to make all this tool-able. So in a RAD tool you can load up the controller (presentation model) for an FXML document and then bind things directly in the tool. It will introspect and find all the properties exposed on the PM and offer these as bind targets and make this all nice and easy. Those are my thoughts on it. What are yours?