升级JDK1.8 到 JDK17 时访问报Unable to make protected native ??? .clone() 的异常 您所在的位置:网站首页 unnamed中文意思 升级JDK1.8 到 JDK17 时访问报Unable to make protected native ??? .clone() 的异常

升级JDK1.8 到 JDK17 时访问报Unable to make protected native ??? .clone() 的异常

2023-06-12 14:23| 来源: 网络整理| 查看: 265

问题重现 异常代码 2023-06-05T23:35:32.328+08:00 ERROR 6968 --- [nio-8080-exec-9] y.s.c.exception.ExceptionInterception : Unable to make protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not "opens java.lang" to unnamed module @1757cd72 java.lang.reflect.InaccessibleObjectException: Unable to make protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException accessible: module java.base does not "opens java.lang" to unnamed module @1757cd72 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na] at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na] at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199) ~[na:na] at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) ~[na:na]

现在还有很长,不放了,大概意思就是这样

问题重点及分析

module java.base does not "opens java.lang" to unnamed module

翻译得:base 模块中没将 lang 模块打包到未命名模块。

说人话,人家不想给我们用 clone() 了,人家把 accessiable 属性设置为 false 了。

在 JDK1.8 及之前,这个属性是打开的,意思就是 1.8 前会反射出里面的所有方法。我们都知道反射需要大量的性能。然而这些方法的使用频率不高,为了这些调用可能性低的代码牺牲这些性能显然不值,何况有性能更高的方法来代替了这些方法,所以从 JDK1.8 后大量包的可访问反射属性都被关闭了,lang 就是其中之一。

这也就是很多 Java 工程以前明明用的好好的,升级后会报大量异常的原因。

问题证明

声明:出问题的异常的版本为 JDK17。

异常第二行中点击进去跳转到 AccessibleObject 的第 354 行,方法如下。

仔细分析会发现,在最后一个判断前,可设置访问属性全部都是返回true。 当上面都返回 false,第三个参数又为 true ,此时一定会报异常。

private boolean checkCanSetAccessible(Class caller, Class declaringClass, boolean throwExceptionIfDenied) { if (caller == MethodHandle.class) { throw new IllegalCallerException(); // should not happen } Module callerModule = caller.getModule(); Module declaringModule = declaringClass.getModule(); if (callerModule == declaringModule) return true; if (callerModule == Object.class.getModule()) return true; if (!declaringModule.isNamed()) return true; String pn = declaringClass.getPackageName(); int modifiers; if (this instanceof Executable) { modifiers = ((Executable) this).getModifiers(); } else { modifiers = ((Field) this).getModifiers(); } // class is public and package is exported to caller boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); if (isClassPublic && declaringModule.isExported(pn, callerModule)) { // member is public if (Modifier.isPublic(modifiers)) { return true; } // member is protected-static if (Modifier.isProtected(modifiers) && Modifier.isStatic(modifiers) && isSubclassOf(caller, declaringClass)) { return true; } } // package is open to caller if (declaringModule.isOpen(pn, callerModule)) { return true; } if (throwExceptionIfDenied) { // not accessible String msg = "Unable to make "; if (this instanceof Field) msg += "field "; msg += this + " accessible: " + declaringModule + " does not \""; if (isClassPublic && Modifier.isPublic(modifiers)) msg += "exports"; else msg += "opens"; msg += " " + pn + "\" to " + callerModule; InaccessibleObjectException e = new InaccessibleObjectException(msg); if (printStackTraceWhenAccessFails()) { e.printStackTrace(System.err); } throw e; } return false; }

再看异常提示:module java.base does not "opens java.lang" to unnamed module

关于 module 的。

在方法里我们发现在 339 行判断了 module ,刚好那个检查的方法就叫 isOpen ,显然检测访问属性的这里。

通过打断点可以发现,Module 的 560 行调用了616 行的方法,很不幸所有能返回 true 的一个没踩到。

到此,完全可以证明 lang 包不被开放可访问属性。

解决方法

既然知道了问题,那简单,让他放开就可以了。但这个明显是关于 JVM 的问题,所以我们需要去 JVM 里调参。那简单点启动时给他加上这个开放属性就可以了。

具体如下

1

2

在这里插入图片描述

3 代码在这里 –add-opens java.base/java.lang=ALL-UNNAMED

在这里插入图片描述

至此,这个问题已解决。再测试,clone() 方法已经正常用了。

总结

一个问题是由多方位造成的,写了这么多不仅仅只是想让大家知道这个问题如何解决,更想传递一种定位问题、解决问题的方法。

行成于思,善于思考才是最重要的!!

END


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有