}
private static CtClass createProxyCtClass(ClassLoader loader, ProxyMixin[] mixins, Class<?>[] interfaces)
throws Exception
{
ClassPool pool = AspectManager.instance().findClassPool(loader);
if (pool == null) throw new NullPointerException("Could not find ClassPool");
String classname = null;
synchronized (ProxyFactory.class)
{
classname = GENERATED_PROXIES_PACKAGE + ".AOPProxy$" + counter++;
}
CtClass base = pool.get("org.jboss.aop.proxy.Proxy");
CtClass proxy = TransformerCommon.makeClass(pool, classname, base);
proxy.addInterface(pool.get("org.jboss.aop.instrument.Untransformable"));
CtClass map = pool.get("java.util.Map");
CtField methodMap = new CtField(map, "methodMap", proxy);
methodMap.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
Instrumentor.addSyntheticAttribute(methodMap);
proxy.addField(methodMap);
CtMethod getMethodMap = CtNewMethod.getter("getMethodMap", methodMap);
getMethodMap.setModifiers(Modifier.PUBLIC);
Instrumentor.addSyntheticAttribute(getMethodMap);
proxy.addMethod(getMethodMap);
HashSet<String> addedInterfaces = new HashSet<String>();
HashSet<Long> addedMethods = new HashSet<Long>();
if (mixins != null)
{
for (int i = 0; i < mixins.length; i++)
{
HashSet<Long> mixinMethods = new HashSet<Long>();
Class<?>[] mixinf = mixins[i].getInterfaces();
ClassPool mixPool = AspectManager.instance().findClassPool(mixins[i].getMixin().getClass());
CtClass mixClass = mixPool.get(mixins[i].getMixin().getClass().getName());
for (int j = 0; j < mixinf.length; j++)
{
if (addedInterfaces.contains(mixinf[j].getName())) throw new Exception("2 mixins are implementing the same interfaces");
ClassPool mixIntfPool = AspectManager.instance().findClassPool(mixinf[j]);
CtClass intfClass = mixIntfPool.get(mixinf[j].getName());
CtMethod[] methods = intfClass.getMethods();
for (int m = 0; m < methods.length; m++)
{
if (methods[m].getDeclaringClass().getName().equals("java.lang.Object")) continue;
Long hash = new Long(JavassistMethodHashing.methodHash(methods[m]));
if (mixinMethods.contains(hash)) continue;
if (addedMethods.contains(hash)) throw new Exception("More than one mixin has same method");
mixinMethods.add(hash);
addedMethods.add(hash);
String returnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ";
String code = "{" +
" " + mixClass.getName() + " mixin = (" + mixClass.getName() + ")mixins[" + i + "].getMixin();" +
" " + returnStr + " mixin." + methods[m].getName() + "($$);" +
"}";
CtMethod newMethod = CtNewMethod.make(methods[m].getReturnType(), methods[m].getName(), methods[m].getParameterTypes(), methods[m].getExceptionTypes(), code, proxy);
newMethod.setModifiers(Modifier.PUBLIC);
proxy.addMethod(newMethod);
}
proxy.addInterface(intfClass);
addedInterfaces.add(intfClass.getName());
}
}
}
for (int i = 0; i < interfaces.length; i++)
{
if (addedInterfaces.contains(interfaces[i].getName())) continue;
ClassPool mixPool = AspectManager.instance().findClassPool(interfaces[i]);
CtClass intfClass = mixPool.get(interfaces[i].getName());
CtMethod[] methods = intfClass.getMethods();
for (int m = 0; m < methods.length; m++)
{
if (methods[m].getDeclaringClass().getName().equals("java.lang.Object")) continue;
Long hash = Long.valueOf(JavassistMethodHashing.methodHash(methods[m]));