advanced.java
← All concepts
Compiler tooling · ch. 13, p. 96

The Java Compiler API

javax.tools exposes javac as a library, so a running JVM can compile source it generated or received, then load the result.

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();

StandardJavaFileManager fm =
    compiler.getStandardFileManager(diagnostics, null, null);

boolean ok = compiler.getTask(
        null, fm, diagnostics, List.of("-d", "out"), null,
        fm.getJavaFileObjectsFromFiles(List.of(new File("Main.java"))))
    .call();

for (Diagnostic<?> d : diagnostics.getDiagnostics()) {
    System.out.printf("%s:%d %s%n", d.getSource(), d.getLineNumber(),
                      d.getMessage(null));
}

getSystemJavaCompiler() returns null on a JRE without the compiler module — always check.

Compiling from memory

Subclass SimpleJavaFileObject to serve source from a String, and wrap the file manager to collect the resulting bytes. Load them with a custom ClassLoader and you have runtime code generation with no temp files.

Why it matters here

This is exactly the mechanism the playground on this site uses. javac is written in Java, so CheerpJ can run it inside the browser’s WebAssembly JVM and compile your code with no server involved.

1 questions on this concept Drill it