package spoonloader; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import spoon.processing.Builder; import spoon.reflect.Factory; import spoon.reflect.declaration.CtSimpleType; import spoon.support.ByteCodeOutputProcessor; import spoon.support.DefaultCoreFactory; import spoon.support.JavaOutputProcessor; import spoon.support.StandardEnvironment; /** * Class that implements the minimum environment needed to load, mirror (i.e. * create reflective instances of), modify, and (re)compile classes at runtime * using Spoon. Note that * modification and recompilation will only work correctly if the modified * classes are not already on the classpath. *
*
* Released to the public domain. Let me know if you find the code useful. * * @author Brett Daniel */ public class SimpleSpoonLoader { private static final String DEFAULT_MODEL_BIN_DIR = "spoon/bin"; private static final String DEFAULT_MODEL_SRC_DIR = "spoon/src"; private Factory factory; private String modelBinDir = DEFAULT_MODEL_BIN_DIR; private String modelSrcDir = DEFAULT_MODEL_SRC_DIR; public SimpleSpoonLoader() { factory = createFactory(); } /** * @return the {@link Factory} used to create mirrors */ public Factory getFactory() { return factory; } /** * Set the temporary directory in which this class outputs source files */ public void setModelSrcDir(String modelSrcDir) { this.modelSrcDir = modelSrcDir; } /** * Get the temporary directory in which this class outputs source files */ public String getModelSrcDir() { return modelSrcDir; } /** * Set the temporary directory in which this class outputs compiled class files */ public void setModelBinDir(String modelBinDir) { this.modelBinDir = modelBinDir; } /** * Get the temporary directory in which this class outputs compiled class files */ public String getModelBinDir() { return modelBinDir; } /** * @return a new Spoon {@link Factory} */ protected Factory createFactory() { StandardEnvironment env = new StandardEnvironment(); Factory factory = new Factory(new DefaultCoreFactory(), env); // environment initialization env.setComplianceLevel(6); env.setVerbose(false); env.setDebug(false); env.setTabulationSize(5); env.useTabulations(true); env.useSourceCodeFragments(false); return factory; } /** * Add directories or JAR files in which to search for input source code */ public void addSourcePath(String sourcePath) { addSourcePath(new File(sourcePath)); } /** * Add directories or JAR files in which to search for input source code */ public void addSourcePath(File sourcePath) { buildModel(sourcePath); compile(); } /** * Build the internal model (i.e. abstract syntax tree) of the source code */ protected void buildModel(File sourcePath) { Builder builder = getFactory().getBuilder(); try { builder.addInputSource(sourcePath); builder.build(); } catch (IOException e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); } } /** * Create class files of the internal model in {@link #modelBinDir} */ public void compile() { JavaOutputProcessor fileOutput = new JavaOutputProcessor(new File(modelSrcDir)); ByteCodeOutputProcessor classOutput = new ByteCodeOutputProcessor(fileOutput, new File(modelBinDir)); classOutput.setFactory(getFactory()); classOutput.init(); for (CtSimpleType type : getFactory().Class().getAll()) { classOutput.process(type); } classOutput.processingDone(); } /** * @return the class with the given qualified name. */ @SuppressWarnings("unchecked") public Class load(String qualifiedName) { try { URL url = new File(modelBinDir).toURI().toURL(); URLClassLoader cl = new URLClassLoader(new URL[] {url}); Thread.currentThread().setContextClassLoader(cl); return (Class)(cl.loadClass(qualifiedName)); } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } /** * @return the reflective instance of the class with the given qualified name */ public CtSimpleType mirror(String qualifiedName) { Class clazz = load(qualifiedName); return mirror(clazz); } /** * @return the reflective instance of the given class */ public CtSimpleType mirror(Class clazz) { return getFactory().Type().get(clazz); } }