package net.sourceforge.javautil.interceptor.type.cjc;
import java.lang.reflect.Method;
import java.util.List;
import net.sourceforge.javautil.bytecode.BytecodeCompiler;
import net.sourceforge.javautil.bytecode.api.BytecodeContext;
import net.sourceforge.javautil.bytecode.api.IBytecodeResolvable;
import net.sourceforge.javautil.bytecode.api.MethodDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeDescriptor;
import net.sourceforge.javautil.bytecode.api.TypeMemberAccess.Scope;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeBlock;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeConstructor;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeConstructorBase;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeContextMethod;
import net.sourceforge.javautil.bytecode.api.type.method.IBytecodeMethod;
import net.sourceforge.javautil.bytecode.api.type.method.BytecodeMethodConcrete;
import net.sourceforge.javautil.common.CollectionUtil;
import net.sourceforge.javautil.interceptor.IInterceptorManager;
import net.sourceforge.javautil.interceptor.IInterceptorManipulator;
import net.sourceforge.javautil.interceptor.type.InterceptorProxyTypeInterceptor;
/**
* A proxy type that itself is the instance being invoked with added methods for proxying purposes.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class InterceptorProxyTypeCJC extends InterceptorProxyTypeInterceptor {
public InterceptorProxyTypeCJC(BytecodeCompiler compiler, List<IInterceptorManipulator> abilities, Class type, String name) {
super(compiler, abilities, type, name);
}
@Override public void addProxyConstructors() {
InterceptorProxyConstructor apc = new InterceptorProxyConstructor(abilities);
for (IBytecodeConstructor constructor : getSuperType().getDeclaredConstructors()) {
if (constructor.getAccess().getScope() == Scope.Public) {
TypeDescriptor[] parameters = constructor.getDescriptor().getParameters();
parameters = CollectionUtil.insert(parameters, 0, TypeDescriptor.getFor(IInterceptorManager.class));
BytecodeConstructorBase pc = this.addConstructor(Scope.Public, constructor.isVarArgs(), parameters);
pc.copyAnnotations(constructor);
pc.setMethodBody(apc);
}
}
}
@Override public void addProxyMethods() {
final InterceptorProxyMethod apm = new InterceptorProxyMethod();
BytecodeBlock apmb = new BytecodeBlock() {
@Override protected void writeInstructions(BytecodeContextMethod context) {
apm.write(context);
}
};
IBytecodeResolvable st = getSuperType();
while (st != null && !"java.lang.Object".equals( st.getType().getClassName() )) {
for (IBytecodeMethod method : st.getDeclaredMethods()) {
if (method.getAccess().isStatic() || method.getAccess().getScope() != Scope.Public) continue;
this.addMethod(method.getName() + "$$", Scope.Private, false, true, method.getDescriptor()).setMethodBody(
new BytecodeBlock() {
@Override protected void writeInstructions(BytecodeContextMethod context) {
context.returnValue(
context.createSuperInvocation(context.getMethod().getName().split("\\$")[0], context.getMethodArguments())
);
}
}
);
BytecodeMethodConcrete bmc = this.addMethod(method.getName(), Scope.Public, false, true, method.getDescriptor());
bmc.copyAnnotations(method);
bmc.setMethodBody(apmb);
}
st = st.getSuperType();
}
try {
Method toString = type.getMethod("toString");
if (toString.getDeclaringClass() == Object.class) {
this.addMethod("toString", Scope.Public, false, true, new MethodDescriptor(toString))
.setMethodBody(new BytecodeBlock() {
@Override protected void writeInstructions(BytecodeContextMethod context) {
context.returnValue(context.createConcat(context.translate(
context.createInvocation(context.resolve("this"), "getClass")
.createInvocation(context, "getSuperclass")
.createInvocation(context, "getName"), "@",
context.createInvocation(context.resolve("this"), "hashCode")
)));
}
});
}
} catch (NoSuchMethodException e) {}
}
}