Skip to content

Using ControlsFX with JDK 9 and above

Abhinay Agarwal edited this page Apr 15, 2020 · 2 revisions

Introduction

JEP 253 made Skin and CSS related APIs public, which resulted in a lot of changes for custom controls which depend on these APIs. Most of the controls in ControlsFX were moved to JDK 9 without issue. However, some of the controls had to depend on ugly hacks to make sure they work as they used to prior to JDK 9. This document talks about these controls and the JVM flags that we need to pass for them to work in the project.

NOTE: This document is not about Jigsaw and considers the reader to have basic knowledge on JPMS.

Understanding exceptions

Let us try to understand the most common exception you will find while using controls from ControslFX by taking an example of GridView control.

If you use GridView in a project, you will get the following exception:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final javafx.scene.control.skin.VirtualFlow javafx.scene.control.skin.VirtualContainerBase.flow accessible: module javafx.controls does not "opens javafx.scene.control.skin" to module org.controlsfx.controls

The exception correctly points that we are accessing a private final field of type VirtualFlow from javafx.scene.control.skin.VirtualContainerBase using reflection. This is done in GridViewSkin:

flow = ReflectionUtils.getVirtualFlow(this);

In JDK 9 and later, in order to access any private field from a class, we need to open its package to the module trying to access it. In our case, package is javafx.scene.control.skin and the module trying to access it is org.controlsfx.controls.

Adding the following as a JVM flag to the project should fix the exception:

--add-opens=javafx.controls/javafx.scene.control.skin=org.controlsfx.controls

Similarly, if you are using ControlsFX in a non-modular project, then the exception would be something similar to:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final javafx.scene.control.skin.VirtualFlow javafx.scene.control.skin.VirtualContainerBase.flow accessible: module javafx.controls does not "opens javafx.scene.control.skin" to unnamed module @0x6ea6fae3

In the exception, module "org.controlsfx.controls" is replaced with "unnamed module @0x6ea6fae3". JDK refers everything on classpath to ALL-UNNAMED module. Therefore, to fix the exception we need to open the package to module "ALL-UNNAMED".

--add-opens=javafx.controls/javafx.scene.control.skin=ALL-UNNAMED

Controls or API

AutoCompletionBinding

--add-exports=javafx.base/com.sun.javafx.event=org.controlsfx.controls

BreadCrumbBar

--add-exports=javafx.graphics/com.sun.javafx.scene=org.controlsfx.controls,
--add-exports=javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls

FilterPanel

--add-opens=javafx.controls/javafx.scene.control.skin=org.controlsfx.controls

GlyphFont

--add-exports=javafx.graphics/com.sun.javafx.css=org.controlsfx.controls

GridView

--add-opens=javafx.controls/javafx.scene.control.skin=org.controlsfx.controls

NotificationPane

--add-exports=javafx.graphics/com.sun.javafx.scene=org.controlsfx.controls,
--add-exports=javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls

TableRowExpanderColumn

--add-opens=javafx.controls/javafx.scene.control.skin=org.controlsfx.controls