Re: javax.tools.JavaCompilerTool
On Thu, 25 Oct 2007 11:36:33 GMT, Roedy Green
<see_website@mindprod.com.invalid> wrote, quoted or indirectly quoted
someone who said :
Has anyone found either sample code or a tutorial or even notes on how
to use javax.tools.JavaCompiler to compile generated code on the fly?
Here is some code I wrote trying to understand how this works.
It seem to compile my on-the-fly generated in RAM source code ok,
but I have not figured out how to direct the class file output
somewhere that I can load the code. I will figure this out
eventually, but I thought some of you might enjoy a challenge.
This is one of Sun's more inscrutable bits of code.
/**
* Demonstrate generating Java source code on the fly, compiling it
and
* executing it.<br>
*/
package com.mindprod.example;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
/**
* Demonstrate generating Java source code on the fly, compiling it
* with the JavaCompiler class and executing it.
* Note JavaCompiler is quite different from JavaCompilerTool that was
* released with JDK 1.6 beta, now withdrawn.
* The source code is generated in RAM and never written to disk.
*
* @author Roedy Green
* @version 1.0 2007-10-25
*/
public final class TestJavaCompiler {
// -------------------------- STATIC METHODS
--------------------------
/**
* Compile from within this JVM without spawning javac.exe or a
separate JVM.
*
* @param source points to source, possibly in RAM.
* @return status of the compile, true all went perfectly without
error.
* @throws java.io.IOException if trouble writing class files.
*/
@SuppressWarnings({"JavaDoc"})
private static boolean compile(JavaFileObject... source) {
final JavaCompiler compiler =
ToolProvider.getSystemJavaCompiler();
final JavaCompiler.CompilationTask task =
compiler.getTask(null /* default System.err */,
null /* standard file manager */,
null /* standard DiagnosticListener */,
null /* no options */,
null /* no annotation classes */,
// we must convert JavaFileObject... to Iterable<?
extends JavaFileObject>
Arrays.asList(source) /* source code */);
return task.call();
}
/**
* Compose source for sample Java program on the fly.
*
* @param className name of class you want to generate
* @param expression a an expression involving a and/or b you want
to
* calculate.
* @return text of an on-the-fly composed Java class.
*/
@SuppressWarnings({"SameParameterValue"})
private static String composeAProgram(String className, String
expression) {
final StringBuilder sb = new StringBuilder(1000);
sb.append("package com.mindprod.example;\n");
sb.append("import java.util.Date;\n");
sb.append("public final class ").append(className).append("
implements Calculator\n");
sb.append("{\n");
sb.append("public double calc( double a, double b )\n");
sb.append(" {\n");
sb.append(" return ");
sb.append(expression);
sb.append(";\n");
sb.append(" }\n");
sb.append("public Date whenCompiled()\n");
sb.append(" {\n");
sb.append(" return new Date(");
sb.append(System.currentTimeMillis());
sb.append("L);\n");
sb.append(" }\n");
sb.append("}\n");
return sb.toString();
}
// --------------------------- main() method
---------------------------
/**
* Compose a program on the fly, compile it, and execute it.
*
* @param args not used
* @throws java.io.IOException if problems writing class
files.
* @throws ClassNotFoundException if generated class cannot
be found.
* @throws IllegalAccessException if try to instantiate a
class we are not permitted to access.
* @throws InstantiationException if cant intstantiate class
* @throws java.net.URISyntaxException if malformed class name.
*/
public static void main(String[] args) throws URISyntaxException,
IOException,
ClassNotFoundException,
IllegalAccessException,
InstantiationException {
// compose text of Java program on the fly.
final String programText =
composeAProgram("Hypotenuse", "Math.sqrt( a*a + b*b
)");
System.out.println("PROGRAM TO BE COMPILED");
System.out.println(programText);
// compile it
final boolean status = compile(new
RamJavaFileObject("Hypotenuse", programText));
System.out.println("status of compile: " + status);
// Load class and create an instance.
final Calculator calculator =
(Calculator)
Class.forName("com.mindprod.example.Hypotenuse")
.newInstance();
// execute its methods:
System.out
.println("Hypotenuse.calc( 3, 4 ) is : "
+ calculator.calc(3.0, 4.0));
System.out.println("compiled on: " +
calculator.whenCompiled());
}
}
/**
* Represents the source text of a Java program in RAM.
*/
class RamJavaFileObject extends SimpleJavaFileObject {
/**
* source text of the program to be compiled
*/
private final String programText;
// -------------------------- PUBLIC INSTANCE METHODS
--------------------------
/**
* constructor
*
* @param className class name, without package
* @param programText text of the program.
* @throws java.net.URISyntaxException if malformed class name.
*/
@SuppressWarnings({"SameParameterValue"})
public RamJavaFileObject(String className, String programText)
throws URISyntaxException {
super(new URI(className + ".java"), Kind.SOURCE);
this.programText = programText;
}
/**
* Get the text of the java program
*
* @param ignoreEncodingErrors ignored.
*/
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
return programText;
}
}
--
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com