programacion - ¿Es posible compilar programáticamente el código fuente de Java en la memoria solamente?
fases de compilacion de java (3)
Dimos una charla sobre este caso de uso en JavaOne 2016 (la pregunta es un poco antigua, pero parece que todavía hay algo de interés).
Hay un repository con ejemplos de generación de código práctico utilizando javac en memoria.
Mire específicamente a SimpleJavaCompiler para ver un ejemplo sobre cómo hacer esto en la memoria que se ocupa de la seguridad de subprocesos (lo usamos en el contexto de un servidor) para una sola clase. Fácilmente podría ser adaptado para un escenario multi-clase.
También hay clases para tratar la carga de clases y la generación de código (alcance de variables, generación de nombres únicos, sombreado de nombres, etc.).
He encontrado muchas referencias que explican cómo compilar mediante programación una clase Java utilizando la clase JavaCompiler
:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, "a_file_name");
Sin embargo, me gustaría saber si hay una biblioteca de código abierto que me permita compilar el código fuente generado mediante programación (por lo tanto, sin que esté involucrado un archivo src) y generar algún código de bytes en una secuencia de salida (sin generar un archivo de clase en el sistema de archivos). ).
Por ejemplo, estoy buscando poder escribir algo como esto:
InputStream input = generateSourceCode();
OutputStream output = getByteCode(input);
doCoolStuffWithByteCode(output);
Gracias por cualquier ayuda.
Los JavaDocs son tus amigos:
http://download.oracle.com/javase/6/docs/api/javax/tools/JavaCompiler.html
Mira la última sección que se refiere a SimpleJavaFileObject
; le muestra cómo usarlo junto con el código almacenado en una String
Para empezar, mira la API de JavaCompiler . Básicamente:
- Crear la clase de Java en una cadena.
- Ponga la cadena en la clase que extiende SimpleJavaFileObject .
- Compilar utilizando una instancia de
JavaCompiler
.
Finalmente, llama a los métodos la nueva clase.
Aquí hay un example que funciona con JDK6 +:
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.Arrays;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject.Kind;
public class CompileSourceInMemory {
public static void main(String args[]) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
out.println("public class HelloWorld {");
out.println(" public static void main(String args[]) {");
out.println(" System.out.println(/"This is in another java file/");");
out.println(" }");
out.println("}");
out.close();
JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString());
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);
boolean success = task.call();
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
System.out.println(diagnostic.getCode());
System.out.println(diagnostic.getKind());
System.out.println(diagnostic.getPosition());
System.out.println(diagnostic.getStartPosition());
System.out.println(diagnostic.getEndPosition());
System.out.println(diagnostic.getSource());
System.out.println(diagnostic.getMessage(null));
}
System.out.println("Success: " + success);
if (success) {
try {
Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class })
.invoke(null, new Object[] { null });
} catch (ClassNotFoundException e) {
System.err.println("Class not found: " + e);
} catch (NoSuchMethodException e) {
System.err.println("No such method: " + e);
} catch (IllegalAccessException e) {
System.err.println("Illegal access: " + e);
} catch (InvocationTargetException e) {
System.err.println("Invocation target: " + e);
}
}
}
}
class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace(''.'',''/'') + Kind.SOURCE.extension),Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}