2016-08-01 72 views
1

我有一個在Eclipse中開發的java應用程序。ClassNotFoundException當在IDE之外運行時

系統上有一個文件夾,其中包含大量「.java」文件。這些「.java」文件是某些用戶編寫的類。我希望加載所有這些Java類並在我的Java應用程序中編譯它們。

所有「.java」文件的另一個屬性是所有寫在裏面的類擴展了一個類,它在我的原始應用程序中。

我用下面的語言來閱讀和編譯所有的類。

File parentFile = new File(rulesDir + "\\"); 
String fileName = rulesDir + "\\" + ruleName + ".java"; 
File ruleFile = new File(fileName); 
// Compile source file. 
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
compiler.run(null, null, null, ruleFile.getPath());    
// Load and instantiate compiled class. 
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { parentFile.toURI().toURL() }); 
Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader); 

如果我運行在Eclipse上面的代碼,它工作正常。當我從運行應用程序作爲一個罐子其他地方,它拋出了線 Class<? extends AbstractRule> cls = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader);

這究竟是爲什麼一個ClassNotFoundException?有什麼不同,它在Eclipse中執行,不通過命令行?

+0

在Eclipse中使用的IDE與您在何處運行JAR的版本相同? 要檢查您的Eclipse JRE,請執行以下操作:單擊「窗口」,然後單擊「首選項」菜單中的「首選項」,選擇已安裝的JRE。 –

+0

在Class.forName之前缺少括號。錯字? – ManoDestra

+1

已修改。這是一個錯字。在eclipse中沒有語法錯誤 – Kaushik

回答

1

從文檔Class.forName

名稱 - 所需類的完全限定名

因此,爲了獲取完整的類名,你需要操縱你的rulesDir變量用句點替換反斜槓,然後將其添加到您的ruleName變量中,並與另一個句點結合,以獲取完全限定的類名。然後你就可以使用ClassLoader來加載類。完全限定名稱是必需的,以便ClassLoader可以從類路徑的根目錄找到您的資源。

注意我假定您的rulesDir是從您的類路徑的基礎的相對路徑。如果不是,那麼你就必須額外操縱在這裏做

見下面的代碼操作:

import java.io.File; 
import java.net.URL; 
import java.net.URLClassLoader; 
import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 
import rules.AbstractRule; 

public class MainApp { 
    public static void main(String[] args) { 
     try { 
      System.out.println("Test"); 
      // NB Amended here to now take project root, relative path to rules directory and class name. So that compilation can take place based on the absolute path and class loading from the relative one. 
      compile("C:\\Media\\Code\\manodestra_java\\src\\tmp", "rules", "TestRule"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    private static void compile(String projectRoot, String rulesDir, String ruleName) throws Exception { 
     File parentFile = new File(projectRoot + "\\" + rulesDir + "\\"); 
     System.out.println(parentFile); 
     String fileName = parentFile.getCanonicalPath() + "\\" + ruleName + ".java"; 
     File ruleFile = new File(fileName); 
     System.out.println(ruleFile); 

     // Compile source file. 
     System.out.println("Compiling..."); 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     compiler.run(null, null, null, ruleFile.getPath()); 

     // Load and instantiate compiled class. 
     System.out.println("Loading class..."); 
     URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { parentFile.toURI().toURL() }); 
     System.out.println("Class Loader: " + classLoader); 
     ruleName = rulesDir.replace("\\", ".") + "." + ruleName; 
     Class<? extends AbstractRule> clazz = (Class<? extends AbstractRule>)Class.forName(ruleName, true, classLoader); 
     System.out.println(clazz); 
    } 
} 

對於我測試的緣故,這個類在默認包定義和我創建該級別下的規則目錄包含AbstractRule的我的子類。所以,rules.TestRule是我的班級名稱的完全合格的路徑。但是,你可能是...

com.example.testapplication.rules.TestRule等

而這正是將在的Class.forName需要。有一條路徑指向你的類路徑根,然後是從那裏到你的java文件(這相當於你的類的包)的相對路徑,然後是該包路徑下的實際類名。

+0

對不起。你的假設是不正確的。 RulesDir是絕對路徑。不是相對路徑。我們將如何解決這種情況? @ManoDestra – Kaushik

+0

我試過你的建議。它現在不適用於eclipse和命令行。但我認爲這是因爲rulesDir是一個相對路徑的假設。 – Kaushik

+0

我在答案中描述瞭如何解決這種情況。您可以指向編譯的絕對路徑,但是您需要指向Class.forName的完全限定路徑,該路徑將是絕對路徑的以句點定界的子集。 – ManoDestra

相關問題