以编程方式编译java文件



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

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

是我正在使用的,并且(如预期的那样)编译器是null。现在,我确实知道我必须使用JDK而不是JRE作为"运行时",但这里有一些我不理解的东西:仅仅将tools.jar放在应用程序的类路径中,然后访问Java编译器API还不够吗?如果这是真的,那么独立的java应用程序和基于web的应用程序之间是否存在(我认为存在)区别?实际上,我正试图从PlayFramework web应用程序召唤javaccompiler,所以我弄清楚了,也许这个解决方案(包括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/catch。
  • App . ClassLoader()是一个play方法,它返回应用
  • 的ClassLoader。tools.jar包含在Play项目的lib文件夹中(这意味着它在项目的类路径上-根据Play文档)

我很确定在播放能够加载Java编译器类之前还有别的事情我需要做,我只是不知道我错过了什么。

我知道Runtime.exec("javac myFile.java")和Eclipse JDT编译器这样的选项,但这不是我想要的。

哦,像System.setProperty("java.home", "PATH_TO_YOUR_JDK");,然后ToolProvider.getSystemJavaCompiler();是工作的,但我发现这个解决方案太丑了。

问好

EDIT:(给出附加信息并反映最后状态)这是web-app-structure的基本表示:

myApp
|-conf...
|-libMyJar.jar
|-libtools.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时得到编译器!

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

你不应该把tools.jar打包到你的webapp类路径中。Java中的类装入器通常只能自下而上地工作。因此,作为jdk一部分的工具提供程序不会在webapp类路径中看到你的tools.jar(它不能向下查看webapp类路径)。

解决方案:使用JDK并确保指向它,或者将tools.jar放在Java ext目录中。您可以通过设置属性-Djava.ext来覆盖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);

where defaultJavaCompilerName = "com.sun.tools.javac.api.JavacTool"

将其子类化为JavaCompiler并获得新的实例-您将拥有您的编译器

相关内容

  • 没有找到相关文章

最新更新