Two months after the primary commit in October 2022, Peter Verhas, Senior Architect at EPAM Techniques, has released model 2.0.0 of SourceBuddy, a brand new utility that compiles dynamically created Java supply code outlined by a String
or a file to a class
file. SourceBuddy, requiring Java 17, is a simplified facade for the javac
compiler, which delivers the identical performance.
Model 2.0.0 helps a mixture of hidden and non-hidden courses throughout compilation and run-time. Moreover, the API has been simplified, containing breaking adjustments equivalent to altering the loadHidden()
methodology to the hidden()
methodology, therefore the brand new main launch. An entire overview of the adjustments per model is accessible within the releases documentation on GitHub.
SourceBuddy can be utilized after including the next Maven dependency:
<dependency>
<groupId>com.javax0.sourcebuddy</groupId>
<artifactId>SourceBuddy</artifactId>
<model>2.0.0</model>
</dependency>
Alternatively the next Gradle dependency could also be used:
implementation 'com.javax0.sourcebuddy:SourceBuddy:2.0.0'
To exhibit SourceBuddy, think about the next instance interface which shall be utilized by the dynamically created code:
package deal com.app;
public interface PrintInterface
void print();
The straightforward API is ready to compile one class at a time by utilizing the static com.javax0.sourcebuddy.Compiler.compile()
methodology. For instance, to compile a brand new class implementing the beforehand talked about PrintInterface
:
String supply = """
package deal com.app;
public class CustomClass implements PrintInterface
@Override
public void print()
System.out.println("Hey world!");
""";
Class<?> clazz = Compiler.compile(supply);
PrintInterface customClass =
(PrintInterface) clazz.getConstructor().newInstance();
customClass.print();
The fluent API provides options to resolve extra complicated issues such because the compilation of a number of information with the Compiler.java()
static methodology:
Compiler.java().from(supply).compile().load().newInstance(PrintInterface.class);
Optionally, the binary identify of the category could also be specified, though SourceBuddy will already detect the identify at any time when potential:
.from("com.app", supply)
For a number of supply information, the from()
methodology could also be known as a number of occasions, or all of the supply information in a particular listing could also be loaded directly:
.from(Paths.get("src/foremost/java/sourcefiles"))
Optionally, the hidden()
methodology could also be used to create a Hidden Class which might’t be used instantly by different courses, solely by means of reflection by utilizing the category object returned by SourceBuddy.
The compile()
methodology generates the byte codes for the Java supply information, however would not load them into reminiscence but.
closing var byteCodes = Compiler.java()
.from("com.app", supply)
.compile();
Optionally, the byte codes could also be saved to the native drive:
byteCodes.saveTo(Paths.get("./goal/generated_classes"));
Alternatively, the stream()
methodology, which returns a stream of byte arrays, could also be used to retrieve data such because the binary identify:
byteCodes.stream().forEach(
bytecode -> System.out.println(Compiler.getBinaryName(bytecode)));
The byteCodes.load()
methodology masses the courses and converts the bytecode to Class
objects:
closing var loadedClasses = compiled.load();
Accessing a category is feasible by casting to a superclass or an interface the category implements or by utilizing the reflection API. For instance, to entry the CustomClass
:
Class<?> customClass = loadedClasses.get("com.app.CustomClass");
Alternatively, the newInstance()
methodology could also be used to create an occasion of the category:
Object customClassInstance = loadedClasses.newInstance("com.app.CustomClass");
The stream of courses could also be used to retrieve extra details about the courses:
loadedClasses.stream().forEach(
clazz -> System.out.println(clazz.getSimpleName()));
Extra details about SourceBuddy will be discovered within the detailed explanations contained in the README
file on GitHub.