icom.weaver.JpaMethodAdapter.java Source code

Java tutorial

Introduction

Here is the source code for icom.weaver.JpaMethodAdapter.java

Source

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER
 * 
 * Copyright (c) 2010, Oracle Corporation All Rights Reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License ("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can obtain
 * a copy of the License at http://openjdk.java.net/legal/gplv2+ce.html.
 * See the License for the specific language governing permission and
 * limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at openICOM/bootstrap/legal/LICENSE.txt.
 * Oracle designates this particular file as subject to the "Classpath" exception
 * as provided by Oracle in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [ ] replaced by your own
 * identifying information:  "Portions Copyrighted [year]
 * [name of copyright owner].
 *
 * Contributor(s): Oracle Corporation
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package icom.weaver;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class JpaMethodAdapter extends MethodAdapter implements Opcodes, Descriptors {

    ClassDefinition classDefn;
    int oprandStackIncrement;

    String methodName;
    String methodDescriptor;

    public JpaMethodAdapter(MethodVisitor mv, ClassDefinition classDefn, String methodName,
            String methodDescriptor) {
        super(mv);
        this.classDefn = classDefn;
        this.methodName = methodName;
        this.methodDescriptor = methodDescriptor;
    }

    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        if (opcode == GETFIELD) {
            interceptGetField(opcode, owner, name, desc);
        } else if (opcode == PUTFIELD) {
            interceptPutField(opcode, owner, name, desc);
        } else {
            super.visitFieldInsn(opcode, owner, name, desc);
        }
    }

    public boolean isCurrentMethodAccessorOfField(String fieldName) {
        return false;
    }

    // TODO need to support boxing of primitive types before calling pre and post methods
    public void interceptGetField(int opcode, String owner, String name, String desc) {
        FieldDefinition fieldDefn = classDefn.managedFields.get(name);
        if (fieldDefn != null && !isCurrentMethodAccessorOfField(name)) {
            /*  inject preGet("fieldX") before GETFIELD
            */
            // at this point stack has (..., [object]) which is ready for GETFIELD
            // DUP [object]
            mv.visitInsn(DUP);
            // stack has (..., [object], [object])  
            // push [this]
            mv.visitVarInsn(ALOAD, 0);
            // stack has (..., [object], [object], [this])
            Label label = new Label();
            // if ([object] == [this])
            mv.visitJumpInsn(IF_ACMPNE, label);
            // stack has (..., [this]) because (object == this)
            // DUP [this]
            mv.visitInsn(DUP);
            // stack has (..., [this], [this])
            // push "fieldX"
            mv.visitLdcInsn(name);
            // stack has (..., [this], [this], "fieldX")
            // invoke preGet("fieldX")
            mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, preGetMethodName, preGetMethodDesc);
            // stack has (..., [this])
            // label:
            mv.visitLabel(label);
            // Frame TODO
            // mv.visitFrame(??, 0, null, 0, null);
            // stack has (..., [object])
            if (oprandStackIncrement < 3) {
                oprandStackIncrement = 3;
            }
        }
        // stack has (..., [object])
        // GETFIELD
        super.visitFieldInsn(opcode, owner, name, desc);
    }

    // TODO need to support boxing of primitive types before calling pre and post methods
    public void interceptPutField(int opcode, String owner, String name, String desc) {
        FieldDefinition fieldDefn = classDefn.managedFields.get(name);
        if (fieldDefn != null && !isCurrentMethodAccessorOfField(name)) {
            if (fieldDefn.isCollection() && (fieldDefn.isEntity() || fieldDefn.isEmbedded())) {
                super.visitFieldInsn(opcode, owner, name, desc);
                return;
            }
            char[] field = name.toCharArray();
            field[0] = Character.toUpperCase(field[0]);
            String getterMethodName = "get" + String.valueOf(field);
            String getterMethodDesc = "()" + desc;

            /*  inject preSet before PUTFIELD and postSet after PUTFIELD
            */
            // at this point stack has (..., [this], [fieldX]) which is ready for PUTFIELD  
            // push [this]
            mv.visitVarInsn(ALOAD, 0);
            // stack has (..., [this], [fieldX], [this])
            mv.visitInsn(DUP2);
            // stack has (..., [this], [fieldX], [this], [fieldX], [this])
            // push "fieldX"
            mv.visitLdcInsn(name);
            // stack has (..., [this], [fieldX], [this], [fieldX], [this], "fieldX")
            mv.visitInsn(DUP_X2);
            // stack has (..., [this], [fieldX], [this], "fieldX", [fieldX], [this], "fieldX")
            // pop                         
            mv.visitInsn(POP);
            // stack has (..., [this], [fieldX], [this], "fieldX", [fieldX], [this])
            // invoke getFieldX()
            mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, getterMethodName, getterMethodDesc);
            // stack has (..., [this], [fieldX], [this], "fieldX", [fieldX], getFieldX())
            mv.visitInsn(SWAP);
            // stack has (..., [this], [fieldX], [this], "fieldX", getFieldX(), [fieldX])
            if (fieldDefn.isEntity()) {
                // invoke preSet("fieldX", getFieldX(), [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, preSetMethodName, preSetMethodDesc);
            } else if (fieldDefn.isEmbedded()) {
                // invoke preSetEmbedded("fieldX", getFieldX(), [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, preSetEmbeddedMethodName,
                        preSetEmbeddedMethodDesc);
            } else if (fieldDefn.isBasic()) {
                // invoke preSetBasic("fieldX", getFieldX(), [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, preSetBasicMethodName,
                        preSetBasicMethodDesc);
            } else {
                // invoke preSetAmbiguous("fieldX", getFieldX(), [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, preSetAmbiguousMethodName,
                        preSetAmbiguousMethodDesc);
            }
            // stack has (..., [this], [fieldX], preSet())
            // DUP IRETURN value of preSet() beneath third word
            mv.visitInsn(DUP_X2);
            // stack has (..., preSet(), [this], [fieldX], preSet())
            mv.visitInsn(POP);
            // stack has (..., preSet(), [this], [fieldX])
            mv.visitInsn(DUP_X2);
            // stack has (..., [fieldX], preSet(), [this], [fieldX])

            // PUTFIELD in [this].[fieldX]
            super.visitFieldInsn(opcode, owner, name, desc);
            // stack has (..., [fieldX], preSet())

            /* inject postSet after PUTFIELD
               if (IRETURN value of preSet() is false && [this].[fieldX] == [fieldX])
              postSet...
            */
            Label label1 = new Label();
            // stack has (..., [fieldX], preSet())
            // if true goto label, there is not change by PUTFIELD
            mv.visitJumpInsn(IFGT, label1);
            // stack has (..., [fieldX])
            mv.visitInsn(DUP);
            // stack has (..., [fieldX], [fieldX])
            // push [this]
            mv.visitVarInsn(ALOAD, 0);
            // stack has (..., [fieldX], [fieldX], [this])
            // get [this].[fieldX]
            mv.visitFieldInsn(GETFIELD, classDefn.internalClassName, name, desc);
            // stack has (..., [fieldX], [fieldX], [this].[fieldX])
            // if ([this].[fieldX] == [fieldX])
            mv.visitJumpInsn(IF_ACMPNE, label1); // jump if !=
            // stack has (..., [fieldX])
            // push [this]
            mv.visitVarInsn(ALOAD, 0);
            // stack has (..., [fieldX], [this])
            mv.visitInsn(SWAP);
            // stack has (..., [this], [fieldX])
            // push "fieldX"
            mv.visitLdcInsn(name);
            // stack has (..., [this], [fieldX], "fieldX")
            mv.visitInsn(SWAP);
            // stack has (..., [this], "fieldX", [fieldX])
            if (fieldDefn.isEntity()) {
                // stack has (..., [this], "fieldX", [fieldX])
                mv.visitInsn(POP);
                // stack has (..., [this], "fieldX") 
                // invoke postSet("fieldX")
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, postSetMethodName,
                        postSetMethodDesc);
                // stack has (...)
            } else if (fieldDefn.isEmbedded()) {
                // stack has (..., [this], "fieldX", [fieldX])
                // invoke postSetEmbedded("fieldX", [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, postSetEmbeddedMethodName,
                        postSetEmbeddedMethodDesc);
                // stack has (...)
            } else if (fieldDefn.isBasic()) {
                // stack has (..., [this], "fieldX", [fieldX])
                // invoke postSetBasic("fieldX", [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, postSetBasicMethodName,
                        postSetBasicMethodDesc);
                // stack has (...)
            } else {
                // stack has (..., [this], "fieldX", [fieldX])
                // invoke postSetAmbiguous("fieldX", [fieldX])
                mv.visitMethodInsn(INVOKEVIRTUAL, classDefn.internalClassName, postSetAmbiguousMethodName,
                        postSetAmbiguousMethodDesc);
                // stack has (...)
            }
            Label label2 = new Label();
            mv.visitJumpInsn(GOTO, label2);
            // label1:
            mv.visitLabel(label1);
            // stack has (..., [fieldX])
            mv.visitInsn(POP);
            // stack has (...)
            // label2:
            mv.visitLabel(label2);
            // stack has (...)

            // Frame TODO
            // mv.visitFrame(F_SAME, 0, null, 0, null);
            if (oprandStackIncrement < 9) {
                oprandStackIncrement = 9;
            }
            return;
        }
        super.visitFieldInsn(opcode, owner, name, desc);
    }

    public void visitMaxs(int maxStack, int maxLocals) {
        //maxStack += oprandStackIncrement;
        super.visitMaxs(maxStack, maxLocals);
    }

}