[英]How can I make a URLClassLoader behave like this?
我正在嘗試制作一個行為如下的URLClassLoader:
我無法使它正常工作。 在下面的嘗試中,我希望SpecialClassLoader
成功加載Test$Thing
。 這樣做時,我希望它嘗試加載Test$SuperThing
,並且可以對虛擬類Nothing
進行加載這一事實感到滿意。
但是,出現了問題,並拋出了NoClassDefFoundError
以查找Test$SuperThing
。
有誰知道如何解決這一問題?
public class Test {
private static class SuperThing {}
private static class Thing extends SuperThing {}
public static void main(String[] args) {
Set<String> inclusions = new HashSet<String>();
inclusions.add("Test$Thing"); // note Test$SuperThing is excluded
URLClassLoader cl = (URLClassLoader)
Thread.currentThread().getContextClassLoader();
SpecialClassLoader cll =
new SpecialClassLoader(cl.getURLs(), inclusions);
try {
cll.loadClass("Test$Thing"); // line 22 (see stacktrace below)
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static class Nothing {}
private static final class SpecialClassLoader extends URLClassLoader {
private final Set<String> inclusions;
public SpecialClassLoader(URL[] urls, Set<String> inclusions) {
super(urls);
this.inclusions = inclusions;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (inclusions.contains(name)) {
return findClass(name); // line 40 (see stacktrace below)
}
return Nothing.class;
}
}
}
編輯:這是我得到的stacktrace(上面的清單中指出了行號22和40):
Exception in thread "main" java.lang.NoClassDefFoundError: Test$SuperThing at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass(URLClassLoader.java:260) at java.net.URLClassLoader.access$000(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at Test$SpecialClassLoader.loadClass(Test.java:40) at Test.main(Test.java:22)
這是正在發生的事情。
當您嘗試加載Test $ Thing時,defineClass方法會指出它需要加載Test $ Thing的超類。 即Test $ SuperThing。
系統類加載器調用您的類加載器,該類加載器返回Nothing類。
系統類加載器說“哇!該類沒有正確的完全合格的類名!”,並拋出NoClassDefFoundError
。
基本上,該系統類加載器可防止破壞JVM穩定性的事物。 如果允許自定義類加載器加載錯誤的類,則可能會發生令人討厭的事情。 例如,考慮在欺騙類加載器加載Nothing類之后,如果某些代碼調用為Test $ SuperThing類定義的某些方法,會發生什么情況。
如果您想做一些骯臟的技巧來代替某個類的虛擬版本,則需要使用正確的完全限定的類名,正確的超類和接口以及具有正確簽名的方法來動態生成字節碼。 簡而言之,您必須滿足二進制兼容性規則。 如果不這樣做,則無論您嘗試在自定義類加載器中執行什么操作,系統類加載器都將拒絕加載您的類。
坦白說,無論您想做什么,都應該采取完全不同的方法。
可以在編譯器的輸出中找到名為Test $ Thing.class的類嗎? 正如此處給出的代碼一樣,它永遠也不會被直接引用,也許編譯器會優化該類。 在這種情況下,反射無法找到該類。
如果是這種情況,您可以簡單地向該類添加一個(非反射)引用,以便對其進行編譯。
編輯:自己嘗試一下之后,我認為我找到了問題的根源。 如果我從Thing聲明中刪除了“ extendeds SuperThing”,它會抱怨找不到java.lang.Object。 可能是,類加載器還嘗試加載所有相關類(包括其擴展的類),但由於未在白名單中而無法加載。 但這是一個理論。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.