package compiler.java; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Path; import java.util.regex.Matcher; import util.FileUtils; /** * A compiled class: name + bytecode. */ public class CompiledClass { /***************************************************************************** * Class name as returned by {@link Class#getName()} (e.g. "java.util.List" or * "java.util.AbstractMap$SimpleEntry"). */ public final String name; /****************************************************************************/ public final byte[] bytecode; /****************************************************************************/ public Class<?> klass = null; /****************************************************************************/ public CompiledClass(String name, byte[] bytecode) { this.name = name; this.bytecode = bytecode; } /****************************************************************************/ public boolean loaded() { return klass != null; } /****************************************************************************/ public Class<?> klass() { if (!loaded()) { throw new Error("Trying the get the class object of an unloaded " + "compiled class: " + this); } return klass; } /****************************************************************************/ @Override public String toString() { return name; } /***************************************************************************** * Dump the bytecode into a file whose matches the structure of the class * name, under the $root directory. */ public void dump(Path root) { String relative = name.replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + ".class"; File output = root.resolve(relative).toFile(); try { FileUtils.create(output); OutputStream stream = new BufferedOutputStream( new FileOutputStream(output), bytecode.length); stream.write(bytecode); stream.close(); } catch (IOException e){ throw new Error("I/O error when trying to dump bytecode for class " + name + " to file " + output + ".", e); } } /***************************************************************************** * Load this class in the supplied class loader, and returns the resulting * Class object. */ public Class<?> load(MemoryClassLoader loader) { return (klass = loader.defineClass(name, bytecode)); } }