我正在編寫一個程序,它允許用戶將java代碼輸入到文本區域,然後將其編譯並作爲一種「插件」加載到程序中。我目前能夠編譯.java文件並加載外部類,但是我無法加載/實例化用戶編寫的內部類而沒有錯誤。目前,這是我用來加載外部類的代碼,這個代碼可以工作,並且我能夠輕鬆地使用外部類而不會有任何複雜的問題。 (我做了一些修改以提高可讀性,如果你發現一個錯字告訴我)使用類加載器加載內部類
private ArrayList<String> execute(ArrayList<String> fileNames) {
ArrayList<String> successStories = new ArrayList();
ArrayList<Class<?>> eventHandlers = new ArrayList();
// Load all classes first...
for (int i = 0; i < fileNames.size(); i++) {
Class<?> clazz = loadClassByName2(fileNames.get(i));
if (EventHandler.class.isAssignableFrom(clazz)) {
eventHandlers.add(clazz);
successStories.add(fileNames.get(i));
} else if (InterfaceInnerClass.class.isAssignableFrom(clazz)) {
successStories.add(fileNames.get(i));
} else {
System.out.println(clazz.getName() + " couldn't be loaded");
}
}
// Then instantiate the handlers.
for (int i = 0; i < eventHandlers.size(); i++) {
try {
Object obj = eventHandlers.get(i).newInstance();
if (obj instanceof EventHandler) {
EventHandler EH = (EventHandler)obj;
EH.name = EH.getClass().getSimpleName();
CmdEvents.addEvent(EH);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return successStories;
}
public static Class<?> loadClassByName2(String name) {
try {
// My program sets up classpath environment variables so "./" is all that is needed as the URL
URLClassLoader classLoader = new URLClassLoader(
new URL[] { new File("./").toURI().toURL() });
// Load the class from the classloader by name....
Class<?> c = classLoader.loadClass("plugins.event_handlers." + name);
classLoader.close();
return c;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
文件名的原始列表是從一個GUI發送與中列出的插件目錄中每一個.class文件。用戶選擇他們要加載的類,單擊一個按鈕,然後將這些文件名發送到這些方法。在這段代碼中,EventHandler是一個你將在下面看到的類,InterfaceInnerClass只是一個用作標籤的接口,以確保沒有任何嚴重問題,並且CmdEvents是用於管理這些「插件」類的程序中的一個控制檯命令。就像我上面所說的那樣,這段代碼對於外層類很好,問題是當我嘗試加載內層類時。我的EventHandler抽象類的代碼如下。
public abstract class EventHandler {
public String name; // Don't mind this being public, I have my reasons for this.
public abstract void execute(String input);
public abstract boolean condition(String input);
}
我的程序的工作方式,它臨危來自用戶的字符串,然後調用條件(字符串),如果返回true,則調用執行(字符串)。我寫了一些測試代碼來嘗試我的裝載程序如下。
package plugins.event_handlers;
public class Test_Handler extends events.EventHandler {
public void execute(String input) {
System.out.println("Testing...");
TestInner inner = new TestInner();
inner.test();
System.out.println("Did it work?");
}
public boolean condition(String input) {
return input.contains("testinput");
}
public class TestInner implements events.InterfaceInnerClass {
public TestInner() {
System.out.println("The inner works!");
}
public void test() {
System.out.println("Inner class has been tested");
}
}
}
我跑我的程序,同時選擇Test_Handler.class和Test_Handler $ TestInner.class,然後點擊按鈕。當該方法返回一個ArrayList或成功加載的類時,它將返回BOTH外部類和內部類。但是,當我運行程序並將「testinput」傳遞給條件並執行方法時,這是我的輸出。
Testing... Exception in thread "Execute_Thread_Test_Handler" java.lang.NoClassDefFoundError: plugins/event_handlers/Test_Handler$TestInner at plugins.event_handlers.Test_Handler.execute(Test_Handler.java:11) at events.ThreadEventExecutor.run(ThreadEventExecutor.java:20) Caused by: java.lang.ClassNotFoundException: plugins.event_handlers.Test_Handler$TestInner at java.net.URLClassLoader$1.run(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) ... 2 more
什麼,我想它要打印的是
Testing... The inner works! Inner class has been tested Did it work?
所以最後我的問題,我該如何讓上面的代碼工作?我不想讓我的用戶編寫他們自己的類加載器,並加載一個內部/單獨的類(因爲不是所有用戶在編碼時都會一定很驚人),所以我需要能夠引用內部類類型,而不需要代碼炸燬。