简体   繁体   English

如何使反射在 JDK 16 及更高版本上工作?

[英]How can I make reflection work on JDK 16 and later?

I have the following legacy code that I migrated to Java 16 but, due to the strong encapsulation introduced by this new version, it doesn't work:我有以下已迁移到 Java 16 的遗留代码,但是由于这个新版本引入了强封装,它不起作用:

try {
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    method.setAccessible(true);
    method.invoke(new URLClassLoader(
        new URL[] {}),
        new File("C:/external-folder/my.jar").toURI().toURL()
    );
} catch (Exception exc) {
    exc.printStackTrace();
}

Is there a way to make it work?有没有办法让它工作?

The problem is not that reflection "doesn't work";问题不在于反射“不起作用”; it is that reflection is finally enforcing more of the accessibility model that the compiler and runtime have always enforced.正是反射最终强制执行了编译器和运行时一直强制执行的更多可访问性模型。 URLClassLoader::addUrl is intended only for subclasses; URLClassLoader::addUrl仅用于子类; it is not intended to be accessed from outside the implementation, which is what you're doing.它不打算从实现外部访问,这就是您正在做的事情。 Over time, starting with Java 9 and continuing in later versions (including 17), access restrictions are increasingly recognized by reflection, with warnings, to give broken code a chance to migrate to something supportable.随着时间的推移,从 Java 9 开始并继续到更高版本(包括 17),反射越来越多地认识到访问限制,并带有警告,让损坏的代码有机会迁移到可支持的东西。

The code in question only really ever worked accidentally;有问题的代码只是偶然地工作; it depended on being able to break into an unsupported interface.它取决于能够闯入不受支持的接口。 Using setAccessible should be a clue.使用setAccessible应该是一个线索。 Sure, you can get into locked houses by breaking windows, but if you have to break a window (and it's not your house), you should be aware of where the problem lies.当然,你可以通过打破窗户进入锁着的房子,但如果你不得不打破窗户(这不是你的房子),你应该知道问题出在哪里。

Look at it as glass-half-full;把它看成玻璃半满; this accidentally-working code worked for a long time.这个意外工作的代码工作了很长时间。 But the bill has come due;但该法案已经到期; it is time to fix your code.是时候修复您的代码了。

The code is very weird.代码非常奇怪。 At first glance, I thought it used reflection to access URLClassLoader internals to add myJar to an existing class loader , but instead it uses it to add it to a new class loader .乍一看,我认为它使用反射访问URLClassLoader内部来将myJar添加到现有的类加载器,但它使用它来将它添加到新的类加载器 There's no reason to do that - you can just use the URLClassLoader constructor for that.没有理由这样做 - 您可以为此使用URLClassLoader构造函数

It should look something like this (untested because I am away from an IDE):它应该看起来像这样(未经测试,因为我远离 IDE):

URL jar = new File("C:/external-folder/my.jar").toURI().toURL();
URL[] urls = { jar };
new URLClassLoader(urls);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM