我有一个在Eclipse中开发的java应用程序。
系统上有一个包含大量“.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);
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中运行上面的代码,它可以正常工作。当我从其他地方运行应用程序作为jar时,它会为该行抛出
ClassNotFoundException
为什么会这样?它在Eclipse中执行的有什么不同,而不是通过命令行?
答案 0 :(得分:1)
name - 所需类的完全限定名称
因此,为了获得完全限定的类名,您需要操作rulesDir变量以用句点替换反斜杠,然后将其添加到您的ruleName变量,并结合另一个句点,以获取完全限定的类名。然后,您将能够使用ClassLoader加载该类。完全限定名称是必需的,以便ClassLoader可以从类路径的根目录中找到您的资源。
NB我假设你的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文件的相对路径(相当于你的类的包),然后是那个包路径下的实际类名。