DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Java Enterprise Is Already Ready for the AI Era
  • Orchestration Meets MCP: Building Governed Agentic Workflows With Quarkus Flow and AGENTS.md
  • I Built a Java Version Manager by Fixing Other Tools' Open Bugs
  • Arrays in Java

Trending

  • From Microservices to Agent Services: The Next Architectural Shift
  • Vector Database Indexing Explained: Why It Matters More Than the Embeddings Themselves
  • The AI Memory Security Blueprint
  • Member Spotlight: Pavan Belagatti
  1. DZone
  2. Coding
  3. Java
  4. How to Generate and Compile Sources at Runtime in Java

How to Generate and Compile Sources at Runtime in Java

In this article, learn how to generate and compile sources at runtime in Java with and without class loading.

By 
Marion Keely user avatar
Marion Keely
·
Feb. 03, 21 · Tutorial
Likes (9)
Comment
Save
Tweet
Share
12.3K Views

Join the DZone community and get the full member experience.

Join For Free

With ClassFactory, it is possible to generate classes at runtime, but how can we do that if we only need to compile sources without loading them or just generating sources?

Here come the source code generator components and the JavaMemoryCompiler of Burningwave Core to our aid. With source code generators, we can generate source code and store it on the drive or compile it via the JavaMemoryCompiler.

Now, let's try to generate and store the following class:

Java
 




x


 
1
package source.generation.test;
2

          
3
import java.util.Arrays;
4
import java.util.List;
5

          
6
public class MyClass {
7
    
8
    
9
    private List<String> words;
10
    
11
    public MyClass(String... words) {
12
        this.words = Arrays.asList(words);
13
    }
14
    
15
    public void print() {
16
        System.out.print(String.join(" ", words));
17
    }
18
    
19
    public static void main(String[] args) {
20
        new MyClass(args).print();
21
    }
22
}


With the source code generators:

Java
 




xxxxxxxxxx
1
60


 
1
package source.generation.test;
2

          
3
import java.lang.reflect.Modifier;
4
import java.util.Arrays;
5
import java.util.List;
6

          
7
import org.burningwave.core.classes.ClassSourceGenerator;
8
import org.burningwave.core.classes.FunctionSourceGenerator;
9
import org.burningwave.core.classes.GenericSourceGenerator;
10
import org.burningwave.core.classes.TypeDeclarationSourceGenerator;
11
import org.burningwave.core.classes.UnitSourceGenerator;
12
import org.burningwave.core.classes.VariableSourceGenerator;
13

          
14
public class SourceGenerationTester {
15

          
16
    
17
    public static UnitSourceGenerator generate() {
18
        return UnitSourceGenerator.create(SourceGenerationTester.class.getPackage().getName())
19
        .addClass(
20
            ClassSourceGenerator.create(TypeDeclarationSourceGenerator.create("MyClass"))
21
            .addField(
22
                VariableSourceGenerator.create(
23
                    TypeDeclarationSourceGenerator.create(List.class)
24
                    .addGeneric(GenericSourceGenerator.create(String.class)),
25
                    "words"
26
                )
27
            )
28
            .addConstructor(
29
                FunctionSourceGenerator.create().addParameter(
30
                    VariableSourceGenerator.create(
31
                        TypeDeclarationSourceGenerator.create(String.class)
32
                        .setAsVarArgs(true),
33
                        "words"
34
                    )
35
                ).addBodyCodeLine("this.words = Arrays.asList(words);").useType(Arrays.class)
36
            )
37
            .addMethod(
38
                FunctionSourceGenerator.create("print")
39
                .addModifier(Modifier.PUBLIC).setReturnType(void.class)
40
                .addBodyCodeLine(
41
                  "System.out.println(\"\\n\\t\" + String.join(\" \", words) + \"\\n\");"
42
                )
43
            )
44
            .addMethod(
45
                FunctionSourceGenerator.create("main")
46
                .addModifier(Modifier.PUBLIC | Modifier.STATIC)
47
                .setReturnType(void.class)
48
                .addParameter(VariableSourceGenerator.create(String[].class, "args"))
49
                .addBodyCodeLine("new MyClass(args).print();")
50
            )
51
        );
52
    }
53
    
54
    
55
    public static void main(String[] args) {
56
        UnitSourceGenerator unitSG = SourceGenerationTester.generate();
57
        unitSG.storeToClassPath(System.getProperty("user.home") + "/Desktop/sources");
58
        System.out.println("\nGenerated code:\n" + unitSG);
59
        
60
    }
61
}
62

          


