FileDocCategorySizeDatePackage
TopLinkClassWeaver.javaAPI DocGlassfish v2 API18834Tue May 22 16:54:44 BST 2007oracle.toplink.essentials.internal.weaving

TopLinkClassWeaver

public class TopLinkClassWeaver extends ClassAdapter implements Constants
INTERNAL: Weaves classes to allow them to support TopLink indirection. Classes are weaved to add a variable of type ValueHolderInterface for each attribute that uses indirection. In addition, access methods are added for the new variable. Also, triggers the process of weaving the methods of the class.
see
oracle.toplink.essentials.internal.weaving.TopLinkMethodWeaver

Fields Summary
public static final String
VHI_CLASSNAME
public static final String
VH_SHORT_SIGNATURE
public static final String
VHI_SHORT_SIGNATURE
public static final String
VHI_SIGNATURE
public static final String
TW_SHORT_SIGNATURE
protected ClassDetails
classDetails
public boolean
alreadyWeaved
public boolean
weavedVH
Constructors Summary
public TopLinkClassWeaver(ClassWriter classWriter, ClassDetails classDetails)


         
        super(classWriter);
        this.classDetails = classDetails;
    
Methods Summary
public voidaddGetterMethodForFieldAccess(oracle.toplink.essentials.internal.weaving.ClassDetails classDetails, oracle.toplink.essentials.internal.weaving.AttributeDetails attributeDetails)
INTERNAL: Adds a convenience method used to replace a GETFIELD when field access is used. The method follows the following form: public _toplink_getvariableName(){ this.item = ()_toplink_variableName_vh.getValue(); return this.item; }

        String attribute = attributeDetails.getAttributeName();

        CodeVisitor cv_get = cv.visitMethod(ACC_PUBLIC, "_toplink_get" + attribute, "()L" + attributeDetails.getReferenceClass().replace('.",'/") + ";", null, null);
        cv_get.visitVarInsn(ALOAD, 0);
        cv_get.visitVarInsn(ALOAD, 0);
        cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", TopLinkClassWeaver.VHI_SIGNATURE);
        cv_get.visitMethodInsn(INVOKEINTERFACE, TopLinkClassWeaver.VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;");
        cv_get.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClass().replace('.",'/"));
        cv_get.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, "L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");
        cv_get.visitVarInsn(ALOAD, 0);
        cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), attribute, "L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");
        cv_get.visitInsn(ARETURN);
        cv_get.visitMaxs(0, 0);
    
public voidaddGetterMethodForValueHolder(oracle.toplink.essentials.internal.weaving.ClassDetails classDetails, oracle.toplink.essentials.internal.weaving.AttributeDetails attributeDetails)
INTERNAL: Add a get method for the newly added valueholder. Adds a method of the following form: public WeavedAttributeValueHolderInterface _toplink_getfoo_vh(){ if (_toplink_foo_vh.isCoordinatedWithProperty() || _toplink_foo_vh.isNewlyWeavedValueHolder()){ EntityC object = getFoo(); if (object != _toplink_foo_vh.getValue()){ setFoo(object); } } return _toplink_foo_vh; }

        String attribute = attributeDetails.getAttributeName();
        String className = classDetails.getClassName();
        // Create a getter method for the new valueholder
        CodeVisitor cv_get_VH = cv.visitMethod(ACC_PUBLIC, "_toplink_get" + attribute + "_vh", "()" + VHI_SIGNATURE, null, null);
        cv_get_VH.visitVarInsn(ALOAD, 0);
        
        // if (_toplink_foo_vh.isCoordinatedWithProperty() || _toplink_foo_vh.isNewlyWeavedValueHolder()){
        cv_get_VH.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", VHI_SIGNATURE);
        cv_get_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "isCoordinatedWithProperty", "()Z");       
        Label l0 = new Label();
        cv_get_VH.visitJumpInsn(IFNE, l0);
        cv_get_VH.visitVarInsn(ALOAD, 0);
        cv_get_VH.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", VHI_SIGNATURE);
        cv_get_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "isNewlyWeavedValueHolder", "()Z");
        Label l1 = new Label();
        cv_get_VH.visitJumpInsn(IFEQ, l1);
        cv_get_VH.visitLabel(l0);
        cv_get_VH.visitVarInsn(ALOAD, 0);    
        
        // EntityC object = getFoo();
        if (attributeDetails.getGetterMethodName() != null){
            cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), attributeDetails.getGetterMethodName(), "()L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");    
        } else {
            cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_toplink_get" + attributeDetails.attributeName, "()L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");                
        }
        cv_get_VH.visitVarInsn(ASTORE, 1);

        // if (object != _toplink_foo_vh.getValue()){
        cv_get_VH.visitVarInsn(ALOAD, 1);
        cv_get_VH.visitVarInsn(ALOAD, 0);
        cv_get_VH.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", VHI_SIGNATURE);
        cv_get_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;");
        cv_get_VH.visitJumpInsn(IF_ACMPEQ, l1);
        
        // setFoo(object);
        cv_get_VH.visitVarInsn(ALOAD, 0);
        cv_get_VH.visitVarInsn(ALOAD, 1);
        if (attributeDetails.getSetterMethodName() != null){
            cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), attributeDetails.getSetterMethodName(), "(L" + attributeDetails.getReferenceClass().replace('.",'/") + ";)V");
        } else {
            cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_toplink_set" + attributeDetails.getAttributeName(), "(L" + attributeDetails.getReferenceClass().replace('.",'/") + ";)V");
        }
        
        // }
        cv_get_VH.visitLabel(l1); 
        
        // return _toplink_foo_vh;
        cv_get_VH.visitVarInsn(ALOAD, 0);
        cv_get_VH.visitFieldInsn(GETFIELD, className, "_toplink_" + attribute + "_vh", VHI_SIGNATURE);
        cv_get_VH.visitInsn(ARETURN);

        cv_get_VH.visitMaxs(0, 0);
    
public voidaddSetterMethodForFieldAccess(oracle.toplink.essentials.internal.weaving.ClassDetails classDetails, oracle.toplink.essentials.internal.weaving.AttributeDetails attributeDetails)
INTERNAL: Adds a convenience method used to replace a PUTFIELD when field access is used. The method follows the following form: public void _toplink_setvariableName( item) { _toplink_variableName_vh.setValue(item); this.item = item; }

        String attribute = attributeDetails.getAttributeName();
        CodeVisitor cv_set = cv.visitMethod(ACC_PUBLIC, "_toplink_set" + attribute, "(L" + attributeDetails.getReferenceClass().replace('.",'/") + ";)V", null, null);
        cv_set.visitVarInsn(ALOAD, 0);
        cv_set.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_toplink_" + attribute + "_vh", TopLinkClassWeaver.VHI_SIGNATURE);
        cv_set.visitVarInsn(ALOAD, 1);
        cv_set.visitMethodInsn(INVOKEINTERFACE, TopLinkClassWeaver.VHI_SHORT_SIGNATURE, "setValue", "(Ljava/lang/Object;)V");
        cv_set.visitVarInsn(ALOAD, 0);
        cv_set.visitVarInsn(ALOAD, 1);
        cv_set.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, "L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");
        cv_set.visitInsn(RETURN);
        cv_set.visitMaxs(0 ,0);
    
public voidaddSetterMethodForValueHolder(oracle.toplink.essentials.internal.weaving.ClassDetails classDetails, oracle.toplink.essentials.internal.weaving.AttributeDetails attributeDetails)
INTERNAL: Add a set method for the newly added ValueHolder. Adds a method of this form: public void _toplink_setfoo_vh(WeavedAttributeValueHolderInterface valueholderinterface){ _toplink_foo_vh = valueholderinterface; if (valueholderinterface.isInstantiated()){ Object object = getFoo(); Object value = valueholderinterface.getValue(); if (object != value){ setFoo((EntityC)value); } } }

        String attribute = attributeDetails.getAttributeName();
        String className = classDetails.getClassName();
        // create a setter method for the new valueholder
        CodeVisitor cv_set_value = cv.visitMethod(ACC_PUBLIC, "_toplink_set" + attribute + "_vh", "(" + VHI_SIGNATURE + ")V", null, null);                                 
        
        // _toplink_foo_vh = valueholderinterface;
        cv_set_value.visitVarInsn(ALOAD, 0);
        cv_set_value.visitVarInsn(ALOAD, 1);
        cv_set_value.visitFieldInsn(PUTFIELD, className, "_toplink_" + attribute + "_vh", VHI_SIGNATURE);    
        
        // if (valueholderinterface.isInstantiated()){
        cv_set_value.visitVarInsn(ALOAD, 1);
        cv_set_value.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "isInstantiated", "()Z");
        Label l0 = new Label();
        cv_set_value.visitJumpInsn(IFEQ, l0);
        
        // Object object = getFoo();
        cv_set_value.visitVarInsn(ALOAD, 0);            
         if (attributeDetails.getGetterMethodName() != null){
            cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, attributeDetails.getGetterMethodName(), "()L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");    
        } else {
            cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, "_toplink_get" + attributeDetails.attributeName, "()L" + attributeDetails.getReferenceClass().replace('.",'/") + ";");                
        }
        cv_set_value.visitVarInsn(ASTORE, 2);
        
        // Object value = valueholderinterface.getValue();
        cv_set_value.visitVarInsn(ALOAD, 1);
        cv_set_value.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;");
        cv_set_value.visitVarInsn(ASTORE, 3);       
        
        // if (object != value){
        cv_set_value.visitVarInsn(ALOAD, 2);
        cv_set_value.visitVarInsn(ALOAD, 3);
        cv_set_value.visitJumpInsn(IF_ACMPEQ, l0);
        
        // setFoo((EntityC)value);
        cv_set_value.visitVarInsn(ALOAD, 0);
        cv_set_value.visitVarInsn(ALOAD, 3);
        cv_set_value.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClass().replace('.",'/"));
         if (attributeDetails.getSetterMethodName() != null){
            cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, attributeDetails.getSetterMethodName(), "(L" + attributeDetails.getReferenceClass().replace('.",'/") + ";)V");
        } else {
            cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, "_toplink_set" + attributeDetails.getAttributeName(), "(L" + attributeDetails.getReferenceClass().replace('.",'/") + ";)V");
        }

        // }
        cv_set_value.visitLabel(l0);
        
        
        cv_set_value.visitInsn(RETURN);
        cv_set_value.visitMaxs(0, 0);
        
    
public voidaddValueHolder(oracle.toplink.essentials.internal.weaving.AttributeDetails attributeDetails)
INTERNAL: Add a variable of type ValueHolderInterface to the class. When this method has been run, the class will contain a variable declaration similar to the following: private ValueHolderInterface _toplink_variableName_vh;

        String attribute = attributeDetails.getAttributeName();
        RuntimeVisibleAnnotations annotations = null;
        if (attributeDetails.getGetterMethodName() == null || attributeDetails.getGetterMethodName().equals("")){
            annotations = getTransientAnnotation();
        }
        weavedVH = true;  
        cv.visitField(ACC_PRIVATE, "_toplink_" + attribute + "_vh", VHI_SIGNATURE, null, annotations);
    
private oracle.toplink.libraries.asm.attrs.RuntimeVisibleAnnotationsgetTransientAnnotation()

        RuntimeVisibleAnnotations attrs = new RuntimeVisibleAnnotations();
        Annotation transientAnnotation = new Annotation("Ljavax/persistence/Transient;");
        attrs.annotations.add(transientAnnotation);
        return attrs;
    
public voidvisit(int version, int access, java.lang.String name, java.lang.String superName, java.lang.String[] interfaces, java.lang.String sourceFile)


        // prevent 'double' weaving: scan for TopLinkWeaved interface
        for (int i = 0; i < interfaces.length; i++) {
            String s = interfaces[i];
            if (TW_SHORT_SIGNATURE.equals(s)) {
                alreadyWeaved = true;
                break;
            }
        }
        
        if (!alreadyWeaved) {
            int len = 1 + interfaces.length;
            String[] newInterfaces = new String[len];
            System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
			// add 'marker' oracle.toplink.essentials.internal.weaving.TopLinkWeaved interface
            newInterfaces[interfaces.length] = TW_SHORT_SIGNATURE;
            super.visit(version, access, name, superName, newInterfaces,
                sourceFile);
        } else {
            super.visit(version, access, name, superName, interfaces, sourceFile);
        }

    
public voidvisitAttribute(oracle.toplink.libraries.asm.Attribute attr)

        if (!alreadyWeaved) {
            cv.visitAttribute(attr);
        } else {
            super.visitAttribute(attr);
        }
    
public voidvisitEnd()

        if (!alreadyWeaved) {
            // add implementation of weavedValueHolders() method in the TopLinkWeaved interface
            // this method will return true if we have weaved and false otherwise.
            CodeVisitor cv_weavedValueHolders = cv.visitMethod(ACC_PUBLIC,
                "weavedValueHolders", "()Z", null, null);
            if (classDetails.weavedValueHolders()) {
                cv_weavedValueHolders.visitInsn(ICONST_1);
            } else {
                cv_weavedValueHolders.visitInsn(ICONST_0);
            }
            cv_weavedValueHolders.visitInsn(IRETURN);
            cv_weavedValueHolders.visitMaxs(0, 0);
        }
        
        // for each attribute we need to check what methods and variables to add
        for (Iterator i = classDetails.getAttributesMap().values().iterator();i.hasNext();) {
            AttributeDetails attributeDetails = (AttributeDetails)i.next();
            if (attributeDetails.weaveValueHolders()) {
                
                // we will add valueholders and methods to classes that have not already been weaved
                // and classes that actually contain the attribute we are processing
                // an attribute could be in the classDetails but not actually in the class
                // if it is owned by a MappedSuperClass
                if (!alreadyWeaved && !attributeDetails.isAttributeOnSuperClass()){
                    addValueHolder(attributeDetails);
                    addGetterMethodForValueHolder(classDetails, attributeDetails);
                    addSetterMethodForValueHolder(classDetails, attributeDetails);
                    
                    // We only add the following convenience method if we are using attribute access.
                    if (attributeDetails.getMapping().usesIndirection() && attributeDetails.isMappedWithAttributeAccess()){
                        addSetterMethodForFieldAccess(classDetails, attributeDetails);
                        addGetterMethodForFieldAccess(classDetails, attributeDetails);
                    }
                }
 
            }
        }
        super.visitEnd();
    
public oracle.toplink.libraries.asm.CodeVisitorvisitMethod(int access, java.lang.String methodName, java.lang.String desc, java.lang.String[] exceptions, oracle.toplink.libraries.asm.Attribute attrs)
INTERNAL: Construct a TopLinkMethodWeaver and allow it to process the method.


        if (!alreadyWeaved) {
            return new TopLinkMethodWeaver(this, methodName, desc, cv.visitMethod(access, methodName, desc, exceptions, attrs));
        } else {
            return super.visitMethod(access, methodName, desc, exceptions, attrs);
        }