package org.hotswap.agent.plugin.weld; import org.hotswap.agent.annotation.OnClassLoadEvent; import org.hotswap.agent.config.PluginManager; import org.hotswap.agent.javassist.CannotCompileException; import org.hotswap.agent.javassist.ClassPool; import org.hotswap.agent.javassist.CtClass; import org.hotswap.agent.javassist.CtConstructor; import org.hotswap.agent.javassist.CtMethod; import org.hotswap.agent.javassist.NotFoundException; import org.hotswap.agent.javassist.expr.ExprEditor; import org.hotswap.agent.javassist.expr.MethodCall; import org.hotswap.agent.util.PluginManagerInvoker; /** * Hook into ProxyFactory constructors to register proxy factory into WeldPlugin. If WeldPlugin is not initialized in proxy factory * classLoader (ModuleClassLoader) then the proxy factory is not registered - it happens most likely in case of system beans proxy factories. * * @author Vladimir Dvorak */ public class ProxyFactoryTransformer { /** * Patch ProxyFactory class. * - add factory registration into constructor * - changes call classLoader.loadClass(...) in getProxyClass() to ProxyClassLoadingDelegate.loadClass(classLoader, ...) * - changes call ClassFileUtils.toClass() in createProxyClass() to ProxyClassLoadingDelegate.loadClass(...) * * @param ctClass the ProxyFactory class * @param classPool the class pool * @throws NotFoundException the not found exception * @throws CannotCompileException the cannot compile exception */ @OnClassLoadEvent(classNameRegexp = "org.jboss.weld.bean.proxy.ProxyFactory") public static void patchProxyFactory(CtClass ctClass, ClassPool classPool) throws NotFoundException, CannotCompileException { CtClass[] constructorParams = new CtClass[] { classPool.get("java.lang.String"), classPool.get("java.lang.Class"), classPool.get("java.util.Set"), //classPool.get("java.lang.String"), classPool.get("javax.enterprise.inject.spi.Bean"), classPool.get("boolean") }; CtConstructor declaredConstructor = ctClass.getDeclaredConstructor(constructorParams); // TODO : we should find constructor without this() call and put registration only into this one declaredConstructor.insertAfter( "if (" + PluginManager.class.getName() + ".getInstance().isPluginInitialized(\"" + WeldPlugin.class.getName() + "\", this.classLoader)) {" + PluginManagerInvoker.buildCallPluginMethod("this.classLoader", WeldPlugin.class, "registerProxyFactory", "this", "java.lang.Object", "bean", "java.lang.Object", "this.classLoader", "java.lang.ClassLoader", "proxiedBeanType", "java.lang.Class" ) + "}" ); CtMethod getProxyClassMethod = ctClass.getDeclaredMethod("getProxyClass"); getProxyClassMethod.instrument( new ExprEditor() { public void edit(MethodCall m) throws CannotCompileException { if (m.getClassName().equals(ClassLoader.class.getName()) && m.getMethodName().equals("loadClass")) m.replace("{ $_ = org.hotswap.agent.plugin.weld.command.ProxyClassLoadingDelegate.loadClass(this.classLoader,$1); }"); } }); CtMethod createProxyClassMethod = ctClass.getDeclaredMethod("createProxyClass"); createProxyClassMethod.instrument( new ExprEditor() { public void edit(MethodCall m) throws CannotCompileException { if (m.getClassName().equals("org.jboss.weld.util.bytecode.ClassFileUtils") && m.getMethodName().equals("toClass")) m.replace("{ $_ = org.hotswap.agent.plugin.weld.command.ProxyClassLoadingDelegate.toClass($$); }"); } }); } }