And now let's try to compile the sources and store the compiled files with JavaMemoryCompiler:

Java
 




x
9
38


 
1
package source.compilation.test;
2

          
3

          
4
import org.burningwave.core.assembler.ComponentContainer;
5
import org.burningwave.core.classes.JavaMemoryCompiler;
6
import org.burningwave.core.classes.JavaMemoryCompiler.Compilation;
7
import org.burningwave.core.concurrent.QueuedTasksExecutor.ProducerTask;
8
import org.burningwave.core.io.FileSystemItem;
9

          
10
import source.generation.test.SourceGenerationTester;
11

          
12
public class SourceCompilationTester {
13
    
14
    
15
    public static void main(String[] args) throws ClassNotFoundException {
16
        ComponentContainer componentContainer = ComponentContainer.getInstance();
17
        JavaMemoryCompiler javaMemoryCompiler = componentContainer.getJavaMemoryCompiler();
18
        ProducerTask<Compilation.Result> compilationTask = javaMemoryCompiler.compile(
19
            Compilation.Config.forUnitSourceGenerator(
20
                SourceGenerationTester.generate()
21
            )
22
            .storeCompiledClassesTo(
23
                System.getProperty("user.home") + "/Desktop/classes"
24
            )
25
        );
26
        
27
        Compilation.Result compilationResult = compilationTask.join();
28
        
29
        System.out.println("\n\tAbsolute path of compiled file: " + 
30
            compilationResult.getClassPath()
31
            .findFirstInAllChildren(
32
                FileSystemItem.Criteria.forAllFileThat(FileSystemItem::isFile)
33
            ).getAbsolutePath() + "\n"
34
        );
35
    }
36
    
37
}


And now let's try to load the compiled file:

Java
 




xxxxxxxxxx
1
37


 
1
package source.compilation.test;
2

          
3
import static org.burningwave.core.assembler.StaticComponentContainer.ClassLoaders;
4
import static org.burningwave.core.assembler.StaticComponentContainer.Methods;
5

          
6
import org.burningwave.core.assembler.ComponentContainer;
7
import org.burningwave.core.classes.JavaMemoryCompiler;
8
import org.burningwave.core.classes.JavaMemoryCompiler.Compilation;
9
import org.burningwave.core.concurrent.QueuedTasksExecutor.ProducerTask;
10

          
11
import source.generation.test.SourceGenerationTester;
12

          
13
public class SourceCompilationTester {
14
    
15
    
16
    public static void main(String[] args) throws ClassNotFoundException {
17
        ComponentContainer componentContainer = ComponentContainer.getInstance();
18
        JavaMemoryCompiler javaMemoryCompiler = componentContainer.getJavaMemoryCompiler();
19
        ProducerTask<Compilation.Result> compilationTask = javaMemoryCompiler.compile(
20
            Compilation.Config.forUnitSourceGenerator(
21
                SourceGenerationTester.generate()
22
            )
23
            .storeCompiledClassesTo(
24
                System.getProperty("user.home") + "/Desktop/classes"
25
            )
26
        );
27
        
28
        Compilation.Result compilattionResult = compilationTask.join();
29
        
30
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
31
        ClassLoaders.addClassPaths(classLoader, compilattionResult.getDependencies());
32
        ClassLoaders.addClassPath(classLoader, compilattionResult.getClassPath().getAbsolutePath());
33
        Class<?> cls = classLoader.loadClass("source.generation.test.MyClass");
34
        Methods.invokeStaticDirect(cls, "main", new Object[] {new String[] {"Hello", "world!"}});
35
    }
36
    
37
}


Conclusion

In this tutorial, we learned how to generate and compile sources and how to load the generated class files. You can do a lot of things that are not mentioned here like, for example, compile sources that references classes located outside the runtime class paths. If you are curious or need further help, you can request it at the official forum.

Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • Java Enterprise Is Already Ready for the AI Era
  • Orchestration Meets MCP: Building Governed Agentic Workflows With Quarkus Flow and AGENTS.md
  • I Built a Java Version Manager by Fixing Other Tools' Open Bugs
  • Arrays in Java

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook