我只是尝试使用Java 9运行我的服务器,并得到下一个警告:
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by io.netty.util.internal.ReflectionUtil (file:/home/azureuser/server-0.28.0-SNAPSHOT.jar) to constructor java.nio.DirectByteBuffer(long,int)
WARNING: Please consider reporting this to the maintainers of io.netty.util.internal.ReflectionUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
我希望隐藏此警告,而不在启动期间向JVM选项添加<code>--非法访问=拒绝</code>。类似于:
System.setProperty("illegal-access", "deny");
有什么办法吗?
所有建议使用JVM选项的相关答案,我想从代码中关闭它。这可能吗?
为了澄清-我的问题是关于从代码中转换此警告,而不是通过类似问题中所述的JVM参数/标志。
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Main {
@SuppressWarnings("unchecked")
public static void disableAccessWarnings() {
try {
Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Object unsafe = field.get(null);
Method putObjectVolatile = unsafeClass.getDeclaredMethod("putObjectVolatile", Object.class, long.class, Object.class);
Method staticFieldOffset = unsafeClass.getDeclaredMethod("staticFieldOffset", Field.class);
Class loggerClass = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field loggerField = loggerClass.getDeclaredField("logger");
Long offset = (Long) staticFieldOffset.invoke(unsafe, loggerField);
putObjectVolatile.invoke(unsafe, loggerClass, offset, null);
} catch (Exception ignored) {
}
}
public static void main(String[] args) {
disableAccessWarnings();
}
}
它在JAVA 11中对我有效。
还有另一个选项,它不需要流抑制,也不依赖于未记录或不支持的API。使用Java代理,可以重新定义模块以导出/打开所需的包。代码如下所示:
void exportAndOpen(Instrumentation instrumentation) {
Set<Module> unnamed =
Collections.singleton(ClassLoader.getSystemClassLoader().getUnnamedModule());
ModuleLayer.boot().modules().forEach(module -> instrumentation.redefineModule(
module,
unnamed,
module.getPackages().stream().collect(Collectors.toMap(
Function.identity(),
pkg -> unnamed
)),
module.getPackages().stream().collect(Collectors.toMap(
Function.identity(),
pkg -> unnamed
)),
Collections.emptySet(),
Collections.emptyMap()
));
}
现在,您可以运行任何非法访问而不会出现警告,因为您的应用程序包含在未命名的模块中,例如:
Method method = ClassLoader.class.getDeclaredMethod("defineClass",
byte[].class, int.class, int.class);
method.setAccessible(true);
为了获得Instrumence
实例,您可以编写一个非常简单的Java代理,并使用-javaagent:myjar.jar
在命令行(而不是类路径)上指定它。代理将只包含一个premain
方法,如下所示:
public class MyAgent {
public static void main(String arg, Instrumentation inst) {
exportAndOpen(inst);
}
}
或者,您可以使用byte-party-agent项目(我编写的)方便访问的附加API动态附加:
exportAndOpen(ByteBuddyAgent.install());
您需要在非法访问之前调用它。请注意,这仅在 JDK 和 Linux VM 上可用,而如果您在其他 VM 上需要,则需要在命令行上提供 Byte Buddy 代理作为 Java 代理。当您希望在通常安装了 JDK 的测试和开发计算机上进行自连接时,这可能很方便。
正如其他人所指出的,这应该只是一个中间解决方案,但我完全理解当前的行为经常会破坏日志爬虫和控制台应用程序,这就是为什么我自己在生产环境中使用它作为使用Java9的短期解决方案,这么长时间我没有遇到任何问题。
然而,好的一面是,这种解决方案对未来的任何操作更新都是健壮的,即使动态附件是合法的。使用一个助手进程,Byte Buddy甚至可以绕过通常被禁止的自连接。
有一些方法可以禁用非法访问警告,但我不建议这样做。
由于警告打印到默认错误流,因此您可以简单地关闭此流并将stderr
重定向到stdout
。
public static void disableWarning() {
System.err.close();
System.setErr(System.out);
}
注意事项:
一个好消息是,在JDK 9中仍然可以在没有警告的情况下访问< code>sun.misc.Unsafe。解决方法是借助不安全API重置内部< code>IllegalAccessLogger。
public static void disableWarning() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe u = (Unsafe) theUnsafe.get(null);
Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field logger = cls.getDeclaredField("logger");
u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
} catch (Exception e) {
// ignore
}
}
问题内容: 我只是尝试使用Java 9运行服务器,并收到下一个警告: 我想隐藏此警告而不在启动过程中添加到JVM选项。就像是: 有什么办法吗? 建议使用JVM选项的所有相关答案,我想从代码中关闭它。那可能吗? 要澄清-我的问题是关于从代码而不是通过类似问题中所述的JVM参数/标志来启用此警告。 问题答案: 有几种方法可以禁用非法访问警告,尽管我不建议您这样做。 1.简单的方法 由于警告已打印到默认
我正在遵循Oracle的教程在JavaFX中创建TableView。在这个截图中,我复制并粘贴了代码,发现了几个错误,教程中没有提到这些错误。 TableView上的警告显示: TableView是原始类型。对泛型类型TableView的引用 表列上的警告说: 表列是一个原始类型。对泛型类型TableCol列的引用 addAll方法上的警告是: 类型安全:方法addAll(Object…)属于原始
如何为非法反射访问警告引发异常?例如,考虑以下代码: 此代码将以下警告输出到 System.err: Boolean.TRUE是一个如此简单的值,以至于我真的不需要RefltionToStringBuilder。但是更复杂的类型(例如HashMap)打印相同的警告。我选择Boolean.TRUE是为了简化这个例子。 当我搜索此警告消息时,我发现了将其报告给包维护者,避免警告或完全禁用它的建议(JD
如果能帮助我重写一些使用反射的Java代码,以便在Java10上删除编译器中的警告,我将不胜感激: 这就是所讨论的Java方法: 这是GitHub上的问题代码:https://github.com/librepdf/openpdf/blob/master/openpdf/src/main/java/com/lowagie/text/pdf/mappedrandomaccessfile.java#l
我正在尝试设置一个动态,从本地目录读取文件。因此,我创建了以下可参数化类: 参数化流在的帮助下注册,如下所示: 启动应用程序后,我得到以下警告: 如果我理解正确的话,负责创建集成bean(从而设置beanFactory)。但是为什么我会收到这个错误信息呢?
我在Eclipse(版本2019-06)中运行一个项目,它在我的java计算机上运行得很好--“OpenJDK 1.8.0_222” 然而,当我尝试tor在Eclipse(版本2021-3)上的另一台计算机上用java运行该项目时--“OpenJDK版本”1.8.0_292“,它不起作用! 我得到以下错误: 警告:发生非法反射访问操作警告:com.google.gson.internal.bind