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

  • Zero-Downtime Deployments for Java Apps on Kubernetes
  • Rethinking Java CRUDs With Event Sourcing and CQRS Patterns
  • Detecting Bugs and Vulnerabilities in Java With SonarQube
  • Introduction to Tactical DDD With Java: Steps to Build Semantic Code

Trending

  • Throughput vs Goodput: The Performance Metric You Are Probably Ignoring in LLM Testing
  • You Don't Get to Retrofit Trust: Why API Security Must Be Designed In, Not Bolted On
  • Kafka and Spark Structured Streaming in Enterprise: The Patterns That Hold Up Under Pressure
  • Master-Class: Understanding Database Replication (Single, Multi, and Leaderless)
  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.2K 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

  • Zero-Downtime Deployments for Java Apps on Kubernetes
  • Rethinking Java CRUDs With Event Sourcing and CQRS Patterns
  • Detecting Bugs and Vulnerabilities in Java With SonarQube
  • Introduction to Tactical DDD With Java: Steps to Build Semantic Code

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