Deep Reflection in xxSkin Classes

Starting with update 9-u175, java allows illegal access by default, thereby allowing you to use all the old tricks. It works fine, except when it comes to classes in control.skin (others may not have been tested as well) - to play, run the example below, click the button and see how the access succeeds while the line trying to access the private field in ButtonSkin. Stack:

Exception in thread "JavaFX Application Thread" java.lang.reflect.InaccessibleObjectException: Unable to make field private final com.sun.javafx.scene.control.behavior.BehaviorBase javafx.scene.control.skin.ButtonSkin.behavior accessible: module javafx.controls does not "opens javafx.scene.control.skin" to unnamed module @537fb2 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281) at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:176) at java.base/java.lang.reflect.Field.setAccessible(Field.java:170) 

My context: jdk9-u175, eclipse-oxygen-R with a patch for java9, access rules in the project are set to allow javafx / **

Question: who is the criminal? FX, Eclipse, ea or ..?

Example:

 import java.lang.reflect.Field; import java.util.logging.Logger; import javafx.application.Application; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.SkinBase; import javafx.scene.control.skin.ButtonSkin; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; import com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler; public class AccessFieldFX extends Application { private Parent getContent() { Button button = new Button("something to click on"); // okay Object def = invokeGetFieldValue(Button.class, button, "defaultButton"); button.setOnAction(e -> { ButtonSkin skin = (ButtonSkin) button.getSkin(); // okay LambdaMultiplePropertyChangeListenerHandler cl = (LambdaMultiplePropertyChangeListenerHandler) invokeGetFieldValue(SkinBase.class, skin, "lambdaChangeListenerHandler"); // okay Object clField = invokeGetFieldValue(LambdaMultiplePropertyChangeListenerHandler.class, cl, "EMPTY_CONSUMER"); // failure Object beh = invokeGetFieldValue(ButtonSkin.class, skin, "behavior"); }); BorderPane pane = new BorderPane(button); return pane; } @Override public void start(Stage primaryStage) throws Exception { primaryStage.setScene(new Scene(getContent(), 600, 400)); // primaryStage.setTitle(FXUtils.version()); primaryStage.show(); } public static Object invokeGetFieldValue(Class declaringClass, Object target, String name) { try { Field field = declaringClass.getDeclaredField(name); field.setAccessible(true); return field.get(target); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } return null; } public static void main(String[] args) { launch(args); } @SuppressWarnings("unused") private static final Logger LOG = Logger .getLogger(AccessFieldFX.class.getName()); } 
+7
eclipse javafx java-9
source share
1 answer

To avoid accidental dependencies on the new APIs, illegal access is granted only to packages that existed before Java 9, so I assume that com.sun.javafx.scene.control.behavior is new.

In his email with the revised proposal for --illegal-access Mark Reinhold writes (my attention):

--illegal-access=permit

This mode opens every package in each module at runtime for code in all unnamed modules, i.e. the code in the class path , if this package exists in JDK 8 . This provides both static access, i.e. compiled bytecode and deep reflective access through the platform various mapping APIs.

The first operation of reflective access to any such packet causes a warning, which should be issued, but after that no warnings are issued. This one warning describes how to enable additional warnings.

This mode will be used by default for JDK 9. It will be removed in a future release.

+8
source share

All Articles