This issue has already been reported at the JFoenix's issue tracker:
For starters, JFoenix is not really ready for Java 11+. The released version is intended for Java 9, but it still works with Java 11 and JavaFX 11, providing you add the JavaFX dependencies.
However, under JDK 12 it fails to run, and the issue is not JavaFX related: even with JavaFX 11.0.2 it still fails.
The issue is related to the use of reflection to access the Text
node of TextFieldSkin
:
textNode = ReflectionHelper.getFieldContent(TextFieldSkin.class, this, "textNode");
java.lang.IllegalAccessException: class com.jfoenix.adapters.ReflectionHelper (in module com.jfoenix) cannot access a member of class javafx.scene.control.skin.TextFieldSkin (in module javafx.controls) with modifiers "private"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:355)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:639)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
at java.base/java.lang.reflect.Field.get(Field.java:416)
at com.jfoenix/com.jfoenix.adapters.ReflectionHelper.getFieldContent(ReflectionHelper.java:98)
at com.jfoenix/com.jfoenix.skins.JFXTextFieldSkin.<init>(JFXTextFieldSkin.java:59)
While this worked fine up until Java 11.0.2, with Java 12 a regression recent changes in unsafe
prevents this from working, and causes textNode = null
.
As @AlanBateman mentions in his comments below:
[The JFoenix maintainers] should replace their setAccessible
method to call obj.setAccessible(true)
so that the user gets the right exceptions when the library tries to hack internals that are not accessible to it. If you do that then the user can workaround those issues with --add-exports
or --add-opens
options until the maintainers of the library fix their issues.
For now this will mean sticking to JDK 11.
Alternatively, you could try to build your own JFoenix version, cloning the repo (branch 9.0.0) and making the necessary changes to make it work with JavaFX 11+ (out of scope of this answer...), and removing the use of reflection where possible.
For instance, the textNode
can be directly retrieved with:
textNode = textPane.getChildren().get(1);
or, still rely on reflection, but with the proper changes mentioned:
try {
Field field = cls.getDeclaredField(fieldName);
field.setAccessible(true); // <-- Use this.
return (T) field.get(obj);
} catch (Throwable ex) { }
combined with:
--add-exports=javafx.controls/javafx.scene.control.skin=$moduleName