我知道这个问题已经被问了很多次并得到了答案,但我仍然没有一个好的解决方案,也不理解其中的一些部分。因此,我的要求是以编程方式编译*.java文件。
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
我使用的是JRE,而(如预期)编译器为null
。 我知道必须使用JDK而不是作为“运行时”的JRE,但有些事情我不明白:只需将tools.jar
放入应用程序的类路径中,就可以访问Java Compiler API了吗? 如果是这样,那么独立的Java应用程序和基于Web的应用程序之间是否有区别(我认为有)。
实际上,我正在尝试从PlayFramework Web应用程序中调用JavaCompiler,因此我想,也许这种解决方案(包括tools.jar
)仅适用于独立应用程序?
我还尝试创建自定义ClassLoader并使用反射调用上述方法,但我得到的只是null
的compiler
对象:
ClassLoader classloader = app.classloader();
File file = new File("lib/tools.jar");
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
ClassLoader newCL = new URLClassLoader(urls, classloader) {
};
Class<?> loadClass = newCL.loadClass("javax.tools.ToolProvider");
Method method = loadClass.getMethod("getSystemJavaCompiler", null);
Object object = method.invoke(null);
System.out.println("Object: " + object); // NULL
上面代码的解释:
- 出于简单起见,我没有包含try / catch块。
- app.classloader()是Play方法,返回应用程序的ClassLoader
tools.jar
已包含在Play项目的lib文件夹中(这意味着根据Play文档,它在项目的类路径上)。
我很确定在Play能够加载Java编译器类之前还需要做些其他事情,但我不知道缺少什么。
像 Runtime.exec("javac myFile.java")
和 Eclipse JDT编译器等选项对我来说都很熟悉,但这不是我在寻找的。
哦,还有类似于 System.setProperty("java.home", "PATH_TO_YOUR_JDK");
然后 ToolProvider.getSystemJavaCompiler();
这样的解决方案可以工作,但我认为这个解决方案太丑陋了。
最好的祝福
编辑:(提供额外信息并反映最新状态) 这是Web应用程序结构的基本表示:
myApp
|-conf\...
|-lib\MyJar.jar
|-lib\tools.jar
|-logs\...
|-...
MyJar.jar现在带有一个META-INF/MANIFEST.MF
文件,其内容如下:
Manifest-Version: 1.0
Sealed: true
Main-Class: here.comes.my.main.class
Class-Path: tools.jar
在不启动Play应用程序的情况下,我试图(在lib
文件夹中): java -jar MyJar.jar
-我的简单main
方法尝试调用编译器(ToolProvider.getSystemJavaCompiler();
),并返回null
。因此,这使我相信问题与Play无关-即使正常运行我的Jar也无法获得编译器!