10

我知道这已经被问了很多,但我仍然没有一个好的解决方案,我仍然不明白某些部分。所以我需要以编程方式编译 *.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 时,我什至无法获得编译器!

4

2 回答 2

1

Web 应用程序和独立应用程序之间没有区别。

您不应该将 tools.jar 打包到您的 webapp 类路径中。Java 中的类加载器通常只能自下而上工作。因此,作为 jdk 一部分的 ToolProvider 不会在 webapp 类路径中看到您的 tools.jar(它不能向下查看 webapp 类路径)。

解决方案:使用 JDK 并确保指向它或将 tools.jar 放在 Java ext 目录中。您可以通过将属性 -Djava.ext.dir 设置为您喜欢的任何目录来覆盖 ext 目录。

于 2013-04-18T13:18:09.703 回答
0

它在文档中说您是To run the Play framework, you need JDK 6 or later.如何设法使用 jre 运行它的?

无论如何,如果getSystemJavaCompiler返回 null 这意味着您tools.jar的类路径中没有或它已损坏。如果是 Sun/Oracle java,请确保其中包含com.sun.tools.javac.api.JavacTool类。

如果您想使用自定义类加载器,您需要加载的是 JavacTool 类,而不是 ToolProvider。看看它在 java 6 中的执行方式:

        URL[] urls = {file.toURI().toURL()};
        ClassLoader cl = URLClassLoader.newInstance(urls);
        cl.setPackageAssertionStatus("com.sun.tools.javac", true);
        return Class.forName(defaultJavaCompilerName, false, cl);

在哪里defaultJavaCompilerName = "com.sun.tools.javac.api.JavacTool"

将其子类化JavaCompiler并获取新实例 - 你将拥有你的编译器。

于 2013-03-31T18:21:44.947 回答