org.codehaus.aspectwerkz.transform.inlining.weaver.AddWrapperVisitor.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.aspectwerkz.transform.inlining.weaver.AddWrapperVisitor.java

Source

/**************************************************************************************
 * Copyright (c) Jonas Bonr, Alexandre Vasseur. All rights reserved.                 *
 * http://aspectwerkz.codehaus.org                                                    *
 * ---------------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the LGPL license      *
 * a copy of which has been included with this distribution in the license.txt file.  *
 **************************************************************************************/
package org.codehaus.aspectwerkz.transform.inlining.weaver;

import org.objectweb.asm.Opcodes;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.codehaus.aspectwerkz.transform.Context;
import org.codehaus.aspectwerkz.transform.TransformationUtil;
import org.codehaus.aspectwerkz.transform.TransformationConstants;
import org.codehaus.aspectwerkz.transform.inlining.ContextImpl;
import org.codehaus.aspectwerkz.transform.inlining.EmittedJoinPoint;
import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
import org.codehaus.aspectwerkz.joinpoint.management.JoinPointType;

import java.util.List;
import java.util.Iterator;
import java.util.Set;
import java.lang.reflect.Modifier;

/**
 * Adds field and method and ctor wrappers when there has been at least one joinpoint emitted.
 *
 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonr </a>
 */
public class AddWrapperVisitor extends ClassAdapter implements Opcodes, TransformationConstants {

    private ContextImpl m_context;

    private Set m_addedMethods;

    public AddWrapperVisitor(ClassVisitor classVisitor, Context context, Set alreadyAddedMethods) {
        super(classVisitor);
        m_context = (ContextImpl) context;
        m_addedMethods = alreadyAddedMethods;
    }

    /**
     * Visits the class.
     *
     * @param access
     * @param name
     * @param signature
     * @param superName
     * @param interfaces
     */
    public void visit(final int version, final int access, final String name, final String signature,
            final String superName, final String[] interfaces) {
        // iterate on the emitted joinpoints
        // we don't need to filter more since the joinpoint type and the weaving phase did that for us
        List jps = m_context.getEmittedJoinPoints();
        for (Iterator iterator = jps.iterator(); iterator.hasNext();) {
            EmittedJoinPoint emittedJoinPoint = (EmittedJoinPoint) iterator.next();
            int jpType = emittedJoinPoint.getJoinPointType();
            if (Modifier.isPublic(emittedJoinPoint.getCalleeMemberModifiers())
                    || !name.equals(emittedJoinPoint.getCalleeClassName())) {//TODO ?
                continue;
            }
            switch (jpType) {
            case (JoinPointType.FIELD_GET_INT):
                createGetFieldWrapperMethod(Modifier.isStatic(emittedJoinPoint.getCalleeMemberModifiers()), name,
                        emittedJoinPoint.getCalleeMemberName(), emittedJoinPoint.getCalleeMemberDesc(), null//FIXME generic is that ok ?
                );
                break;
            case (JoinPointType.FIELD_SET_INT):
                createPutFieldWrapperMethod(Modifier.isStatic(emittedJoinPoint.getCalleeMemberModifiers()), name,
                        emittedJoinPoint.getCalleeMemberName(), emittedJoinPoint.getCalleeMemberDesc(), null//FIXME generic is that ok ?
                );
                break;
            case (JoinPointType.METHOD_EXECUTION_INT):
            case (JoinPointType.METHOD_CALL_INT):
                createMethodWrapperMethod(emittedJoinPoint.getCalleeMemberModifiers(), name,
                        emittedJoinPoint.getCalleeMemberName(), emittedJoinPoint.getCalleeMemberDesc(), null, //FIXME generic is that ok ?
                        EMPTY_STRING_ARRAY//TODO should throw Throwable ??
                );
                break;
            case (JoinPointType.CONSTRUCTOR_CALL_INT):
            case (JoinPointType.CONSTRUCTOR_EXECUTION_INT):
                createConstructorWrapperMethod(emittedJoinPoint.getCalleeMemberModifiers(), name,
                        emittedJoinPoint.getCalleeMemberName(), emittedJoinPoint.getCalleeMemberDesc(), null, //FIXME generic is that ok ?
                        EMPTY_STRING_ARRAY//TODO should throw Throwable ??
                );
                break;
            }
        }

        super.visit(version, access, name, signature, superName, interfaces);
    }

    /**
     * Creates a public wrapper method that delegates to the GETFIELD instruction of the non-public field.
     *
     * @param isStaticField
     * @param declaringTypeName
     * @param name
     * @param desc
     * @param signature
     */
    private void createGetFieldWrapperMethod(final boolean isStaticField, final String declaringTypeName,
            final String name, final String desc, final String signature) {
        String wrapperName = TransformationUtil.getWrapperMethodName(name, desc, declaringTypeName,
                GETFIELD_WRAPPER_METHOD_PREFIX);

        StringBuffer wsignature = new StringBuffer();
        wsignature.append('(');
        wsignature.append(')');
        wsignature.append(desc);

        final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, wsignature.toString());
        if (m_addedMethods.contains(wrapperKey)) {
            return;
        }
        m_addedMethods.add(wrapperKey);

        int modifiers = ACC_SYNTHETIC;
        if (isStaticField) {
            modifiers |= ACC_STATIC;
        }

