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

  • HTTP QUERY in Java: The Missing Method for Complex REST API Searches
  • OBO SSO in Java Applications: Securely Calling Downstream APIs on Behalf of a User
  • Jakarta NoSQL: Why JPA Is Not Enough for the AI Era
  • Top Java Security Vulnerabilities and How to Prevent Them in Modern Java

Trending

  • Building Production-Grade Delta Lake Pipelines With Apache Spark on Databricks
  • If You Can Write Acceptance Criteria, You Can Write an AI Routing Policy
  • Multi-Agent Software Engineering: One Coding Agent Isn't Enough
  • The New Senior Developer Job Description: Half Engineer, Half AI Systems Architect
  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

  • HTTP QUERY in Java: The Missing Method for Complex REST API Searches
  • OBO SSO in Java Applications: Securely Calling Downstream APIs on Behalf of a User
  • Jakarta NoSQL: Why JPA Is Not Enough for the AI Era
  • Top Java Security Vulnerabilities and How to Prevent Them in Modern 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