package org.springframework.aop.framework.asm; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.AdvisedSupport; import java.lang.reflect.Method; /** * @author robh */ public class ProxyConstructorGenerationStrategy extends AbstractCodeGenerationStrategy { public void generate(ClassWriter cw, Method method, AdvisedSupport advised, String proxyInternalName, String targetInternalName, String targetDescriptor) { MethodVisitor mv; // add field to store advised cw.visitField(Opcodes.ACC_PRIVATE, ADVISED_FIELD_NAME, ADVISED_SUPPORT_DESCRIPTOR, null, null); TargetSource targetSource = advised.getTargetSource(); boolean staticTargetSource = targetSource.isStatic(); boolean emptyTargetSource = (targetSource == AdvisedSupport.EMPTY_TARGET_SOURCE); // field to early load static TargetSource if (staticTargetSource && !(emptyTargetSource)) { cw.visitField(Opcodes.ACC_PRIVATE, TARGET_FIELD_NAME, targetDescriptor, null, null); } // add constructor to pass in the target String descriptor = getMethodDescriptor(void.class, new Class[]{AdvisedSupport.class}); mv = cw.visitMethod(Opcodes.ACC_PUBLIC, CONSTRUCTOR_INTERNAL_NAME, descriptor, null, null); // invoke super String superName = (emptyTargetSource) ? OBJECT_INTERNAL_NAME : targetInternalName; mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, superName, CONSTRUCTOR_INTERNAL_NAME, NO_ARG_CONSTRUCTOR_DESCRIPTOR); // store advised in field mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitFieldInsn(Opcodes.PUTFIELD, proxyInternalName, ADVISED_FIELD_NAME, ADVISED_SUPPORT_DESCRIPTOR); // store target in field if needed; if (staticTargetSource && !(emptyTargetSource)) { Label openTry = new Label(); mv.visitLabel(openTry); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ADVISED_SUPPORT_INTERNAL_NAME, GET_TARGET_SOURCE_METHOD, GET_TARGET_SOURCE_DESCRIPTOR); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, TARGET_SOURCE_INTERNAL_NAME, GET_TARGET_METHOD, GET_TARGET_DESCRIPTOR); mv.visitTypeInsn(Opcodes.CHECKCAST, targetInternalName); mv.visitFieldInsn(Opcodes.PUTFIELD, proxyInternalName, TARGET_FIELD_NAME, targetDescriptor); Label closeTry = new Label(); mv.visitLabel(closeTry); Label exit = new Label(); mv.visitJumpInsn(Opcodes.GOTO, exit); Label handler = new Label(); mv.visitLabel(handler); mv.visitVarInsn(Opcodes.ASTORE, 2); mv.visitTypeInsn(Opcodes.NEW, AOP_CONFIG_EXCEPTION_INTERNAL_NAME); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn("Unable to obtain target from static TargetSource"); mv.visitVarInsn(Opcodes.ALOAD, 2); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, AOP_CONFIG_EXCEPTION_INTERNAL_NAME, CONSTRUCTOR_INTERNAL_NAME, EXCEPTION_CONSTRUCTOR_DESCRIPTOR); mv.visitInsn(Opcodes.ATHROW); mv.visitLabel(exit); mv.visitInsn(Opcodes.RETURN); mv.visitTryCatchBlock(openTry, closeTry, handler, EXCEPTION_INTERNAL_NAME); } else { mv.visitInsn(Opcodes.RETURN); } // close mv.visitMaxs(0, 0); } }