        MethodVisitor mv = cv.visitMethod(modifiers, wrapperName, wsignature.toString(), signature,
                EMPTY_STRING_ARRAY);

        if (isStaticField) {
            mv.visitFieldInsn(GETSTATIC, declaringTypeName, name, desc);
        } else {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, declaringTypeName, name, desc);
        }

        AsmHelper.addReturnStatement(mv, Type.getType(desc));
        mv.visitMaxs(0, 0);
    }

    /**
     * Creates a public wrapper method that delegates to the PUTFIELD instruction of the non-public field.
     * Static method if field is static (PUTSTATIC instr)
     *
     * @param isStaticField
     * @param declaringTypeName
     * @param name
     * @param desc
     * @param signature
     */
    private void createPutFieldWrapperMethod(boolean isStaticField, final String declaringTypeName,
            final String name, final String desc, final String signature) {
        String wrapperName = TransformationUtil.getWrapperMethodName(name, desc, declaringTypeName,
                PUTFIELD_WRAPPER_METHOD_PREFIX);

        StringBuffer wsignature = new StringBuffer();
        wsignature.append('(');
        wsignature.append(desc);
        wsignature.append(')');
        wsignature.append('V');

        final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, wsignature.toString());
        if (m_addedMethods.contains(wrapperKey)) {
            return;
        }
        m_addedMethods.add(wrapperKey);

        int modifiers = ACC_SYNTHETIC;
        if (isStaticField) {
            modifiers |= ACC_STATIC;
        }

        MethodVisitor mv = cv.visitMethod(modifiers, wrapperName, wsignature.toString(), signature,
                EMPTY_STRING_ARRAY);

        Type fieldType = Type.getType(desc);
        if (isStaticField) {
            AsmHelper.loadArgumentTypes(mv, new Type[] { fieldType }, true);
            mv.visitFieldInsn(PUTSTATIC, declaringTypeName, name, desc);
        } else {
            mv.visitVarInsn(ALOAD, 0);
            AsmHelper.loadArgumentTypes(mv, new Type[] { fieldType }, false);
            mv.visitFieldInsn(PUTFIELD, declaringTypeName, name, desc);
        }

        AsmHelper.addReturnStatement(mv, Type.VOID_TYPE);
        mv.visitMaxs(0, 0);
    }

    /**
     * Creates a public wrapper method that delegates to the non-public target method.
     *
     * @param access
     * @param declaringTypeName
     * @param name
     * @param desc
     * @param signature
     * @param exceptions
     */
    private void createMethodWrapperMethod(final int access, final String declaringTypeName, final String name,
            final String desc, final String signature, final String[] exceptions) {
        final String wrapperName = TransformationUtil.getWrapperMethodName(name, desc, declaringTypeName,
                INVOKE_WRAPPER_METHOD_PREFIX);

        final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, desc);
        if (m_addedMethods.contains(wrapperKey)) {
            return;
        }
        m_addedMethods.add(wrapperKey);

        int modifiers = ACC_SYNTHETIC;
        if (Modifier.isStatic(access)) {
            modifiers |= ACC_STATIC;
        }

        MethodVisitor mv = super.visitMethod(modifiers, wrapperName, desc, signature, exceptions);

        if (Modifier.isStatic(access)) {
            AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
            mv.visitMethodInsn(INVOKESTATIC, declaringTypeName, name, desc);
        } else {
            mv.visitVarInsn(ALOAD, 0);
            AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), Modifier.isStatic(access));
            mv.visitMethodInsn(INVOKEVIRTUAL, declaringTypeName, name, desc);
        }

        AsmHelper.addReturnStatement(mv, Type.getReturnType(desc));

        mv.visitMaxs(0, 0);
    }

    /**
     * Creates a public wrapper static method that delegates to the non-public target ctor.
     *
     * @param access
     * @param declaringTypeName
     * @param name
     * @param desc
     * @param signature
     * @param exceptions
     */
    private void createConstructorWrapperMethod(final int access, final String declaringTypeName, final String name,
            final String desc, final String signature, final String[] exceptions) {
        final String wrapperName = TransformationUtil.getWrapperMethodName(name, desc, declaringTypeName,
                INVOKE_WRAPPER_METHOD_PREFIX);

        final String wrapperKey = AlreadyAddedMethodAdapter.getMethodKey(wrapperName, desc);
        if (m_addedMethods.contains(wrapperKey)) {
            return;
        }
        m_addedMethods.add(wrapperKey);

        int modifiers = ACC_SYNTHETIC;
        modifiers |= ACC_STATIC;

        Type declaringType = Type.getType('L' + declaringTypeName + ';');
        String ctorDesc = Type.getMethodDescriptor(declaringType, Type.getArgumentTypes(desc));

        MethodVisitor mv = super.visitMethod(modifiers, wrapperName, ctorDesc, signature, exceptions);

        mv.visitTypeInsn(NEW, declaringTypeName);
        mv.visitInsn(DUP);
        AsmHelper.loadArgumentTypes(mv, Type.getArgumentTypes(desc), true);
        mv.visitMethodInsn(INVOKESPECIAL, declaringTypeName, name, desc);
        AsmHelper.addReturnStatement(mv, declaringType);

        mv.visitMaxs(0, 0);
    }

}