Backend Development 16 min read

Practical Use of Java Dynamic Compilation in Projects

This article explains how Java's dynamic compilation can be applied to modularize and simplify code management in large projects, demonstrates a basic implementation with code examples, and shows how to integrate the technique into Spring Boot applications while addressing class‑loader and dependency challenges.

政采云技术
政采云技术
政采云技术
Practical Use of Java Dynamic Compilation in Projects

Java Dynamic Compilation in Project Practice

Introduction

Most developers have never used Java's dynamic compilation feature; the author encountered it while trying to manage a heterogeneous project that required frequent code changes across many business modules.

To avoid the pain of locating owners for each module and repeatedly releasing the whole application, the author proposed splitting the codebase into small, independently managed code blocks that could be compiled on demand.

1. What Is Dynamic Compilation

1.1 Related Concepts

JavaFileManager: manages files during compilation.

DiagnosticListener: collects compilation diagnostics such as errors and warnings.

JavaFileObject: represents a Java source file or compiled bytecode.

1.2 Simple Implementation Steps

Create a JavaCompiler instance.

Create a DiagnosticCollector to gather diagnostics.

Create a JavaFileManager (e.g., StandardJavaFileManager ).

Create a JavaFileObject that holds the source code.

Obtain a CompilationTask via JavaCompiler.getTask .

Call CompilationTask.call() to compile.

Process the diagnostics and the compilation result.

Example code:

public class DynamicCompiler {
    public static void main(String[] args) throws Exception {
        // Create JavaCompiler
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // Collect diagnostics
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
        // Manage files
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
        // Source code to compile
        String code = "public class HelloWorld { public static void main(String[] args) { System.out.println(\"Hello World!\"); } }";
        JavaFileObject source = new JavaSourceFromString("HelloWorld", code);
        // Prepare compilation units
        Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(source);
        CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
        // Compile
        boolean success = task.call();
        // Output diagnostics
        for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
            System.out.println(d.getMessage(null));
        }
        // Result handling
        if (success) {
            System.out.println("Compilation was successful.");
        } else {
            System.out.println("Compilation failed.");
        }
        fileManager.close();
    }
}

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;
    }
}

Running the program prints:

Hello World!
Compilation was successful.

2. Integrating with a Spring Boot Project

While the simple example works, real projects need to handle more complex scenarios such as dependency resolution and class loading.

2.1 Problems Encountered

2.1.1 Overriding the ClassLoader

Dynamic compilation generates classes at runtime, which the default application class loader cannot load. Therefore a custom ClassLoader (or a subclass) must be provided to define and load the generated bytecode.

2.1.2 Dependency Handling

The Java compiler uses JavaFileManager to locate dependent classes. In a Spring Boot fat‑jar, the default manager cannot read nested JARs, so a custom JavaFileManager is required to expose those dependencies.

2.2 Code Example

Utility method to compile a class and load it with a memory‑based class loader:

public static Class compile(String className, String code) {
    try (MemoryClassLoader loader = MemoryClassLoader.genInstance()) {
        loader.registerJava(className, code);
        return MemoryClassLoader.getInstance().loadClass(className);
    } catch (Exception e) {
        // ignore
    }
    return null;
}

Key components (simplified):

class MemoryClassLoader extends URLClassLoader {
    private static final Map<String, byte[]> classBytes = new ConcurrentHashMap<>();
    // register source code, compile, store byte[] in classBytes
    // override findClass to defineClass from classBytes
    // provide factory methods genInstance(), getInstance()
}

class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
    // stores compiled bytecode in memory
    // overrides getJavaFileForOutput to return a MemoryOutputJavaClassObject
    // overrides list() to supply classes from nested JARs when running inside a Spring Boot jar
}

class SpringJavaFileManager extends JavacFileManager {
    // creates a ClassLoader that can load classes from URLs inside the Spring Boot jar
}

These classes together enable on‑the‑fly compilation of user‑provided snippets, proper handling of Spring Boot's embedded dependencies, and loading of the resulting classes without restarting the application.

Conclusion

Dynamic compilation is not a daily requirement, but in specific situations—such as modular business logic that must be updated without a full redeploy—it provides a clean solution. The article offers a practical reference for implementing this technique in Java backend projects, especially those built with Spring Boot.

JavaSpring BootClassLoaderDynamic CompilationJavaCompilerMemoryClassLoader
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.