Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to programmatically compile java source code in memory only?

I have found many references explaining how to programmatically compile a Java class using the JavaCompiler class:

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, "a_file_name"); 

However, I would like to know if there is an open source library that let me compile source code generated programmatically (therefore without a src file being involved) and generate some byte code in an output stream (without generating a class file in the file system).

For example, I am looking for being able to write something like this:

InputStream input = generateSourceCode(); OutputStream output = getByteCode(input); doCoolStuffWithByteCode(output); 

Thanks for any help.

like image 530
Sergio Avatar asked Nov 03 '11 00:11

Sergio


People also ask

How does Java source code get compiled?

Java source code is compiled into bytecode when we use the javac compiler. The bytecode gets saved on the disk with the file extension . class . When the program is to be run, the bytecode is converted, using the just-in-time (JIT) compiler.

What command is used to compile a Java source program?

Type 'javac MyFirstJavaProgram. java' and press enter to compile your code. If there are no errors in your code, the command prompt will take you to the next line (Assumption: The path variable is set).

Does JVM compile source code?

JVM does not compile the code, it interprets. The instructions in this byte-code cannot be directly run by the CPU. Therefore some other 'program' is needed which can interpret the code, and give the CPU machine level instructions which it can execute. This program is the 'JVM' (Java Virtual Machine).

Can we run Java program without compile?

Starting with Java SE 11 and for the first time in the programming language's history, you can execute a script containing Java code directly without compilation. The Java 11 source execution feature makes it possible to write scripts in Java and execute them directly from the *inx command line.


1 Answers

To start, look at the JavaCompiler API. Basically:

  1. Create the Java class in a string.
  2. Put the string into class that extends SimpleJavaFileObject.
  3. Compile using a JavaCompiler instance.

Finally, call the methods the new class.


Here is an example that works with 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;   } } 
like image 124
James Black Avatar answered Oct 05 '22 23:10

James Black