我知道这已经被问了很多,但我仍然没有一个好的解决方案,我仍然不明白某些部分。所以我需要以编程方式编译 *.java 文件。
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
是我正在使用的,并且(如预期的那样)编译器是null
. 现在,我确实知道我必须使用 JDK 而不是 JRE 作为“运行时”,但这里有一些我不明白的地方:仅仅放入tools.jar
应用程序的类路径然后访问还不够吗?到 Java 编译器 API?如果这是真的,那么独立的 Java 应用程序和基于 Web 的应用程序之间是否存在(我认为存在)差异。实际上,我正在尝试从 PlayFramework webapp 调用 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() 是一个播放方法,它返回 App 的 ClassLoader
tools.jar
包含在 Play 项目的我的 lib 文件夹中(这意味着它位于项目的类路径中 - 根据 Play 文档)
我很确定在 Play 能够加载 Java Compiler 类之前我还需要做一些其他事情,我只是不知道我缺少什么。
我知道像 Eclipse JDT 编译器这样的选项Runtime.exec("javac myFile.java")
,但这不是我想要的。
System.setProperty("java.home", "PATH_TO_YOUR_JDK");
哦,然后类似的东西ToolProvider.getSystemJavaCompiler();
正在工作,但我发现这个解决方案太难看了。
此致
编辑:(提供更多信息并反映最后状态)这是 web-app-structure 的基本表示:
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
方法尝试调用 Compiler ( ToolProvider.getSystemJavaCompiler();
) 并返回null
. 所以这让我相信,这个问题与 Play 无关——在正常运行我的 Jar 时,我什至无法获得编译器!