package compiler.java;
import java.security.SecureClassLoader;
import java.util.HashMap;
import java.util.Map;
/**
* A class loader that exposes a function to define classes from bytecode.
* Functions defined as such are not dumped to disk and live in memory. We also
* save their bytecode, since there is no way to get it back from the Java
* compiler.
*
* The class names supplied to the functions should the full class names as
* returned by {@link Class#getName()} (e.g. "java.util.List" or
* "java.util.AbstractMap$SimpleEntry").
*/
public class MemoryClassLoader extends SecureClassLoader
{
/****************************************************************************/
private static final MemoryClassLoader instance = new MemoryClassLoader();
private MemoryClassLoader() {}
public static MemoryClassLoader get() { return instance; }
/****************************************************************************/
private Map<String, byte[]> bytecodes = new HashMap<>();
/****************************************************************************/
public Class<?> defineClass(String name, byte[] bytecode)
{
/* The class has already been defined. This can happen because a class is
* compiled but then output as result of the compilation of another class
* (that's just how the Java compiler works - compiling whole directories
* and shit). Maybe this should be handled more cleanly. */
if (bytecodes.get(name) != null) {
try {
return loadClass(name);
}
catch (ClassNotFoundException e) {
throw new Error("programming error");
}
}
bytecodes.put(name, bytecode);
return defineClass(name, bytecode, 0, bytecode.length);
}
/****************************************************************************/
public byte[] getBytecode(String name)
{
return bytecodes.get(name);
}
}