package org.enumerable.lambda.weaving; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import static org.enumerable.lambda.exception.UncheckedException.uncheck; import static org.enumerable.lambda.weaving.Debug.debug; public class ClassInjector { static File classDir; static Method defineClass; static Method resolveClass; static Method verify; static Constructor<?> classReaderConstructor; static { try { defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE); defineClass.setAccessible(true); resolveClass = ClassLoader.class.getDeclaredMethod("resolveClass", Class.class); resolveClass.setAccessible(true); classDir = new File(System.getProperty("lambda.weaving.debug.classes.dir", "target/generated-classes/")); debug("writing generated classes to " + classDir.getAbsolutePath()); } catch (Exception e) { throw uncheck(e); } try { String[] realAsmPackageNotToBeChangedByJarJar = { "org.objectweb." }; Class<?> checkClassAdapter = Class.forName(realAsmPackageNotToBeChangedByJarJar[0] + "asm.util.CheckClassAdapter"); Class<?> classReader = Class.forName(realAsmPackageNotToBeChangedByJarJar[0] + "asm.ClassReader"); verify = checkClassAdapter.getMethod("verify", classReader, Boolean.TYPE, PrintWriter.class); classReaderConstructor = classReader.getConstructor(InputStream.class); debug("asm-util is avaialbe, will pre-verify generated classes"); } catch (Exception ignore) { debug("asm-util NOT avaialbe, will not be able to pre-verify generated classes"); } } public void inject(ClassLoader loader, String className, byte[] bs) { try { debug("defining class " + className); Class<?> c = (Class<?>) defineClass.invoke(loader, className, bs, 0, bs.length); resolveClass.invoke(loader, c); } catch (Exception e) { throw uncheck(e); } } public void dump(String name, byte[] b) { if (!debug) return; File file = new File(classDir, name.replace('.', '/') + ".class"); FileOutputStream out = null; try { if (file.getParentFile().isDirectory() || file.getParentFile().mkdirs()) { out = new FileOutputStream(file); out.write(b); } } catch (Exception e) { throw uncheck(e); } finally { if (out != null) { try { out.close(); } catch (IOException silent) { } } } } // Disabled for now, printing loads of stuff anyway @SuppressWarnings("unused") public void verifyIfAsmUtilIsAvailable(byte[] b) { // try { // if (verify == null || !debug) // return; // // Object cr = classReaderConstructor.newInstance(new // ByteArrayInputStream(b)); // PrintWriter pw = new PrintWriter(System.out); // verify.invoke(null, cr, false, pw); // // } catch (Exception e) { // throw uncheck(e); // } } }