2014-05-16 32 views
1

我正在編寫一個程序,它允許用戶將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?

所以最後我的問題,我該如何讓上面的代碼工作?我不想讓我的用戶編寫他們自己的類加載器,並加載一個內部/單獨的類(因爲不是所有用戶在編碼​​時都會一定很驚人),所以我需要能夠引用內部類類型,而不需要代碼炸燬。

回答

0

自從我問起它已經很長時間了,但我在我的代碼和類加載器javadocs之間來回查看,我簡直是愚蠢。

在我的loadClassByName2我調用classLoader.close();如果新加載的類將要加載更多類,則不應該這樣做。

根據javadocs,每個類類型都跟蹤加載它的類加載器。如果這個類的類型需要引用一個未加載的類,它會調用它的類加載器來查找並加載它。當我加載單個類後立即關閉類加載器時,我做了這樣的事情,類加載器無法找到/加載任何其他類(包括本地/內部類)。