JKD17运行报错Unable to make field private final byte[] java.lang.String.value accessible

之前使用jdk8的代码升级到jdk17运行报错信息如下:

Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field private final byte[] java.lang.String.value accessible: module java.base does not "opens java.lang" to unnamed module @473b46c3
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
	at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)

大致意思就是通过反射获取String类中的私有字段byte[] value 失败了。

那怎么会这样呢,原因是:

在Java9之后引入了module模块的概念,而不同module模块间是不允许使用反射来访问非public的字段/方法/构造函数(field/method/constructor),除非被访问的目标模块为反射设置open即允许自身被其他模块进行non-public反射访问。

解决办法:

Java 9之后引入了一个新的JVM选项 --illegal-access,该选项有四个可选值:

permit:Jdk9、Jdk11的默认值,允许不同模块间进行non-public反射访问,且仅在首次非法访问会给出警告,后续不再警告。在该模式下会自动将Jdk8(或更低版本)的代码进行opens设置,即允许Jdk8的代码被其他模块进行non-public反射访问,也允许Jdk8的代码对其他模块进行non-public反射访问,如此可保证高、低版本混合的Java程序如往常一样正常运行。
warn:类似permit,但是每次非法访问都会警告
debug:类似warn,但在warn的基础上加入了类似e.printStackTrace()的功能
deny:未来的默认值,禁止所有的不同模块间的non-public反射访问,出现非法反射则抛出异常,除了使用特别的命令行参数排除的模块,比如使用 –add-opens排除某些模块使其能够通过非法反射访问
线上使用了--illegal-access=deny,所以出现非法反射时会导致程序抛异常而启动失败,
而本地开发环境运行程序时,未明确设置–illegal-access则使用默认--illegal-access=premit,所以可以启动成功,但在第一次非法反射访问时给出了警告。

综上,在设置了--illegal-access=deny(推荐设置deny,兼容未来Java版本)时,需同时添加--add-opens以开启对应模块/包允许被其他模块进行非法(non-public)反射访问。

例如根据之前的日志:

Unable to make field private final byte[] java.lang.String.value accessible:      
module java.base does not "opens java.lang" to unnamed module @1b70203f     

将关键提示日志拆解后如下表:

被访问模块名被访问包名发起非法访问的模块名
modulejava.basedoes not“opens java.lang”tounnamed module @473b46c3


具体转换格式:--add-opens 被访问模块名/被访问包名=发起非法访问的模块名

根据如上日志转换如下--add-opens命令为:

--add-opens java.base/java.long=ALL-UNNAMED


注: ALL-UNNAMED表示所有的未命名模块

反复重启根据提示最终整理如下完整--add-opens选项:

--illegal-access=deny
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
--add-opens java.base/java.lang.invoke=ALL-UNNAMED
--add-opens java.base/java.math=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/java.text=ALL-UNNAMED


如上完整启动选项添加到vm参数中后,程序可以正常启动了。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值