繁体   English   中英

以编程方式编译java文件

[英]Compile java files programmatically

我知道这已被提出并得到了很多回答,但我仍然没有一个好的解决方案,我仍然不理解某些部分。 所以我需要以编程方式编译* .java文件。

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

是我正在使用和(如预期)编译器为null 现在,我知道我必须使用JDK而不是JRE作为“运行时”,但这是我不明白的事情:仅仅将tools.jar放在应用程序的类路径中并不够那么有权访问Java Compiler API吗? 如果这是真的,那么独立的Java应用程序和基于Web的应用程序之间是否存在(我认为存在)差异。 实际上,我试图从PlayFramework webapp召唤JavaCompiler,所以我想出来,也许这个解决方案(包括tools.jar )只适用于独立应用程序?

我还尝试创建一个自定义的ClassLoader并使用反射调用上面提到的方法,但我得到的所有对于compiler对象都是null

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 / catches。
  • app.classloader()是一个Play方法,它返回App的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-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时我甚至无法获得编译器!

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

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

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

它在文档中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并获取新实例 - 您将拥有自己的编译器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM