[英]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
上面代码的解释:
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.