JPMS: --add-open 不适用于 java.lang.reflect.InaccessObjectException



我将Java 14与Jetty 9.4和Weld-servlet-shhaded-3.1一起使用,得到了以下异常:

Caused by: java.lang.reflect.InaccessibleObjectException: 
Unable to make protected final java.lang.Class   
java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int)
throws java.lang.ClassFormatError accessible: module java.base does 
not "opens java.lang" to module weld.servlet.shaded.

根据此处的答案:https://stackoverflow.com/a/41265267/5057736我试着添加

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

--add-opens java.base/java.lang=weld.servlet.shaded 

但没有人帮忙。有人能说怎么修吗?

EDIT 1
我发现这个问题出现在Java 12,13,14 OpenJDK/Oracle中。然而,如果我使用Java 11 OpenJDK/Oralce,一切都很好,我甚至不添加任何--add-opens。如何解释?

EDIT 2
我检查过Jetty pom和Weld pom,它们都具有相同的属性:

<compiler.source>1.8</compiler.source>
<compiler.target>1.8</compiler.target>

编辑3
Java版本

$ java -version
openjdk version "14" 2020-03-17
OpenJDK Runtime Environment (build 14+36-1461)
OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)

启动应用程序

$java .... --add-opens java.base/java.lang=weld.servlet.shaded ...

这是堆栈跟踪

09:58:41.243 [RMI TCP Connection(2)-127.0.0.1] INFO  org.jboss.weld.environment.servletWeldServlet - WELD-ENV-001008: Initialize Weld using ServletContainerInitializer
09:58:41.293 [RMI TCP Connection(2)-127.0.0.1] INFO  org.jboss.weld.Version - WELD-000900: 3.1.0 (Final)
09:58:41.468 [RMI TCP Connection(2)-127.0.0.1] WARN  org.jboss.weld.environment.servletWeldServlet - WELD-ENV-001004: Found both WEB-INF/beans.xml and WEB-INF/classes/META-INF/beans.xml. It is not portable to use both locations at the same time. Weld is going to use: file:/home/<SOME TEXT DELETED>/webapp/WEB-INF/beans.xml
09:58:41.479 [RMI TCP Connection(2)-127.0.0.1] INFO  org.jboss.weld.Bootstrap - WELD-ENV-000014: Falling back to Java Reflection for bean-discovery-mode="annotated" discovery. Add org.jboss:jandex to the classpath to speed-up startup.
09:58:41.550 [RMI TCP Connection(2)-127.0.0.1] WARN  org.eclipse.jetty.annotations.ServletContainerInitializersStarter - 
java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to module weld.servlet.shaded
at java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:349) ~[?:?]
at java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:289) ~[?:?]
at java.lang.reflect.Method.checkCanSetAccessible(Method.java:196) ~[?:?]
at java.lang.reflect.Method.setAccessible(Method.java:190) ~[?:?]
at org.jboss.weld.util.bytecode.ClassFileUtils$1.run(ClassFileUtils.java:88) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at java.security.AccessController.doPrivileged(AccessController.java:554) ~[?:?]
at org.jboss.weld.util.bytecode.ClassFileUtils.makeClassLoaderMethodsAccessible(ClassFileUtils.java:64) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.bootstrap.WeldStartup.startContainer(WeldStartup.java:220) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.bootstrap.WeldBootstrap.startContainer(WeldBootstrap.java:72) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.bootstrap.WeldBootstrap.startContainer(WeldBootstrap.java:67) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.environment.servlet.WeldServletLifecycle.initialize(WeldServletLifecycle.java:182) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.environment.servlet.EnhancedListener.onStartup(EnhancedListener.java:62) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.eclipse.jetty.plus.annotation.ContainerInitializer.callStartup(ContainerInitializer.java:140) ~[jetty-plus-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.annotations.ServletContainerInitializersStarter.doStart(ServletContainerInitializersStarter.java:64) [jetty-annotations-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) [jetty-util-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:346) [jetty-servlet-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1497) [jetty-webapp-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1459) [jetty-webapp-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:852) [jetty-server-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:278) [jetty-servlet-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:545) [jetty-webapp-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) [jetty-util-9.4.14.v20181114.jar:?]
<SOME TEXT DELETED>
09:58:41.555 [RMI TCP Connection(2)-127.0.0.1] WARN  org.eclipse.jetty.webapp.WebAppContext - Failed startup of context o.e.j.w.WebAppContext@6a329710{/,file:///home//<SOME TEXT DELETED>/webapp/,UNAVAILABLE}{/home/<SOME TEXT DELETED>.war}
java.lang.RuntimeException: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to module weld.servlet.shaded
at org.eclipse.jetty.annotations.ServletContainerInitializersStarter.doStart(ServletContainerInitializersStarter.java:69) ~[jetty-annotations-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) ~[jetty-util-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:346) ~[jetty-servlet-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1497) ~[jetty-webapp-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1459) ~[jetty-webapp-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:852) ~[jetty-server-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:278) ~[jetty-servlet-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:545) [jetty-webapp-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) [jetty-util-9.4.14.v20181114.jar:?]
<SOME TEXT DELETED>
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to module weld.servlet.shaded
at java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:349) ~[?:?]
at java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:289) ~[?:?]
at java.lang.reflect.Method.checkCanSetAccessible(Method.java:196) ~[?:?]
at java.lang.reflect.Method.setAccessible(Method.java:190) ~[?:?]
at org.jboss.weld.util.bytecode.ClassFileUtils$1.run(ClassFileUtils.java:88) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at java.security.AccessController.doPrivileged(AccessController.java:554) ~[?:?]
at org.jboss.weld.util.bytecode.ClassFileUtils.makeClassLoaderMethodsAccessible(ClassFileUtils.java:64) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.bootstrap.WeldStartup.startContainer(WeldStartup.java:220) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.bootstrap.WeldBootstrap.startContainer(WeldBootstrap.java:72) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.bootstrap.WeldBootstrap.startContainer(WeldBootstrap.java:67) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.environment.servlet.WeldServletLifecycle.initialize(WeldServletLifecycle.java:182) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.jboss.weld.environment.servlet.EnhancedListener.onStartup(EnhancedListener.java:62) ~[weld-servlet-shaded-3.1.0.Final.jar:?]
at org.eclipse.jetty.plus.annotation.ContainerInitializer.callStartup(ContainerInitializer.java:140) ~[jetty-plus-9.4.14.v20181114.jar:?]
at org.eclipse.jetty.annotations.ServletContainerInitializersStarter.doStart(ServletContainerInitializersStarter.java:64) ~[jetty-annotations-9.4.14.v20181114.jar:?]
... 31 more

