Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compile code fully in memory with javax.tools.JavaCompiler [duplicate]

I'm using the JavaCompiler from the javax.tools package (JDK 1.7) to compile some stuff on the fly, like this:

compiler.run(null, null, "-cp", paths, "path/to/my/file.java");

It works but I would like to do it all in memory (e.g. pass a string with the code, not the source file, and get the byte code back not a .class file). I found that extending the InputStream and OutputStream parameters is no use since it's probably just the same as in the console. Do you know a way to make the run method work like this? Or do you know a confirmed way to do this with the getTask() method? (extending the FileManager looks easy but isn't that easy :)

like image 653
Sandman Avatar asked Aug 29 '12 08:08

Sandman


2 Answers

I've run the above code in Mac OS Java 7. None of them works. So i wrote one https://github.com/trung/InMemoryJavaCompiler

StringBuilder source = new StringBuilder()
    .append("package org.mdkt;\n")
    .append("public class HelloClass {\n")
    .append("   public String hello() { return \"hello\"; }")
    .append("}");

Class<?> helloClass = InMemoryJavaCompiler.compile("org.mdkt.HelloClass", source.toString());
like image 59
trung Avatar answered Nov 15 '22 13:11

trung


I think this here might be of help it basically shows how to compile Java source from memory (the string is located in the class).

It uses the PrinterWriter and StringWriter to write the source to a String/in memory and then uses the JavaCompiler class (since JDK 6) to compile and run the program:

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;


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 {

          URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { new File("").toURI().toURL() });
          Class.forName("HelloWorld", true, classLoader).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;
  }
}

If you have a look at the reference link you will find a few more other examples too

Reference:

  • Compiling from Memory
like image 33
David Kroukamp Avatar answered Nov 15 '22 15:11

David Kroukamp