问题描述
我将Java 14与Jetty 9.4和Weld-servlet-shaded-3.1一起使用,但出现此异常:
I use Java 14 with Jetty 9.4 and Weld-servlet-shaded-3.1 and I get this exception:
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 我试图添加
According to answer here: https://stackoverflow.com/a/41265267/5057736 I tried to add
--add-opens java.base/java.lang=ALL-UNNAMED
和
--add-opens java.base/java.lang=weld.servlet.shaded
但是没有人帮助.谁能说出解决办法?
But no one helped. Could anyone say how to fix it?
编辑1
我发现此问题出现在Java 12,13,14 OpenJDK/Oracle中.但是,如果我使用Java 11 OpenJDK/Oralce,则一切正常,甚至不添加任何--add-opens
.怎么解释呢?
EDIT 1
I found out that this problems appears in Java 12,13,14 OpenJDK/Oracle. However, if I use Java 11 OpenJDK/Oralce everything works fine and I even don't add any --add-opens
. How to explain it?
编辑2
我已经检查码头pom 和焊接pom 它们都具有相同的属性:
EDIT 2
I've checked Jetty pom and Weld pom they both have the same properties:
<compiler.source>1.8</compiler.source>
<compiler.target>1.8</compiler.target>
编辑3
Java版本
EDIT 3
Java version
$ 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
编辑4
我发现由于焊接而发生了不同的行为.这是来自ClassFileUtils的片段:
EDIT 4
I found out that different behavior happens because of weld. This is from piece from 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设置来解决?
as you see at line 88 ti calls setAccessible(true) method that is blocked by JPMS. So, the last question is it possible to solve this problem by JPMS settings, taking into consideration that that Weld and Jetty are in child JPMS layer?
推荐答案
我发现存在两个问题:
- 焊接ClassFileUtils.makeClassLoaderMethodsAccessible()与JDK11和JDK12 +的工作方式不同.
- -add-opens作为CLI参数不适用于动态创建的层JPMS?在此处 中查看详细信息
- Weld ClassFileUtils.makeClassLoaderMethodsAccessible() works differently with JDK11 and JDK12+.
- --add-opens as CLI parameter doesn't work for dynamically created layers JPMS? See details here
这篇关于JPMS:--add-opens不适用于java.lang.reflect.InaccessibleObjectException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!