EDIT 4
我发现焊接会导致不同的行为。这来自ClassFileUtils:

public static void makeClassLoaderMethodsAccessible() {
// the AtomicBoolean make sure this gets invoked only once as WeldStartup is triggered per deployment
if (classLoaderMethodsMadeAccessible.compareAndSet(false, true)) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
Class<?> cl = Class.forName("java.lang.ClassLoader");
final String name = "defineClass";
defineClass1 = cl.getDeclaredMethod(name, String.class, byte[].class, int.class, int.class);
defineClass2 = cl.getDeclaredMethod(name, String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
// First try with Unsafe to avoid illegal access
try {
// get Unsafe singleton instance
Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
singleoneInstanceField.setAccessible(true);
Unsafe theUnsafe = (Unsafe) singleoneInstanceField.get(null);
// get the offset of the override field in AccessibleObject
long overrideOffset = theUnsafe.objectFieldOffset(AccessibleObject.class.getDeclaredField("override"));
// make both accessible
theUnsafe.putBoolean(defineClass1, overrideOffset, true);
theUnsafe.putBoolean(defineClass2, overrideOffset, true);
return null;
} catch (NoSuchFieldException e) {
// This is JDK 12+, the "override" field isn't there anymore, fallback to setAccessible()
LINE 88                 defineClass1.setAccessible(true);
defineClass2.setAccessible(true);
return null;
}
}
});
} catch (PrivilegedActionException pae) {
throw new RuntimeException("cannot initialize ClassPool", pae.getException());
}
}
}

正如您在第88行看到的,ti调用了被JPMS阻止的setAccessible(true(方法。那么,最后一个问题是,考虑到Weld和Jetty在子JPMS层中,是否可以通过JPMS设置来解决这个问题?

我发现有两个问题:

  1. Weld ClassFileUtils.makeClassLoaderMethods Accessible((与JDK11和JDK12+的工作方式不同
  2. --add打开为CLI参数不适用于动态创建的层JPMS?请在此处查看详细信息

相关内容

最新更新