Generating and Compiling Java Classes using Java Compiler API

Steps :

  • Construct JavaFileObject from any source (i.e, here, from sourceCode String) and make it to iterable object
  • Get the Java System Compiler
  • Create a compiler task using Compiler.getTask(), (if required create the task with diagnostic collection to get compilation errors)
  • Execute the Compiler Task (compile it).

Source Code :

import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Locale;

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.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class CompileDynamicClasses {

static String sourceCode = "class DynamicClass{" + "public static void main (String args[]){"
+ "System.out.println (\"Hello, Dynamic Class!\");" + "}" + "}";

public static void main(String[] args) {

// Construct a JavaFileObject from source code
SimpleJavaFileObject fileObject = new DynamicJavaSourceCodeObject("DynamicClass",
sourceCode);

// Pack into Iterable compilationunits
JavaFileObject javaFileObjects[] = new JavaFileObject[] { fileObject };
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(javaFileObjects);

/*
* // Construct compiler options, if needed String[] compileOptions =
* new String[] { "-d", "bin" }; Iterable<String> compilationOptionss =
* Arrays.asList(compileOptions);
*/

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

// Use StandardJavaFileManager to customize how a compiler reads and
// writes to files.
StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, Locale.getDefault(), null);

// DiagnosticCollector used to collect compilation problems
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

/*
* // With Compiler options CompilationTask compilerTask =
* compiler.getTask(null, stdFileManager, diagnostics,
* compilationOptionss, null, compilationUnits);
*/

CompilationTask compilerTask = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);

boolean status = compilerTask.call();
if (!status) {// If compilation error occurs
/* Iterate through each compilation problem and print it */
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
System.out.format("Error on line %d in %s", diagnostic.getLineNumber(), diagnostic);
}
}
try {
stdFileManager.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Successfully Compiled!...");
}
}

/**
* Creates a dynamic source code file object
*/
class DynamicJavaSourceCodeObject extends SimpleJavaFileObject {
private String qualifiedName;
private String sourceCode;

/**
* Converts the name to an URI, as that is the format expected by
* JavaFileObject
*/
protected DynamicJavaSourceCodeObject(String name, String code) {
super(URI.create("string:///" + name.replaceAll("\\.", "/") + Kind.SOURCE.extension), Kind.SOURCE);
this.qualifiedName = name;
this.sourceCode = code;
}

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return sourceCode;
}

public String getQualifiedName() {
return qualifiedName;
}

public void setQualifiedName(String qualifiedName) {
this.qualifiedName = qualifiedName;
}

public String getSourceCode() {
return sourceCode;
}

public void setSourceCode(String sourceCode) {
this.sourceCode = sourceCode;
}
}

3 thoughts on “Generating and Compiling Java Classes using Java Compiler API

  1. Thanks, I already put that into “code” tag, but my theme doesn’t support proper code formatting. Let me fix this soon.

Leave a comment