什么是非法反射访问

Tsc*_*cka 82 java java-9 java-module

关于Java 9中的非法反射访问存在很多问题.

现在我找不到的是因为所有谷歌都在努力解决错误信息,实际上是非法的反射访问.

所以我的问题很简单:

什么定义非法反射访问以及什么情况触发警告?

我已经收集到它与Java 9中引入的封装原则有关,但它们如何挂在一起以及什么触发警告在什么情况下我找不到解释.

Nam*_*man 35

除了了解模块及其各自包之间的访问之外.我相信它的关键在于模块系统#Simply-strong-encapsulation,我只是挑选它的相关部分来尝试回答这个问题.

什么定义非法反射访问以及什么情况触发警告?

为了帮助迁移到Java9,可以放松模块的强大封装.

  • 实现可以提供静态访问,即通过编译的字节码.

  • 可以提供一种方法来调用其运行时系统,其中一个或多个模块的一个或多个包在所有未命名的模块中打开代码,即在类路径上编码.如果以这种方式调用运行时系统,并且通过这样做,一些反射API的调用会成功,否则它们将失败.

在这种情况下,您实际上最终会进行"非法"反射访问,因为在纯粹的模块化世界中,您并不打算进行此类访问.

如何将它们挂在一起以及在什么情况下触发警告的原因是什么?

封装的这种放宽在运行时由新的启动器选项控制,该选项--illegal-access默认在Java9中等于permit.该permit模式确保

对任何此类包的第一次反射访问操作会导致发出警告,但在该点之后不会发出警告.此单个警告描述了如何启用进一步的警告.无法抑制此警告.

模式可配置为值debug(消息以及每个此类访问的堆栈跟踪),warn(每个此类访问的消息)和deny(禁用此类操作).


调试和修复应用程序的几件事情是: -

  • 运行它--illegal-access=deny以了解并避免从一个模块打开包到另一个模块而没有包含这样的指令(opens)或明确使用--add-opensVM arg 的模块声明.
  • 可以使用jdeps带有该--jdk-internals选项的工具来识别从已编译代码到JDK内部API的静态引用

    检测到非法反射访问操作时发出的警告消息具有以下形式:

    WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
    
    Run Code Online (Sandbox Code Playgroud)

    哪里:

    $PERPETRATOR 是包含调用有问题的反射操作的代码的类型的完全限定名称加上代码源(即JAR文件路径)(如果可用),以及

    $VICTIM 是一个描述被访问成员的字符串,包括封闭类型的完全限定名称

针对此类示例警告的问题:= JDK9:发生了非法反射访问操作.org.python.core.PySystemState

最后也是一个重要的注意事项,在尝试确保您不会面临此类警告并且未来安全时,您需要做的就是确保您的模块不会进行非法的反射访问.:)


pto*_*mli 18

我发现了一篇关于Java 9模块系统的Oracle 文章

默认情况下,其他模块无法访问模块中的类型,除非它是公共类型并导出其包.您只公开要公开的包.使用Java 9,这也适用于反射.

正如/sf/answers/3517637091/中所指出的AccessibleObject#setAccessible,JDK8和JDK9 之间的区别是有益的.具体来说,JDK9补充道

C类中的调用者可以使用此方法来访问声明类D的成员,如果满足以下任何条件:

  • C和D在同一模块中.
  • 成员是公共的,D是公开的包,包含D的模块至少导出到包含C的模块.
  • 该成员是静态保护的,D是公包的,包含D的模块至少导出到包含C的模块,而C是D的子类.
  • D在包中,包含D的模块至少打开包含C的模块.未命名和打开模块中的所有包都对所有模块开放,因此当D在未命名或打开的模块中时,此方法总是成功.

这突出了模块及其出口的重要性(在Java 9中)

  • 因此,如果我阅读了那篇文章,正确地修改导出类中的私有属性就不在话下。只能修改受保护和公共属性。现在我不太关心 java 内部导出,但更多的是关于 3rd 方库,我有时需要访问私有变量以设置为特定值。如果它将自己定义为一个模块,那么在这个方案中这将不再可能,对吗? (2认同)

use*_*037 12

只需看看setAccessible()用于访问private字段和方法的方法:

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

https://docs.oracle.com/javase/9​​/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible-boolean-

现在,此方法需要更多条件才能工作.它几乎没有打破所有旧软件的唯一原因是从普通JAR自动生成的模块是非常宽松的(打开并导出所有人的一切).


小智 6

如果你想隐藏警告,你可以使用“--add-opens”选项

--add-opens <source-module>/<package>=<target-module>(,<target-module>)*
Run Code Online (Sandbox Code Playgroud)

例如你有一个错误:

java.lang.ClassLoader.findLoadedClass(java.lang.String)
Run Code Online (Sandbox Code Playgroud)

首先打开 String java 11 文档 Class String,您可以在其中找到模块和包名称

模块 java.base,包 java.lang

解决方案:

java --add-opens=java.base/java.lang=ALL-UNNAMED -jar example.jar
Run Code Online (Sandbox Code Playgroud)