Creating classes dynamically with Java
It is possible to generate classes (via cglib, asm, javassist, bcel), but you shouldn't do it that way. Why?
- the code that's using the library should expect type
Object
and get all the fields using reflection - not a good idea - java is statically typed language, and you want to introduce dynamic typing - it's not the place.
If you simply want the data in an undefined format, then you can return it in an array, like Object[]
, or Map<String, Object>
if you want them named, and get it from there - it will save you much trouble with unneeded class generation for the only purpose of containing some data that will be obtained by reflection.
What you can do instead is have predefined classes that will hold the data, and pass them as arguments to querying methods. For example:
public <T> T executeQuery(Class<T> expectedResultClass,
String someArg, Object.. otherArgs) {..}
Thus you can use reflection on the passed expectedResultClass
to create a new object of that type and populate it with the result of the query.
That said, I think you could use something existing, like an ORM framework (Hibernate, EclipseLink), spring's JdbcTemplate
, etc.
Create a dynamic class in java
Just so you know runtime class generation is extremely complex and not something recommended for beginners to the language. This would be an excellent scenario to use a map an anonymous classes.
class AnimalType {
private static final Map<String, Animal> animals = new HashMap<String, Animal>();
static {
// Populating map with default animals
addAnimal("big","BELLOWWWWW"); // bison
addAnimal("small","SQUEEEEEAK"); // mouse
addAnimal("lazy","ROARRRRR"); // lion
addAnimal("loyal","WOOF "); // dog
}
public static void addAnimal(String criteria, final String sound) {
// Assigning a anonymous implementation of animal to the given criteria
animals.put(criteria, new Animal() {
@Override
public void talk() {
System.out.println(sound);
}
});
}
public static Animal getAnimal(String criteria) {
// Returning an animal from the animals map
return animals.get(criteria);
}
}
If you really do insist on true runtime class generation or if you're curious how it works, check out ByteBuddy.
How to create a class dynamically in java
What would you do with a dynamically created and instantiated class that none of your other code knows about?
For a stically typed language like Java, it makes little sense to have such classes. On the other hand, most OR Mappers like Hibernate come with tools that allow you to statically generate classes from a database schema.
How to Create Java class/es files dynamically?
Working example which will help you.
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
public class HelloWorld {
public static void main(String[] args) throws Exception {
// create an empty source file
File sourceFile = File.createTempFile("Hello", ".java");
sourceFile.deleteOnExit();
// generate the source code, using the source filename as the class name
String classname = sourceFile.getName().split("\\.")[0];
String sourceCode = "public class " + classname + "{ public void hello() { System.out.print(\"Hello world\");}}";
// write the source code into the source file
FileWriter writer = new FileWriter(sourceFile);
writer.write(sourceCode);
writer.close();
// compile the source file
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
File parentDirectory = sourceFile.getParentFile();
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(parentDirectory));
Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile));
compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();
fileManager.close();
// load the compiled class
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { parentDirectory.toURI().toURL() });
Class<?> helloClass = classLoader.loadClass(classname);
// call a method on the loaded class
Method helloMethod = helloClass.getDeclaredMethod("hello");
helloMethod.invoke(helloClass.newInstance());
}
}
How can I dynamically create an instance of a class in java?
Just cast it to A:
instB = (A)Class....newInstance(...);
You don't need to know the exact class.
Automatically generate code to dynamically create Java objects (Reflection)
Using Reflection
you can:
- Invoke
static
newBuilder
method to create builder. - Find all
fields
/setters
for givenPOJO
class. If in all casessetters
on builder andsetters
onPOJO
have the same name like in your example it should be easy to convert. - Invoke
build
on builder instance to create newPOJO
.
Using basic Java
Reflection
and Stream
API
-s it could look like below:
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Properties;
import java.util.StringJoiner;
import java.util.function.Function;
import java.util.stream.Stream;
public class ReflectionApp {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.put("name", "John");
properties.put("date", "today");
AvroPropertie manualInstance = AvroPropertie.newBuilder()
.setName(properties.getProperty("name"))
.setDate(properties.getProperty("date"))
.build();
Object dynamicInstance = AvroAutoCoder.createAndSet(AvroPropertie.class, properties::getProperty);
System.out.println(manualInstance);
System.out.println(dynamicInstance);
System.out.println("manualInstance == dynamicInstance => " + manualInstance.equals(dynamicInstance));
}
}
class AvroAutoCoder {
public static Object createAndSet(Class clazz, Function<String, String> dataSupplier) throws Exception {
Object builderInstance = findMethod(clazz, "newBuilder")
.invoke(null);
Class<?> builderClass = builderInstance.getClass();
getSetters(clazz).forEach(setter -> {
try {
String fieldName = setter.getName().substring(3).toLowerCase();
findMethod(builderClass, setter.getName())
.invoke(builderInstance, dataSupplier.apply(fieldName));
} catch (Exception e) {
throw new IllegalStateException(e);
}
});
return findMethod(builderClass, "build")
.invoke(builderInstance);
}
private static Method findMethod(Class clazz, String methodName) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> method.getName().equals(methodName))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
private static Stream<Method> getSetters(Class clazz) {
return Arrays.stream(clazz.getDeclaredMethods())
.filter(method -> method.getParameterCount() == 1 && method.getReturnType() == Void.TYPE)
.filter(method -> method.getName().startsWith("set"));
}
}
Above code prints:
AvroPropertie[name='John', date='today']
AvroPropertie[name='John', date='today']
manualInstance == dynamicInstance => true
Comment added by the Author of question:
In this specific example class APropertie
has a static inner class named Builder
which holds the wanted setters. In this case the getSetters()
methods needs to be changed a little bit:
// Find all setter of class
private static Stream<Method> getSetters2(Class clazz) {
Optional<Class> first = Arrays.stream(clazz.getDeclaredClasses())
.findFirst();
return Arrays.stream(first.get().getDeclaredMethods())
.filter(method -> method.getName().startsWith("set"));
}
Related Topics
Java 8: Where Is Trifunction (And Kin) in Java.Util.Function? or What Is the Alternative
Jpa: What Is the Proper Pattern for Iterating Over Large Result Sets
Memory Leak When Redeploying Application in Tomcat
How to Encode Uri Parameter Values
Java Split Is Eating My Characters
Deciphering Variable Information While Debugging Java
What Does Class<> Mean in Java
Is It Safe to Get Values from a Java.Util.Hashmap from Multiple Threads (No Modification)
How to Check If a Date Object Equals Yesterday
Ejb 3.1 @Localbean VS No Annotation
How to Return JSON Data from Spring Controller Using @Responsebody
Moving Items Around in an Arraylist
How to Get Whole and Fractional Parts from Double in Jsp/Java
Java Convert Gmt/Utc to Local Time Doesn't Work as Expected
How to Change My Windows Desktop Wallpaper Programmatically in Java/Groovy