Глубокое отражение не удается в классах xxSkin

начиная с обновления 9-u175, java разрешает незаконный доступ по умолчанию, позволяя все старые трюки отражения. Работает отлично, за исключением тех случаев, когда речь идет о классах контроля.скин (возможно, и другие тоже не проверяли) - чтобы воспроизвести, запустите пример ниже, Нажмите кнопку и посмотрите, как доступ преуспевает до строки, которая пытается получить доступ к частному полю в ButtonSkin. Трассировки стека:

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, eclipse-oxygen-R с патчем для java9, правила доступа в проекте установлены для разрешения javafx/**

вопрос в том, кто виноват? FX, Eclipse, советник или ..?

пример:

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 ответов


чтобы предотвратить случайные зависимости от новых API, незаконный доступ предоставляется только пакетам, которые существовали до Java 9-я, следовательно, предполагаю com.sun.javafx.scene.control.behavior новая.

в своем почта с пересмотренным предложением для --illegal-access Марк Рейнхольд пишет (выделено мной):

--illegal-access=permit

этот режим открывает каждый пакет в каждом модуле в образ среды выполнения для код во всех неназванных модулях, т. е. код на пути к классу,если что пакет существовал в JDK 8. Это позволяет как статический доступ, т. е. скомпилированный байт-код и глубокий отражающий доступ через платформу различные API отражения.

первая операция отражающего доступа к любому такому пакету вызывает предупреждение должно быть выдано, но после этого предупреждения не выдается. Это единственное предупреждение описывает, как включить дополнительные предупреждения.

этот режим будет по умолчанию для JDK 9. будет удален в будущий релиз.