关于Java 9中的非法反射访问存在很多问题。
现在我无法找到,因为谷歌的所有人都在努力解决错误信息,实际上是非法的反射访问。
所以我的问题很简单:
什么定义了非法反射访问以及在什么情况下触发警告?
我已经收集到它与Java 9中引入的封装原则有关,但是它们如何挂在一起以及什么触发了警告,在什么情况下我无法找到解释。
答案 0 :(得分:23)
除了了解模块及其各自包之间的访问之外。我相信它的关键在于 Module System#Relaxed-strong-encapsulation ,我只想挑选它的相关部分来尝试回答这个问题。
什么定义了非法反射访问以及在什么情况下 触发警告?
为了帮助迁移到Java9,可以放松对模块的强大封装。
实现可以提供静态访问,即通过编译的字节码。
可以提供一种方法来调用其运行时系统,其中一个或多个模块的一个或多个包打开到所有未命名模块中的代码,即在类路径上编码。如果以这种方式调用运行时系统,并且通过这样做,一些反射API的调用会成功,否则它们将失败。
在这种情况下,您实际上最终会进行反思访问 "非法" ,因为在纯粹的模块化世界中不打算进行此类访问。
如何将它们挂在一起以及触发警告的内容 场景吗
封装的这种放宽在运行时由新的启动器选项--illegal-access
控制,默认情况下,Java9等于permit
。 permit
模式确保
对任何此类包的第一次反射访问操作会导致a 发出警告,但在此之后没有发出警告。 此单个警告描述了如何启用进一步的警告。这个 警告无法抑制。
模式可配置为值debug
(消息以及每次此类访问的堆栈跟踪),warn
(每个此类访问的消息)和deny
(禁用此类操作)。
调试和修复应用程序的几件事情是: -
--illegal-access=deny
运行它以了解并避免打开包从一个模块到另一个模块而没有包含此类指令(opens
)或模块声明的模块声明明确使用--add-opens
VM arg。使用带有jdeps
选项的--jdk-internals
工具
非法反射访问操作时发出的警告消息 检测到具有以下形式:
WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
其中:
$PERPETRATOR
是包含该类型的类型的完全限定名称 调用有问题的反射操作的代码加上代码 source(即JAR文件路径)(如果可用)和
$VICTIM
是一个描述被访问成员的字符串, 包括封闭类型的完全限定名称
此类示例警告的问题:= JDK9: An illegal reflective access operation has occurred. org.python.core.PySystemState
最后也是一个重要的注意事项,在尝试确保您不会面临此类警告并且未来安全的同时,您需要做的就是确保您的模块不会进行非法的反射访问。 :)
答案 1 :(得分:14)
我找到了一个关于Java 9模块系统的Oracle article
默认情况下,其他模块无法访问模块中的类型,除非它是公共类型并导出其包。您只公开要公开的包。使用Java 9,这也适用于反射。
正如https://stackoverflow.com/a/50251958/134894所指出的,JDK8和JDK9的AccessibleObject#setAccessible
之间的差异是有益的。具体来说,JDK9添加了
C类中的调用者可以使用此方法来访问声明类D的成员(如果存在以下任何一种情况):
- C和D属于同一模块。
- 该成员是公共的,D在包中是公共的,包含D的模块至少导出到包含C的模块。
- 该成员受静态保护,D在包中是公共的,包含D的模块至少导出到包含C的模块,而C是D的子类。
- D在包中,包含D的模块至少打开包含C的模块。未命名和打开模块中的所有包都对所有模块开放,因此当D在未命名或打开的模块中时,此方法总是成功。
突出了模块及其出口的重要性(在Java 9中)
答案 2 :(得分:9)
只需查看用于访问setAccessible()
字段和方法的private
方法:
现在,此方法需要更多条件才能工作。它没有打破几乎所有旧软件的唯一原因是从普通JAR自动生成的模块非常宽松(打开并导出所有人的所有内容)。
答案 3 :(得分:1)
如果要使用add-open选项,请使用以下命令查找哪个模块提供了哪个软件包->
java --list-modules | tr @ " " | awk '{ print $1 }' | xargs -n1 java -d
模块名称将与@一起显示,而软件包名称则不包含@
注意:已通过JDK 11测试
重要提示:显然比不对软件包提供者进行非法访问要好
答案 4 :(得分:1)
如果你想隐藏警告,你可以使用“--add-opens”选项
--add-opens <source-module>/<package>=<target-module>(,<target-module>)*
例如你有一个错误:
java.lang.ClassLoader.findLoadedClass(java.lang.String)
首先打开 String java 11 文档 Class String 在哪里可以找到模块和包名称
模块 java.base,包 java.lang
解决方案:
java --add-opens=java.base/java.lang=ALL-UNNAMED -jar example.jar