2017-07-28 43 views
7

自更新9-u175以來,java默認允許非法訪問,因此允許所有舊的反射技巧。工作正常,除非涉及到control.skin中的類(也可能是其他人,沒有檢查) - 重現,運行下面的示例,單擊按鈕,看看如何訪問成功,直到嘗試訪問私有ButtonSkin中的字段。堆棧跟蹤:xxSkin類中的深度反射失敗

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的氧-R與補丁java9,在項目准入規則設置爲允許的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()); 
} 
+0

我在9 + 178上重現了錯誤。的確,非常奇怪的錯誤! – ZhekaKozlov

回答

8

要防止新的API意外的依賴,非法訪問僅授予到Java 9前已存在的軟件包 - 因此我假設com.sun.javafx.scene.control.behavior是新的。

在他mail with the revised proposal for --illegal-access馬克萊因霍爾德寫入(重點煤礦):

--illegal-access=permit

此模式將打開運行時圖像中 代碼中的每個模塊中的每個包中所有未命名的模塊,即如果在JDK 8中存在 包,則在類路徑上的代碼爲。這使得靜態訪問(即編譯的字節碼)和深度反射訪問(通過平臺的各種反射API)成爲可能。

任何此類封裝的第一個反射訪問操作會導致發出警告,但在該點之後不會發出警告。 此單一警告描述瞭如何啓用更多警告。

此模式將作爲JDK 9的默認模式。它將在未來版本的 中刪除。

+2

就是這樣:javafx.scene.control.skin在java9中是新的(從內部的api com.sun中移動到公有的)所以我們需要--add-opens ...現在和將來的皮膚包。 。嘆氣謝謝! – kleopatra