xxSkin类中的深度反射失败

时间:2017-07-28 09:06:09

标签: eclipse javafx java-9

自更新9-u175以来,java默认允许非法访问,因此允许所有旧的反射技巧。工作正常,除了涉及control.skin中的类(也许其他人也没有检查) - 要重现,运行下面的示例,单击按钮,看看访问是否成功,直到尝试访问的行ButtonSkin中的私有字段。 stacktrace:

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)

我的上下文:jdk9-u175,带有java9补丁的eclipse-oxygen-R,项目中的访问规则设置为允许javafx / **

问题是:谁是罪魁祸首? FX,Eclipse,ea还是......?

示例:

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());
}

1 个答案:

答案 0 :(得分:8)

为防止意外依赖新API,非法访问仅授予Java 9之前存在的软件包 - 因此我认为com.sun.javafx.scene.control.behavior是新的。

在他的mail with the revised proposal for --illegal-access Mark Reinhold写道(强调我的):

  

--illegal-access=permit

     

此模式打开运行时映像中每个模块中的每个包      所有未命名模块中的代码,即类路径上的代码,如果是,则为      包存在于JDK 8 中。这实现了静态访问,即通过      通过平台编译的字节码和深度反射访问      各种反思API。

     

对任何此类包的第一次反射访问操作会导致a      发出警告,但在此之后没有发出警告。      此单一警告描述了如何启用进一步警告。

     

此模式将是JDK 9的默认模式。它将在a中删除      未来发布。