2011-02-17 94 views
0

我正在使用命令行應用程序在運行時加載用戶指定的文本翻譯器(通過命令行參數提供的類文件路徑/ jar)。基本上我採取了這一論點,並用它來創建一個URLClassLoader。然後,我需要找到可用於實現Transable接口的URLClassloader的所有類。Java,獲得實現特定接口的URLClassLoader的所有類

現在我只允許這個命令行arg是一個包含類文件的目錄。使解決方案非常簡單(下面的代碼)。但老實說,我不喜歡解決方案,因爲它打破了jar文件,jar文件的目錄等等。另外,這對於具有定義的包的任何類來說都是明顯的失敗,因爲loadClass需要包含包的全名。任何人都有更好的方法?

File d = new File(path); 
    if(d.isDirectory()) { 
     URL url = d.toURI().toURL(); 
     ClassLoader cl = new URLClassLoader(new URL[]{url}); 

     FilenameFilter filter = new FilenameFilter() { 
      @Override 
      public boolean accept(File dir, String name) { 
       return name.endsWith(".class"); 
      } 
     }; 

     for(File f : d.listFiles(filter)) { 
      String name = f.getName().substring(0, f.getName().indexOf(".")); 
      String key = ""; 
      if(name.endsWith("Translator")) { 
       key = name.substring(0, name.indexOf("Translator")); 
      } 
      else if(name.endsWith("translator")) { 
       key = name.substring(0, name.indexOf("translator")); 
      } 
      else 
       key = name; 

      Class c = cl.loadClass(name); 
      if(Transable.class.isAssignableFrom(c)) { 
       Transable t = (Transable)c.newInstance(); 
       env.registerTranslator(key, t); 
      } 
      else { 
       System.out.println("[ClassLoader] "+c.getCanonicalName()+" will not be loaded. It is not a translator class"); 
      } 
     } 
    } 
    else { 
     throw new Error("NOT IMPLEMENTED"); 
    } 
+0

只需進入jar文件並檢查所有條目。 – irreputable 2011-02-17 00:32:17

回答

3

如果你繼續沿着這條路走下去,你可能只需要暴力。據我所知,默認的類加載器甚至不會將類加載到JVM中,除非它以某種方式被引用。這意味着,除非你知道他們完全合格的類名來加載它們,否則你的一些類基本上是不可見的。

您可能想重新考慮您的要求。因爲加載一組您已被授予類名稱的譯員將更加容易。

+0

我正在考慮將其中的一些內容移到一個需要顯式名稱的配置文件,或者至少是包含翻譯器類的包的名稱。它是一個更好的方法,我只是想確保其他選項不能先清理乾淨。 – jdc0589 2011-02-17 00:14:56

+0

@ jdc0589 JAR和本地文件有解決方案,但AFAIK不是任何類加載器的通用解決方案。 – biziclop 2011-02-17 00:18:18

+0

照顧詳細?我只關心本地文件和本地文件夾 – jdc0589 2011-02-17 03:45:23

0

這會有幫助嗎?

由於類c = cl.loadClass(name);

類方法getInterfaces()返回的類

檢查匹配翻譯類名每個類名稱的數組。

3

原則上這不適用於任意類加載器,因爲它們可能以任何可以想象的方式實際加載類,並且根本沒有任何「目錄監聽」函數。

類加載器甚至可能產生在飛行類(即字節代碼的類)每當loadClass來了,和想象TransableClassloader每個這樣的自動定義的類將實現你的界面 - 你的程序將永遠不會結束。


這就是說,對於一個URLClassloader您可以使用getURLs(),併爲jar:file: URL可以使用JarFileFile API來獲取文件名列表(因此類名)來嘗試。由於您擁有URL中給出的包層次結構的根目錄,因此找到正確的包名並不困難。

(如果你需要更多的細節,說出來。)


編輯:對於包名,它們對應於您的層次結構內的目錄名。所以,當你有一個對應於(說)dir/classes的基礎URL,並找到一個名爲dir/classes/com/company/gui/SimpleTranslator.class的類文件時,它對應於類com.company.gui.SimpleTranslator

因此,刪除基地前綴並將/替換.(並剪切.class)。 (在JarFile中,您不必刪除前綴)

實際上,如果您使用遞歸方法來遍歷文件層次結構,則可以使用相同的方法構建包名,只需通過追加字符串(給他們作爲參數傳遞給下一個遞歸調用):

public void searchClassesInDir(File dir, String packagePrefix) { 
    if(dir.isDirectory()) { 
     String prefix = packagePrefix + dir.getName() + "."; 
     for(File f : dir.listFiles()) { 
      searchClasses(f, prefix); 
     } 
    } 
    else { 
     String fileName = dir.getName(); 
     if(! fileName.endsWith(".class")) 
      return; 
     String className = packagePrefix + fileName.substring(0, fileName.length()-".class".length()); 
     // now do the rest of your processing 
    } 
} 

searchClasses(new File(url.toURI()), ""); 
4

而是明確地尋找實現者,你應該USS Java的服務提供者接口(SPI)和ServiceLoader類(在Java 6中引入)。 SPI是一種非常標準的方式來執行您在Java中描述的內容。

關於如何創建服務提供者以及如何在運行時使用ServiceLoader,請參閱official Java tutorial

相關問題