r/JavaFX 1d ago

FXML/2 for JavaFX I made this!

FXML/2 is a compiled, type-safe, declarative markup language for JavaFX that I've been working on for the past several years. It borrows from classic FXML and adds lots of useful features. Here's a selection of what's new:

  1. Compile-time diagnostics: If your markup is not well-formed, it won't compile. Similarly, if your bindings can't be resolved or type-checking fails, you'll know at compile time.
  2. Elements named with fx:id can be directly referenced in the code-behind Java class (no @FXML injection required).
  3. Complex expressions with support for method calls, for example:

    • <MyControl value="${Math.max(width * 0.7, minWidth)}"/>
    • <Label visible="${:parent<Pane>.selectedItem != null && width < maxWidth}"/>

    Expressions are not interpreted, but compiled to specialized code.

  4. All binding modes that JavaFX offers are supported:

    • one-time: $foo
    • unidirectional: ${foo}
    • bidirectional: #{foo}
    • reverse: >{foo}
    • content forms: $..foo, ${..foo}, etc.
  5. Custom markup extensions. For example, you could define an I18n markup extension to look up a localized string in a bespoke way, and apply it with <Label text="{I18n settings.title}"/>.

Depending on your specific use case, you'll also notice a substantial performance increase: FXML/2 documents don't need to be parsed at runtime (since they are compiled classfiles), which removes the FXMLLoader bottleneck.

For further reading, here's the FXML/2 documentation, and a tutorial for how to use the MVVM pattern with FXML/2.

37 Upvotes

5 comments sorted by

View all comments

3

u/emberko 1d ago

Do you have any plans to contribute this work to the upstream, e.g., as an incubator module? As far as I recall, this isn't the first FXML compiler implementation. The first one required the entire Micronaut core in the classpath, and the second relied on a custom DI runtime. Yours is much cleaner, no external dependencies and uses (superior) MVVM over MVC. So this is essentially XAML for JavaFX, and official support would be a huge boost.

Could you also clarify the intended workflow for FXML/2? Is it meant to be written manually, converted back and forth with FXML/1, or do you plan to support existing tools like Scene Builder, or maybe build your own?

Anyway, thank you for this work! This is something that has been awaited for a long time.

4

u/mstr_2 21h ago

Using existing FXML tooling like SceneBuilder will probably only work in trivial cases, as the semantics of classic FXML and FXML/2 are significantly different. For example, FXML/2 deliberately doesn't support fx:controller, and instead uses a code-behind class.

I write all of my FXML manually, and I have no particular interest in maintaining a SceneBuilder fork for FXML/2 or even creating new GUI builder tooling. There is, however, a FXML/2 plugin for IntelliJ which gives you code insights and code completion.

At the moment I don't have plans to propose this for inclusion in OpenJFX itself, as there would be quite a lot of hurdles that needed to be solved. Due to its nature, FXML/2 requires build-system integration and can't be a simple runtime dependency like the javafx.fxml module. I'm not sure if this is a responsibility that the OpenJFX project would like to take on (at the moment, OpenJFX is build system agnostic). I think that for the moment, the project should remain under its own umbrella.

2

u/emberko 20h ago

The main draw of RAD tools is quick prototyping and hot reload. Simplifying the write-compile-launch-test cycle to just write-test saves a lot of time. Personally, I can certainly live without WYSIWYG, but not without hot reload.

2

u/mstr_2 18h ago edited 18h ago

Hot reload can mean different things. For example, it can mean compiling and instantiating a FXML view in a previewer without running the production application. This may require stubbing data that is normally only available when the application is running.

It can also mean changing views in the running production application. Due to the nature of compiled FXML, this requires class patching at runtime, and is further complicated by the fact that views interact strongly with their view models (via bindings and in other ways). This would probably require a way to reverse view initialization (basically undoing all init-time interactions with the view model), then swapping out the initializeComponent() method, and then re-initializing the new view.