package io.github.proxyhotswap.cglib; import io.github.proxyhotswap.TransformationUtils; import io.github.proxyhotswap.javassist.CannotCompileException; import io.github.proxyhotswap.javassist.ClassPool; import io.github.proxyhotswap.javassist.CtClass; import io.github.proxyhotswap.javassist.CtMethod; import io.github.proxyhotswap.javassist.NotFoundException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.security.ProtectionDomain; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author Erki Ehtla * */ public class GeneratorSpyTransformer implements ClassFileTransformer { private static Map<String, GeneratorParams> generatorParams = new ConcurrentHashMap<>(); protected static final ClassPool classPool = TransformationUtils.getClassPool(); public byte[] transform(ClassLoader loader, String className, final Class<?> classBeingRedefined, ProtectionDomain protectionDomain, final byte[] classfileBuffer) { if (classBeingRedefined != null) return null; CtClass cc; try { cc = classPool.makeClass(new ByteArrayInputStream(classfileBuffer), false); CtClass[] interfaces = cc.getInterfaces(); for (CtClass class1 : interfaces) { // We use strings because some libraries repackage cglib to a different namespace to avoid conflicts. if (class1.getSimpleName().equals("GeneratorStrategy")) { CtMethod[] declaredMethods = class1.getMethods(); for (CtMethod method : declaredMethods) { if (method.getName().equals("generate") && method.getReturnType().getSimpleName().equals("byte[]")) { return addGenerationParameterCollector(cc); } } } } } catch (IOException | RuntimeException | NotFoundException | CannotCompileException e) { TransformationUtils.logError(e); } return null; } public static void register(Object generatorStrategy, Object classGenerator, byte[] bytes) { CtClass cc = null; try { cc = classPool.makeClass(new ByteArrayInputStream(bytes), false); generatorParams.put(cc.getName(), new GeneratorParams(generatorStrategy, classGenerator)); } catch (IOException | RuntimeException e) { TransformationUtils.logError(e); } } private byte[] addGenerationParameterCollector(final CtClass cc) throws IOException, NotFoundException, CannotCompileException { CtMethod declaredMethod = cc.getDeclaredMethod("generate"); declaredMethod.insertAfter(getClass().getName() + ".register($0, $1, $_);"); return cc.toBytecode(); } public static Map<String, GeneratorParams> getGeneratorParams() { return generatorParams; } }