I know this has been asked and answered a lot but I still don't have a good solution and I still don't understand some parts. So I have the requirement to compile *.java files programmatically.
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
is what I'm using and (as expected) the compiler is null
.
Now, I do know that I have to use the JDK and not the JRE as a "runtime", but here is something I don't understand: isn't it enough to just put tools.jar
in the classpath of the application and then have access to the Java Compiler API? If this is true, is there (I think there is) difference between a stand-alone java application and web-based application.
Actually, I am trying to summon the JavaCompiler from a PlayFramework webapp so I figured out, maybe this solutions (with including the tools.jar
) only works for stand-alone applications?
I also tried to create a custom ClassLoader and invoke the above mentioned method with reflection but all I am getting is null
for the compiler
object:
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
Explanation for the code above:
- I haven't included try/catches for the sake of simplicity.
- app.classloader() is a Play-method which returns the ClassLoader of the App
tools.jar
is included in my lib folder of the Play project (this implies that it is on the project's classpath - according to the Play documentation)
I am pretty sure there is something else I need to do before Play is able to load the Java Compiler class I just don't know what I am missing.
Options like Runtime.exec("javac myFile.java")
and the Eclipse JDT compiler are known to me, but that's not what I am looking for.
Oh, and something like System.setProperty("java.home", "PATH_TO_YOUR_JDK");
and then ToolProvider.getSystemJavaCompiler();
is working but I find this solution so ugly.
Best regards
EDIT: (to give additional information and reflect the last status) This is a basic representation of web-app-structure:
myApp
|-conf\...
|-lib\MyJar.jar
|-lib\tools.jar
|-logs\...
|-...
MyJar.jar has now a META-INF/MANIFEST.MF
file with the following content:
Manifest-Version: 1.0
Sealed: true
Main-Class: here.comes.my.main.class
Class-Path: tools.jar
Without starting the Play app, I am trying (in the lib
folder): java -jar MyJar.jar
- my simple main
method tries to invoke the Compiler (ToolProvider.getSystemJavaCompiler();
) and returns null
. So this leads me to believe, that the problem has nothing to do with Play - I can't even get a Compiler when normally running my Jar!