Hey, @Edvard,
Dynamic Class creation enables you to create a Java class on the fly at runtime, from source code created from a string. Dynamic class creation can be used in extremely low latency applications to improve performance. Although compiling the source into a class is slow, the newly created class will be treated by the JVM just like any other class.
This is an example to create and used a dynamically created class without creating any intermediate files.
First the source is created using string builder
final String className = "HelloWorld";
final String path = "com.bounded.buffer";
final String fullClassName = path.replace('.', '/') + "/" + className;
final StringBuilder source = new StringBuilder();
source.append("package " + path+";");
source.append("public class " + className + " {\n");
source.append(" public String toString() {\n");
source.append(" return \"HelloWorld - Java Dynamic Class Creation...";");
source.append(" }\n");
source.append("}\n");
This is where the magic happens - the StringBuilder java source, is turned into byte code :
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final SimpleJavaFileObject simpleJavaFileObject
= new SimpleJavaFileObject(URI.create(fullClassName + ".java"), SOURCE) {
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
@Override
public OutputStream openOutputStream() throws IOException{
return byteArrayOutputStream;
}
};
final JavaFileManager javaFileManager = new ForwardingJavaFileManager(
ToolProvider.getSystemJavaCompiler().
getStandardFileManager(null, null, null)) {
@Override
public JavaFileObject getJavaFileForOutput(
Location location,String className,
JavaFileObject.Kind kind,
FileObject sibling) throws .. {
return simpleJavaFileObject;
}
};
ToolProvider.getSystemJavaCompiler().getTask(null, javaFileManager, null, null, null, singletonList(simpleJavaFileObject)).call();
then the bytes that make up the class are loaded into the class loader :
final byte[] bytes = byteArrayOutputStream.toByteArray();
// use the unsafe class to load in the class bytes
final Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
final Unsafe unsafe = (Unsafe) f.get(null);
final Class aClass = unsafe.defineClass(fullClassName, bytes, 0, bytes.length);
and instantiated :
final Object o = aClass.newInstance();
System.out.println(o);
When run, the console will output "HelloWorld