-
-
Notifications
You must be signed in to change notification settings - Fork 22
Generating classes at runtime and invoking their methods with and without the use of reflection
For this purpose is necessary the use of ClassFactory component and of the sources generating components. Once the sources have been set in UnitSourceGenerator objects, they must be passed to loadOrBuildAndDefine
method of ClassFactory with the ClassLoader where you want to define new generated classes. This method performs the following operations: tries to load all the classes present in the UnitSourceGenerator through the class loader, if at least one of these is not found it proceeds to compiling all the UnitSourceGenerators and uploading their classes on class loader: in this case, keep in mind that if a class with the same name was previously loaded by the class loader, the compiled class will not be uploaded. If you need more information you can:
- see a complete example about source code generators
- read this guide where you also can find a link to an example about generating classes by using libraries located outside the runtime class paths
- go here for more examples
- ask for assistance
Once the classes have been compiled and loaded, it is possible to invoke their methods in severals ways as shown at the end of the example below.
package org.burningwave.core.examples.classfactory;
import static org.burningwave.core.assembler.StaticComponentContainer.Constructors;
import java.lang.reflect.Modifier;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import org.burningwave.core.Virtual;
import org.burningwave.core.assembler.ComponentContainer;
import org.burningwave.core.assembler.ComponentSupplier;
import org.burningwave.core.classes.AnnotationSourceGenerator;
import org.burningwave.core.classes.ClassFactory;
import org.burningwave.core.classes.ClassSourceGenerator;
import org.burningwave.core.classes.FunctionSourceGenerator;
import org.burningwave.core.classes.GenericSourceGenerator;
import org.burningwave.core.classes.TypeDeclarationSourceGenerator;
import org.burningwave.core.classes.UnitSourceGenerator;
import org.burningwave.core.classes.VariableSourceGenerator;
public class RuntimeClassExtender {
@SuppressWarnings("resource")
public static void execute() throws Throwable {
UnitSourceGenerator unitSG = UnitSourceGenerator.create("packagename").addClass(
ClassSourceGenerator.create(
TypeDeclarationSourceGenerator.create("MyExtendedClass")
).addModifier(
Modifier.PUBLIC
//generating new method that override MyInterface.convert(LocalDateTime)
).addMethod(
FunctionSourceGenerator.create("convert")
.setReturnType(
TypeDeclarationSourceGenerator.create(Comparable.class)
.addGeneric(GenericSourceGenerator.create(Date.class))
).addParameter(VariableSourceGenerator.create(LocalDateTime.class, "localDateTime"))
.addModifier(Modifier.PUBLIC)
.addAnnotation(AnnotationSourceGenerator.create(Override.class))
.addBodyCodeLine("return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());")
.useType(ZoneId.class)
).addConcretizedType(
MyInterface.class
).expands(ToBeExtended.class)
);
System.out.println("\nGenerated code:\n" + unitSG.make());
//With this we store the generated source to a path
unitSG.storeToClassPath(System.getProperty("user.home") + "/Desktop/bw-tests");
ComponentSupplier componentSupplier = ComponentContainer.getInstance();
ClassFactory classFactory = componentSupplier.getClassFactory();
//this method compile all compilation units and upload the generated classes to default
//class loader declared with property "class-factory.default-class-loader" in
//burningwave.properties file (see "Overview and configuration").
//If you need to upload the class to another class loader use
//loadOrBuildAndDefine(LoadOrBuildAndDefineConfig) method
Class<?> generatedClass = classFactory.loadOrBuildAndDefine(
unitSG
).get(
"packagename.MyExtendedClass"
);
ToBeExtended generatedClassObject =
Constructors.newInstanceOf(generatedClass);
generatedClassObject.printSomeThing();
System.out.println(
((MyInterface)generatedClassObject).convert(LocalDateTime.now()).toString()
);
//You can also invoke methods by casting to Virtual (an interface offered by the
//library for faciliate use of runtime generated classes)
Virtual virtualObject = (Virtual)generatedClassObject;
//Invoke by using reflection
virtualObject.invoke("printSomeThing");
//Invoke by using MethodHandle
virtualObject.invokeDirect("printSomeThing");
System.out.println(
((Date)virtualObject.invokeDirect("convert", LocalDateTime.now())).toString()
);
}
public static class ToBeExtended {
public void printSomeThing() {
System.out.println("Called method printSomeThing");
}
}
public static interface MyInterface {
public Comparable<Date> convert(LocalDateTime localDateTime);
}
public static void main(String[] args) throws Throwable {
execute();
}
}
Burningwave core is a fully indipendent, advanced, free and open source Java frameworks building library that contains AN EXTREMELY POWERFUL CLASSPATH SCANNER.
To include Burningwave Core library in your projects simply use with Apache Maven:
<dependency>
<groupId>org.burningwave</groupId>
<artifactId>core</artifactId>
<version>12.65.2</version>
</dependency>
To use Burningwave Core as a Java module add the following to your module-info.java
:
requires org.burningwave.core;
ClassFactory
ClassHunter
- In depth look to and configuration guide
- USE CASE: retrieving all classes of the classpath
- USE CASE: retrieving all classes that implement one or more interfaces
- USE CASE: finding all classes that extend a base class
- USE CASE: searching for all classes that have package name that matches a regex
- USE CASE: finding all classes for module name (Java 9 and later)
- USE CASE: finding all annotated classes
- USE CASE: how to scan classes for specific annotations and collect its values
- USE CASE: searching for all classes with a constructor that takes a specific type as first parameter and with at least 2 methods that begin for a given string
- USE CASE: searching for all classes with methods whose name begins for a given string and that takes a specific type as its first parameter
- USE CASE: finding all classes that have at least 2 protected fields