| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| // dclarke Bug 244124: Enhanced weaving to support extended FetchGroup functionality |
| // 08/23/2010-2.2 Michael O'Brien |
| // - 323043: application.xml module ordering may cause weaving not to occur causing an NPE. |
| // warn if expected "_persistence_//_vh" method not found |
| // instead of throwing NPE during deploy validation. |
| // 19/04/2014-2.6 Lukas Jungmann |
| // - 429992: JavaSE 8/ASM 5.0.1 support (EclipseLink silently ignores Entity classes with lambda expressions) |
| package org.eclipse.persistence.internal.jpa.weaving; |
| |
| import java.util.Iterator; |
| |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.libraries.asm.ClassVisitor; |
| import org.eclipse.persistence.internal.libraries.asm.EclipseLinkClassVisitor; |
| import org.eclipse.persistence.internal.libraries.asm.FieldVisitor; |
| import org.eclipse.persistence.internal.libraries.asm.Label; |
| import org.eclipse.persistence.internal.libraries.asm.MethodVisitor; |
| import org.eclipse.persistence.internal.libraries.asm.Opcodes; |
| import org.eclipse.persistence.internal.libraries.asm.Type; |
| |
| /** |
| * INTERNAL: Weaves classes to allow them to support EclipseLink 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 org.eclipse.persistence.internal.jpa.weaving.MethodWeaver |
| */ |
| |
| public class ClassWeaver extends EclipseLinkClassVisitor implements Opcodes { |
| |
| // PersistenceWeaved |
| public static final String PERSISTENCE_WEAVED_SHORT_SIGNATURE = "org/eclipse/persistence/internal/weaving/PersistenceWeaved"; |
| |
| // ValueHolders |
| public static final String TW_LAZY_SHORT_SIGNATURE = "org/eclipse/persistence/internal/weaving/PersistenceWeavedLazy"; |
| public static final String VHI_CLASSNAME = "org.eclipse.persistence.indirection.WeavedAttributeValueHolderInterface"; |
| public static final String VH_SHORT_SIGNATURE = "org/eclipse/persistence/indirection/ValueHolder"; |
| public static final String VHI_SHORT_SIGNATURE = "org/eclipse/persistence/indirection/WeavedAttributeValueHolderInterface"; |
| public static final String VHI_SIGNATURE = "L" + VHI_SHORT_SIGNATURE + ";"; |
| |
| // Change tracking |
| public static final String TW_CT_SHORT_SIGNATURE = "org/eclipse/persistence/internal/weaving/PersistenceWeavedChangeTracking"; |
| public static final String PCL_SHORT_SIGNATURE = "java/beans/PropertyChangeListener"; |
| public static final String PCL_SIGNATURE = "L" + PCL_SHORT_SIGNATURE + ";"; |
| public static final String CT_SHORT_SIGNATURE = "org/eclipse/persistence/descriptors/changetracking/ChangeTracker"; |
| public static final String PCE_SHORT_SIGNATURE = "java/beans/PropertyChangeEvent"; |
| public static final String PCE_SIGNATURE = "L" + PCE_SHORT_SIGNATURE + ";"; |
| |
| // PersistenceEntity |
| public static final String PERSISTENCE_ENTITY_SHORT_SIGNATURE = "org/eclipse/persistence/internal/descriptors/PersistenceEntity"; |
| public static final String PERSISTENCE_OBJECT_SHORT_SIGNATURE = "org/eclipse/persistence/internal/descriptors/PersistenceObject"; |
| public static final String PERSISTENCE_OBJECT_SIGNATURE = "L" + PERSISTENCE_OBJECT_SHORT_SIGNATURE + ";"; |
| public static final String VECTOR_SIGNATURE = "Ljava/util/Vector;"; |
| public static final String OBJECT_SIGNATURE = "Ljava/lang/Object;"; |
| public static final String STRING_SIGNATURE = "Ljava/lang/String;"; |
| public static final String CACHEKEY_SIGNATURE = "Lorg/eclipse/persistence/internal/identitymaps/CacheKey;"; |
| |
| // Fetch groups |
| public static final String WEAVED_FETCHGROUPS_SHORT_SIGNATURE = "org/eclipse/persistence/internal/weaving/PersistenceWeavedFetchGroups"; |
| public static final String FETCHGROUP_TRACKER_SIGNATURE = "Lorg/eclipse/persistence/queries/FetchGroupTracker;"; |
| public static final String FETCHGROUP_TRACKER_SHORT_SIGNATURE = "org/eclipse/persistence/queries/FetchGroupTracker"; |
| public static final String FETCHGROUP_SHORT_SIGNATURE = "org/eclipse/persistence/queries/FetchGroup"; |
| public static final String FETCHGROUP_SIGNATURE = "Lorg/eclipse/persistence/queries/FetchGroup;"; |
| public static final String SESSION_SIGNATURE = "Lorg/eclipse/persistence/sessions/Session;"; |
| public static final String ENTITY_MANAGER_IMPL_SHORT_SIGNATURE = "org/eclipse/persistence/internal/jpa/EntityManagerImpl"; |
| public static final String PBOOLEAN_SIGNATURE = "Z"; |
| public static final String LONG_SIGNATURE = "J"; |
| |
| // REST |
| public static final String WEAVED_REST_LAZY_SHORT_SIGNATURE = "org/eclipse/persistence/internal/jpa/rs/weaving/PersistenceWeavedRest"; |
| public static final String LIST_RELATIONSHIP_INFO_SIGNATURE = "Ljava/util/List;"; |
| public static final String LIST_RELATIONSHIP_INFO_GENERIC_SIGNATURE = "Ljava/util/List<Lorg/eclipse/persistence/internal/jpa/rs/weaving/RelationshipInfo;>;"; |
| public static final String LINK_SIGNATURE = "Lorg/eclipse/persistence/internal/jpa/rs/metadata/model/Link;"; |
| public static final String ITEM_LINKS_SIGNATURE = "Lorg/eclipse/persistence/internal/jpa/rs/metadata/model/ItemLinks;"; |
| |
| // Cloneable |
| public static final String CLONEABLE_SHORT_SIGNATURE = "java/lang/Cloneable"; |
| |
| // Transient |
| public static final String JPA_TRANSIENT_DESCRIPTION = "Ljakarta/persistence/Transient;"; |
| public static final String XML_TRANSIENT_DESCRIPTION = "Ljakarta/xml/bind/annotation/XmlTransient;"; |
| |
| public static final String PERSISTENCE_SET = Helper.PERSISTENCE_SET; |
| public static final String PERSISTENCE_GET = Helper.PERSISTENCE_GET; |
| |
| // 323403: These constants are used to search for missing weaved functions - |
| // a copy is in the foundation project under internal.Helper |
| public static final String PERSISTENCE_FIELDNAME_PREFIX = "_persistence_"; |
| public static final String PERSISTENCE_FIELDNAME_POSTFIX = "_vh"; |
| |
| public static final String VIRTUAL_GETTER_SIGNATURE = "(" + ClassWeaver.STRING_SIGNATURE + ")" + ClassWeaver.OBJECT_SIGNATURE; |
| public static final String VIRTUAL_SETTER_SIGNATURE = "(" + ClassWeaver.STRING_SIGNATURE + ClassWeaver.OBJECT_SIGNATURE + ")" + ClassWeaver.OBJECT_SIGNATURE; |
| |
| /** Store if JAXB is on the classpath, true in Java SE 6 - 8, maybe true from 9 */ |
| private static Boolean isJAXBOnPath = null; |
| |
| /** |
| * Stores information on the class gathered from the temp class loader and |
| * descriptor. |
| */ |
| protected ClassDetails classDetails; |
| |
| // Keep track of what was weaved. |
| protected boolean alreadyWeaved = false; |
| public boolean weaved = false; |
| public boolean weavedLazy = false; |
| public boolean weavedPersistenceEntity = false; |
| public boolean weavedChangeTracker = false; |
| public boolean weavedFetchGroups = false; |
| public boolean weavedRest = false; |
| |
| /** |
| * Used for primitive conversion. Returns the name of the class that wraps a |
| * given type. |
| */ |
| public static String wrapperFor(int sort) { |
| switch (sort) { |
| case Type.BOOLEAN: |
| return "java/lang/Boolean"; |
| case Type.BYTE: |
| return "java/lang/Byte"; |
| case Type.CHAR: |
| return "java/lang/Character"; |
| case Type.SHORT: |
| return "java/lang/Short"; |
| case Type.INT: |
| return "java/lang/Integer"; |
| case Type.FLOAT: |
| return "java/lang/Float"; |
| case Type.LONG: |
| return "java/lang/Long"; |
| case Type.DOUBLE: |
| return "java/lang/Double"; |
| } |
| return null; |
| } |
| |
| /** |
| * Used for primitive conversion. Returns the name conversion method for the |
| * given type. |
| */ |
| public static void unwrapPrimitive(AttributeDetails attribute, MethodVisitor visitor) { |
| String wrapper = wrapperFor(attribute.getReferenceClassType().getSort()); |
| switch (attribute.getReferenceClassType().getSort()) { |
| case Type.BOOLEAN: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "booleanValue", "()Z", false); |
| return; |
| case Type.BYTE: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "byteValue", "()B", false); |
| return; |
| case Type.CHAR: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "charValue", "()C", false); |
| return; |
| case Type.SHORT: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "shortValue", "()S", false); |
| return; |
| case Type.INT: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "intValue", "()I", false); |
| return; |
| case Type.FLOAT: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "floatValue", "()F", false); |
| return; |
| case Type.LONG: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "longValue", "()J", false); |
| return; |
| case Type.DOUBLE: |
| visitor.visitMethodInsn(INVOKEVIRTUAL, wrapper, "doubleValue", "()D", false); |
| return; |
| } |
| } |
| |
| /** |
| * Return the get method name weaved for a value-holder attribute. |
| */ |
| public static String getWeavedValueHolderGetMethodName(String attributeName) { |
| return Helper.getWeavedValueHolderGetMethodName(attributeName); |
| } |
| |
| /** |
| * Return the set method name weaved for a value-holder attribute. |
| */ |
| public static String getWeavedValueHolderSetMethodName(String attributeName) { |
| return Helper.getWeavedValueHolderSetMethodName(attributeName); |
| } |
| |
| /** |
| * Return if the JAXB classes are on the classpath (if they are the |
| * XmlTransient annotation is added). |
| */ |
| public static boolean isJAXBOnPath() { |
| if (isJAXBOnPath == null) { |
| try { |
| Class.forName("jakarta.xml.bind.annotation.XmlTransient"); |
| isJAXBOnPath = true; |
| } catch (Exception notThere) { |
| isJAXBOnPath = false; |
| } |
| } |
| return isJAXBOnPath; |
| } |
| |
| public ClassWeaver(ClassVisitor classWriter, ClassDetails classDetails) { |
| super(classWriter); |
| this.classDetails = classDetails; |
| } |
| |
| /** |
| * 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 _persistence_variableName_vh; |
| */ |
| public void addValueHolder(AttributeDetails attributeDetails) { |
| String attribute = attributeDetails.getAttributeName(); |
| FieldVisitor fv = cv.visitField(ACC_PROTECTED, PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE, null, null); |
| |
| // only mark @Transient if this is property access. Otherwise, the |
| // @Transient annotation could mistakenly |
| // cause the class to use attribute access. |
| if (attributeDetails.getGetterMethodName() == null || attributeDetails.getGetterMethodName().equals("") || attributeDetails.weaveTransientFieldValueHolders()) { |
| fv.visitAnnotation(JPA_TRANSIENT_DESCRIPTION, true).visitEnd(); |
| if (isJAXBOnPath()) { |
| fv.visitAnnotation(XML_TRANSIENT_DESCRIPTION, true).visitEnd(); |
| } |
| } |
| fv.visitEnd(); |
| } |
| |
| /** |
| * Add a variable of type PropertyChangeListener to the class. When this |
| * method has been run, the class will contain a variable declaration |
| * similar to the following |
| * |
| * private transient _persistence_listener; |
| */ |
| public void addPropertyChangeListener(boolean attributeAccess) { |
| cv.visitField(ACC_PROTECTED + ACC_TRANSIENT, "_persistence_listener", PCL_SIGNATURE, null, null); |
| } |
| |
| /** |
| * Add the implementation of the changeTracker_getPropertyChangeListener |
| * method to the class. The result is a method that looks as follows: |
| * |
| * public PropertyChangeListener _persistence_getPropertyChangeListener() { |
| * return _persistence_listener; } |
| */ |
| public void addGetPropertyChangeListener(ClassDetails classDetails) { |
| MethodVisitor cv_getPCL = cv.visitMethod(ACC_PUBLIC, "_persistence_getPropertyChangeListener", "()" + PCL_SIGNATURE, null, null); |
| cv_getPCL.visitVarInsn(ALOAD, 0); |
| cv_getPCL.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_listener", PCL_SIGNATURE); |
| cv_getPCL.visitInsn(ARETURN); |
| cv_getPCL.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add the implementation of the changeTracker_setPropertyChangeListener |
| * method to the class. The result is a method that looks as follows: |
| * |
| * public void _persistence_setPropertyChangeListener(PropertyChangeListener |
| * propertychangelistener){ _persistence_listener = propertychangelistener; |
| * } |
| */ |
| public void addSetPropertyChangeListener(ClassDetails classDetails) { |
| MethodVisitor cv_setPCL = cv.visitMethod(ACC_PUBLIC, "_persistence_setPropertyChangeListener", "(" + PCL_SIGNATURE + ")V", null, null); |
| cv_setPCL.visitVarInsn(ALOAD, 0); |
| cv_setPCL.visitVarInsn(ALOAD, 1); |
| cv_setPCL.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_listener", PCL_SIGNATURE); |
| cv_setPCL.visitInsn(RETURN); |
| cv_setPCL.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add a method to track property changes. The method will look as follows: |
| * |
| * public void _toplink_propertyChange(String s, Object obj, Object obj1){ |
| * if(_persistence_listener != null {@literal &&} obj != obj1){ |
| * _persistence_listener.propertyChange(new PropertyChangeEvent(this, s, |
| * obj, obj1)); } } |
| */ |
| public void addPropertyChange(ClassDetails classDetails) { |
| // create the _toplink_propertyChange() method |
| MethodVisitor cv_addPC = cv.visitMethod(ACC_PUBLIC, "_persistence_propertyChange", "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", null, null); |
| |
| // if (_toplink_Listener != null) |
| cv_addPC.visitVarInsn(ALOAD, 0); |
| cv_addPC.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_listener", PCL_SIGNATURE); |
| Label l0 = new Label(); |
| cv_addPC.visitJumpInsn(IFNULL, l0); |
| |
| // if (obj != obj1) |
| cv_addPC.visitVarInsn(ALOAD, 2); |
| cv_addPC.visitVarInsn(ALOAD, 3); |
| cv_addPC.visitJumpInsn(IF_ACMPEQ, l0); |
| |
| // _toplink_listener.propertyChange(...); |
| cv_addPC.visitVarInsn(ALOAD, 0); |
| cv_addPC.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_listener", PCL_SIGNATURE); |
| cv_addPC.visitTypeInsn(NEW, PCE_SHORT_SIGNATURE); |
| cv_addPC.visitInsn(DUP); |
| |
| // new PropertyChangeEvent(this, s, obj, obj1) |
| cv_addPC.visitVarInsn(ALOAD, 0); |
| cv_addPC.visitVarInsn(ALOAD, 1); |
| cv_addPC.visitVarInsn(ALOAD, 2); |
| cv_addPC.visitVarInsn(ALOAD, 3); |
| cv_addPC.visitMethodInsn(INVOKESPECIAL, PCE_SHORT_SIGNATURE, "<init>", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", false); |
| cv_addPC.visitMethodInsn(INVOKEINTERFACE, PCL_SHORT_SIGNATURE, "propertyChange", "(" + PCE_SIGNATURE + ")V", true); |
| |
| // } |
| cv_addPC.visitLabel(l0); |
| |
| cv_addPC.visitInsn(RETURN); |
| cv_addPC.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add a method that allows us to lazily initialize a valueholder we have |
| * woven in This allows us to avoid initializing valueholders in the |
| * constructor. |
| * |
| * protected void _persistence_initialize_attribute_vh(){ |
| * if(_persistence_attribute_vh == null){ _persistence_attribute_vh = new |
| * ValueHolder(this.attribute); // or new ValueHolder() if property access. |
| * _persistence_attribute_vh.setIsNewlyWeavedValueHolder(true); } } |
| */ |
| public void addInitializerForValueHolder(ClassDetails classDetails, AttributeDetails attributeDetails) { |
| String attribute = attributeDetails.getAttributeName(); |
| String className = classDetails.getClassName(); |
| |
| // Create a getter method for the new valueholder |
| // protected void _persistence_initialize_attribute_vh(){ |
| MethodVisitor cv_init_VH = cv.visitMethod(ACC_PROTECTED, "_persistence_initialize_" + attribute + PERSISTENCE_FIELDNAME_POSTFIX, "()V", null, null); |
| |
| // if(_persistence_attribute_vh == null){ |
| cv_init_VH.visitVarInsn(ALOAD, 0); |
| cv_init_VH.visitFieldInsn(GETFIELD, className, PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| Label l0 = new Label(); |
| cv_init_VH.visitJumpInsn(IFNONNULL, l0); |
| |
| // _persistence_attribute_vh = new ValueHolder(this.attribute); |
| cv_init_VH.visitVarInsn(ALOAD, 0); |
| cv_init_VH.visitTypeInsn(NEW, VH_SHORT_SIGNATURE); |
| cv_init_VH.visitInsn(DUP); |
| if (attributeDetails.hasField()) { |
| cv_init_VH.visitVarInsn(ALOAD, 0); |
| cv_init_VH.visitFieldInsn(GETFIELD, className, attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| cv_init_VH.visitMethodInsn(INVOKESPECIAL, VH_SHORT_SIGNATURE, "<init>", "(Ljava/lang/Object;)V", false); |
| } else { |
| cv_init_VH.visitMethodInsn(INVOKESPECIAL, VH_SHORT_SIGNATURE, "<init>", "()V", false); |
| } |
| cv_init_VH.visitFieldInsn(PUTFIELD, className, PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| |
| // _persistence_attribute_vh.setIsNewlyWeavedValueHolder(true); |
| cv_init_VH.visitVarInsn(ALOAD, 0); |
| cv_init_VH.visitFieldInsn(GETFIELD, className, PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| cv_init_VH.visitInsn(ICONST_1); |
| cv_init_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "setIsNewlyWeavedValueHolder", "(Z)V", true); |
| |
| // } |
| cv_init_VH.visitLabel(l0); |
| |
| cv_init_VH.visitInsn(RETURN); |
| cv_init_VH.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add a get method for the newly added valueholder. Adds a method of the |
| * following form: |
| * |
| * public WeavedAttributeValueHolderInterface _persistence_getfoo_vh(){ |
| * _persistence_initialize_attributeName_vh(); if |
| * (_persistence_vh.isCoordinatedWithProperty() || |
| * _persistence_foo_vh.isNewlyWeavedValueHolder()){ EntityC object = |
| * (EntityC)getFoo(); if (object != _persistence_foo_vh.getValue()){ |
| * setFoo(object); } } return _persistence_foo_vh; } |
| */ |
| public void addGetterMethodForValueHolder(ClassDetails classDetails, AttributeDetails attributeDetails) { |
| String attribute = attributeDetails.getAttributeName(); |
| String className = classDetails.getClassName(); |
| // Create a getter method for the new valueholder |
| MethodVisitor cv_get_VH = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_GET + attribute + PERSISTENCE_FIELDNAME_POSTFIX, "()" + VHI_SIGNATURE, null, null); |
| |
| // _persistence_initialize_attributeName_vh(); |
| cv_get_VH.visitVarInsn(ALOAD, 0); |
| cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_initialize_" + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, "()V", false); |
| |
| // if (_toplink_foo_vh.isCoordinatedWithProperty() || |
| // _toplink_foo_vh.isNewlyWeavedValueHolder()){ |
| cv_get_VH.visitVarInsn(ALOAD, 0); |
| cv_get_VH.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| cv_get_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "isCoordinatedWithProperty", "()Z", true); |
| Label l0 = new Label(); |
| cv_get_VH.visitJumpInsn(IFNE, l0); |
| cv_get_VH.visitVarInsn(ALOAD, 0); |
| cv_get_VH.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| cv_get_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "isNewlyWeavedValueHolder", "()Z", true); |
| Label l1 = new Label(); |
| cv_get_VH.visitJumpInsn(IFEQ, l1); |
| cv_get_VH.visitLabel(l0); |
| cv_get_VH.visitVarInsn(ALOAD, 0); |
| |
| // EntityC object = (EntityC)getFoo(); |
| if (attributeDetails.getGetterMethodName() != null) { |
| cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), attributeDetails.getGetterMethodName(), "()L" + attributeDetails.getReferenceClassName().replace('.', '/') + ";", false); |
| cv_get_VH.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClassName().replace('.', '/')); |
| } else { |
| cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), PERSISTENCE_GET + attributeDetails.attributeName, "()L" + attributeDetails.getReferenceClassName().replace('.', '/') + ";", false); |
| } |
| 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(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| cv_get_VH.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;", true); |
| 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.getReferenceClassName().replace('.', '/') + ";)V", false); |
| } else { |
| cv_get_VH.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), PERSISTENCE_SET + attributeDetails.getAttributeName(), "(L" + attributeDetails.getReferenceClassName().replace('.', '/') + ";)V", false); |
| } |
| |
| // } |
| cv_get_VH.visitLabel(l1); |
| |
| // return _toplink_foo_vh; |
| cv_get_VH.visitVarInsn(ALOAD, 0); |
| cv_get_VH.visitFieldInsn(GETFIELD, className, PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| cv_get_VH.visitInsn(ARETURN); |
| |
| cv_get_VH.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add a set method for the newly added ValueHolder. Adds a method of this |
| * form: |
| * |
| * public void _persistence_setfoo_vh(WeavedAttributeValueHolderInterface |
| * valueholderinterface){ _persistence_foo_vh = valueholderinterface; if |
| * (valueholderinterface.isInstantiated()){ Object object = getFoo(); Object |
| * value = valueholderinterface.getValue(); if (object != value){ |
| * setFoo((EntityC)value); } } else { foo = null; } } |
| */ |
| public void addSetterMethodForValueHolder(ClassDetails classDetails, AttributeDetails attributeDetails) { |
| String attribute = attributeDetails.getAttributeName(); |
| String className = classDetails.getClassName(); |
| // create a setter method for the new valueholder |
| MethodVisitor cv_set_value = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_SET + attribute + PERSISTENCE_FIELDNAME_POSTFIX, "(" + 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, PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, VHI_SIGNATURE); |
| |
| // if (valueholderinterface.isInstantiated()){ |
| cv_set_value.visitVarInsn(ALOAD, 1); |
| cv_set_value.visitMethodInsn(INVOKEINTERFACE, VHI_SHORT_SIGNATURE, "isInstantiated", "()Z", true); |
| 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.getReferenceClassName().replace('.', '/') + ";", false); |
| } else { |
| cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, PERSISTENCE_GET + attributeDetails.attributeName, "()L" + attributeDetails.getReferenceClassName().replace('.', '/') + ";", false); |
| } |
| 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;", true); |
| cv_set_value.visitVarInsn(ASTORE, 3); |
| |
| // if (object != value){ |
| cv_set_value.visitVarInsn(ALOAD, 2); |
| cv_set_value.visitVarInsn(ALOAD, 3); |
| if (attributeDetails.getSetterMethodName() != null) { |
| 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.getReferenceClassName().replace('.', '/')); |
| cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, attributeDetails.getSetterMethodName(), "(L" + attributeDetails.getReferenceClassName().replace('.', '/') + ";)V", false); |
| //} |
| cv_set_value.visitLabel(l0); |
| } else { |
| Label l1 = new Label(); |
| cv_set_value.visitJumpInsn(IF_ACMPEQ, l1); |
| // _persistence_setFoo((EntityC)value); |
| cv_set_value.visitVarInsn(ALOAD, 0); |
| cv_set_value.visitVarInsn(ALOAD, 3); |
| cv_set_value.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClassName().replace('.', '/')); |
| cv_set_value.visitMethodInsn(INVOKEVIRTUAL, className, PERSISTENCE_SET + attributeDetails.getAttributeName(), "(L" + attributeDetails.getReferenceClassName().replace('.', '/') + ";)V", false); |
| // } |
| cv_set_value.visitLabel(l1); |
| cv_set_value.visitFrame(F_SAME, 0, null, 0, null); |
| Label l2 = new Label(); |
| cv_set_value.visitJumpInsn(GOTO, l2); |
| // } |
| cv_set_value.visitLabel(l0); |
| // else { |
| cv_set_value.visitFrame(F_SAME, 0, null, 0, null); |
| // foo = null; |
| cv_set_value.visitVarInsn(ALOAD, 0); |
| cv_set_value.visitInsn(ACONST_NULL); |
| cv_set_value.visitFieldInsn(PUTFIELD, className, attributeDetails.attributeName, attributeDetails.getReferenceClassType().getDescriptor()); |
| //} |
| cv_set_value.visitLabel(l2); |
| cv_set_value.visitFrame(F_SAME, 0, null, 0, null); |
| } |
| |
| cv_set_value.visitInsn(RETURN); |
| cv_set_value.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Adds a convenience method used to replace a PUTFIELD when field access is |
| * used. The method follows the following form: |
| * |
| * public void _persistence_set_variableName((VariableClas) argument) { |
| * _persistence_checkFetchedForSet("variableName"); |
| * _persistence_initialize_variableName_vh(); |
| * _persistence_propertyChange("variableName", this.variableName, argument); |
| * // if change tracking enabled, wrapping primitives, i.e. Long.valueOf(item) |
| * this.variableName = argument; |
| * _persistence_variableName_vh.setValue(variableName); // if lazy enabled } |
| */ |
| public void addSetterMethodForFieldAccess(ClassDetails classDetails, AttributeDetails attributeDetails) { |
| String attribute = attributeDetails.getAttributeName(); |
| |
| // create _persistence_set_variableName |
| MethodVisitor cv_set = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_SET + attribute, "(" + attributeDetails.getReferenceClassType().getDescriptor() + ")V", null, null); |
| |
| // Get the opcode for the load instruction. This may be different |
| // depending on the type |
| int opcode = attributeDetails.getReferenceClassType().getOpcode(ILOAD); |
| |
| if (classDetails.shouldWeaveFetchGroups()) { |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitLdcInsn(attribute); |
| // _persistence_checkFetchedForSet("variableName"); |
| cv_set.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_checkFetchedForSet", "(Ljava/lang/String;)V", false); |
| } |
| |
| if (classDetails.shouldWeaveChangeTracking()) { |
| if (attributeDetails.weaveValueHolders()) { |
| // _persistence_initialize_variableName_vh(); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_initialize_" + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, "()V", false); |
| |
| // _persistenc_variableName_vh.getValue(); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| cv_set.visitMethodInsn(INVOKEINTERFACE, ClassWeaver.VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;", true); |
| |
| // Add the cast: |
| // (<VariableClass>)_persistenc_variableName_vh.getValue() |
| cv_set.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClassName().replace('.', '/')); |
| |
| // add the assignment: this.variableName = |
| // (<VariableClass>)_persistenc_variableName_vh.getValue(); |
| cv_set.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| } |
| |
| // load the string attribute name as the first argument of the |
| // property change call |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitLdcInsn(attribute); |
| |
| // if the attribute is a primitive, wrap it |
| // e.g. if it is an integer: Integer.valueOf(attribute) |
| // This is the first part of the wrapping |
| String wrapper = ClassWeaver.wrapperFor(attributeDetails.getReferenceClassType().getSort()); |
| if (wrapper != null) { |
| cv_set.visitTypeInsn(NEW, wrapper); |
| cv_set.visitInsn(DUP); |
| } |
| |
| // load the method argument |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitFieldInsn(GETFIELD, classDetails.getClassName(), attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| |
| if (wrapper != null) { |
| // invoke the constructor for wrapping |
| // e.g. Integer.valueOf(variableName) |
| cv_set.visitMethodInsn(INVOKESPECIAL, wrapper, "<init>", "(" + attributeDetails.getReferenceClassType().getDescriptor() + ")V", false); |
| |
| // wrap the method argument |
| // e.g. Integer.valueOf(argument) |
| cv_set.visitTypeInsn(NEW, wrapper); |
| cv_set.visitInsn(DUP); |
| cv_set.visitVarInsn(opcode, 1); |
| cv_set.visitMethodInsn(INVOKESPECIAL, wrapper, "<init>", "(" + attributeDetails.getReferenceClassType().getDescriptor() + ")V", false); |
| } else { |
| // if we are not wrapping the argument, just load it |
| cv_set.visitVarInsn(ALOAD, 1); |
| } |
| // _persistence_propertyChange("variableName", variableName, |
| // argument); |
| cv_set.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_propertyChange", "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", false); |
| } else { |
| if (attributeDetails.weaveValueHolders()) { |
| // _persistence_initialize_variableName_vh(); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_initialize_" + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, "()V", false); |
| |
| // _persistenc_variableName_vh.getValue(); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| cv_set.visitMethodInsn(INVOKEINTERFACE, ClassWeaver.VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;", true); |
| |
| // Add the cast: |
| // (<VariableClass>)_persistenc_variableName_vh.getValue() |
| cv_set.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClassName().replace('.', '/')); |
| |
| // add the assignment: this.variableName = |
| // (<VariableClass>)_persistenc_variableName_vh.getValue(); |
| cv_set.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| } |
| } |
| |
| // Must set variable after raising change event, so event has old and |
| // new value. |
| // variableName = argument |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitVarInsn(opcode, 1); |
| cv_set.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| |
| if (attributeDetails.weaveValueHolders()) { |
| // _persistence_variableName_vh.setValue(argument); |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| cv_set.visitVarInsn(ALOAD, 1); |
| cv_set.visitMethodInsn(INVOKEINTERFACE, ClassWeaver.VHI_SHORT_SIGNATURE, "setValue", "(Ljava/lang/Object;)V", true); |
| } |
| |
| cv_set.visitInsn(RETURN); |
| cv_set.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Adds a convenience method used to replace a GETFIELD when field access is |
| * used. The method follows the following form: |
| * |
| * public (VariableClass) _persistence_get_variableName() { |
| * _persistence_checkFetched("variableName"); |
| * _persistence_initialize_variableName_vh(); this.variableName = |
| * ((VariableClass))_persistence_variableName_vh.getValue(); return |
| * this.variableName; } |
| */ |
| public void addGetterMethodForFieldAccess(ClassDetails classDetails, AttributeDetails attributeDetails) { |
| String attribute = attributeDetails.getAttributeName(); |
| |
| // create the _persistenc_getvariableName method |
| MethodVisitor cv_get = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_GET + attribute, "()" + attributeDetails.getReferenceClassType().getDescriptor(), null, null); |
| |
| if (classDetails.shouldWeaveFetchGroups()) { |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitLdcInsn(attribute); |
| // _persistence_checkFetched("variableName"); |
| cv_get.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_checkFetched", "(Ljava/lang/String;)V", false); |
| } |
| |
| if (attributeDetails.weaveValueHolders()) { |
| // _persistence_initialize_variableName_vh(); |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_initialize_" + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, "()V", false); |
| |
| // _persistenc_variableName_vh.getValue(); |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attribute + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| cv_get.visitMethodInsn(INVOKEINTERFACE, ClassWeaver.VHI_SHORT_SIGNATURE, "getValue", "()Ljava/lang/Object;", true); |
| |
| // Add the cast: |
| // (<VariableClass>)_persistenc_variableName_vh.getValue() |
| cv_get.visitTypeInsn(CHECKCAST, attributeDetails.getReferenceClassName().replace('.', '/')); |
| |
| // add the assignment: this.variableName = |
| // (<VariableClass>)_persistenc_variableName_vh.getValue(); |
| cv_get.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| } |
| |
| // return this.variableName; |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), attribute, attributeDetails.getReferenceClassType().getDescriptor()); |
| // Get the opcode for the return insturction. This may be different |
| // depending on the type. |
| int opcode = attributeDetails.getReferenceClassType().getOpcode(IRETURN); |
| cv_get.visitInsn(opcode); |
| cv_get.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add a variable of type Object to the class. When this method has been |
| * run, the class will contain a variable declarations similar to the |
| * following: |
| * |
| * private Object _persistence_primaryKey; |
| */ |
| public void addPersistenceEntityVariables() { |
| cv.visitField(ACC_PROTECTED + ACC_TRANSIENT, "_persistence_primaryKey", OBJECT_SIGNATURE, null, null); |
| cv.visitField(ACC_PROTECTED + ACC_TRANSIENT, "_persistence_cacheKey", CACHEKEY_SIGNATURE, null, null); |
| } |
| |
| /** |
| * Add an internal post clone method. This will clone value holders to avoid |
| * change original/clone to effect the other. |
| * |
| * public Object _persistence_post_clone() { this._attribute_vh = |
| * this._attribute_vh.clone(); ... this._persistence_listener = null; return |
| * this; } |
| */ |
| public void addPersistencePostClone(ClassDetails classDetails) { |
| // create the _persistence_post_clone() method |
| MethodVisitor cv_clone = cv.visitMethod(ACC_PUBLIC, "_persistence_post_clone", "()Ljava/lang/Object;", null, null); |
| |
| // if there is a weaved superclass, it will implement |
| // _persistence_post_clone. Call that method |
| // super._persistence_post_clone() |
| if (classDetails.getSuperClassDetails() != null && classDetails.getSuperClassDetails().shouldWeaveInternal()) { |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitMethodInsn(INVOKESPECIAL, classDetails.getSuperClassName(), "_persistence_post_clone", "()Ljava/lang/Object;", false); |
| } |
| |
| if (classDetails.shouldWeaveValueHolders()) { |
| for (Iterator<AttributeDetails> iterator = classDetails.getAttributesMap().values().iterator(); iterator.hasNext();) { |
| AttributeDetails attributeDetails = iterator.next(); |
| if (attributeDetails.weaveValueHolders()) { // && |
| // !attributeDetails.isAttributeOnSuperClass()) |
| // { |
| // clone._attribute_vh = this._attribute_vh.clone(); |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| Label label = new Label(); |
| cv_clone.visitJumpInsn(IFNULL, label); |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| cv_clone.visitMethodInsn(INVOKEINTERFACE, ClassWeaver.VHI_SHORT_SIGNATURE, "clone", "()Ljava/lang/Object;", true); |
| cv_clone.visitTypeInsn(CHECKCAST, ClassWeaver.VHI_SHORT_SIGNATURE); |
| cv_clone.visitFieldInsn(PUTFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + attributeDetails.getAttributeName() + PERSISTENCE_FIELDNAME_POSTFIX, ClassWeaver.VHI_SIGNATURE); |
| cv_clone.visitLabel(label); |
| } |
| } |
| } |
| if (classDetails.shouldWeaveChangeTracking()) { |
| // clone._persistence_listener = null; |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitInsn(ACONST_NULL); |
| cv_clone.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_listener", PCL_SIGNATURE); |
| } |
| if (classDetails.shouldWeaveFetchGroups()) { |
| // clone._persistence_fetchGroup = null; |
| // clone._persistence_session = null; |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitInsn(ACONST_NULL); |
| cv_clone.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_fetchGroup", FETCHGROUP_SIGNATURE); |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitInsn(ACONST_NULL); |
| cv_clone.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_session", SESSION_SIGNATURE); |
| } |
| |
| if (!classDetails.isEmbedable()) { |
| // clone._persistence_primaryKey = null; |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitInsn(ACONST_NULL); |
| cv_clone.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_primaryKey", OBJECT_SIGNATURE); |
| } |
| |
| // return clone; |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitInsn(ARETURN); |
| cv_clone.visitMaxs(0, 0); |
| } |
| |
| public void addPersistenceRestMethods(ClassDetails classDetails) { |
| // public List<RelationshipInfo> _persistence_getRelationships() { |
| // return this._persistence_relationshipInfo; |
| // } |
| MethodVisitor cv_getPKVector = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_FIELDNAME_PREFIX + "getRelationships", "()" + LIST_RELATIONSHIP_INFO_SIGNATURE, "()" + LIST_RELATIONSHIP_INFO_GENERIC_SIGNATURE, null); |
| cv_getPKVector.visitVarInsn(ALOAD, 0); |
| cv_getPKVector.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_relationshipInfo", LIST_RELATIONSHIP_INFO_SIGNATURE); |
| cv_getPKVector.visitInsn(ARETURN); |
| cv_getPKVector.visitMaxs(0, 0); |
| |
| // public void _persistence_setRelationships(List<RelationshipInfo> paramList) { |
| // this._persistence_relationshipInfo = paramList; |
| // } |
| MethodVisitor cv_setPKVector = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_FIELDNAME_PREFIX + "setRelationships", "(" + LIST_RELATIONSHIP_INFO_SIGNATURE + ")V", "(" + LIST_RELATIONSHIP_INFO_GENERIC_SIGNATURE + ")V", null); |
| cv_setPKVector.visitVarInsn(ALOAD, 0); |
| cv_setPKVector.visitVarInsn(ALOAD, 1); |
| cv_setPKVector.visitFieldInsn(PUTFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + "relationshipInfo", LIST_RELATIONSHIP_INFO_SIGNATURE); |
| cv_setPKVector.visitInsn(RETURN); |
| cv_setPKVector.visitMaxs(0, 0); |
| |
| // public Link _persistence_getHref() { |
| // return this._persistence_href; |
| // } |
| MethodVisitor cv_getHref = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_FIELDNAME_PREFIX + "getHref", "()" + LINK_SIGNATURE, null, null); |
| cv_getHref.visitVarInsn(ALOAD, 0); |
| cv_getHref.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + "href", LINK_SIGNATURE); |
| cv_getHref.visitInsn(ARETURN); |
| cv_getHref.visitMaxs(0, 0); |
| |
| // public void _persistence_setHref(Link paramLink) |
| // this._persistence_href = paramLink; |
| // } |
| MethodVisitor cv_setHref = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_FIELDNAME_PREFIX + "setHref", "(" + LINK_SIGNATURE + ")V", null, null); |
| cv_setHref.visitVarInsn(ALOAD, 0); |
| cv_setHref.visitVarInsn(ALOAD, 1); |
| cv_setHref.visitFieldInsn(PUTFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + "href", LINK_SIGNATURE); |
| cv_setHref.visitInsn(RETURN); |
| cv_setHref.visitMaxs(0, 0); |
| |
| // public ItemLinks _persistence_getLinks() { |
| // return this._persistence_links; |
| // } |
| MethodVisitor cv_getLinks = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_FIELDNAME_PREFIX + "getLinks", "()" + ITEM_LINKS_SIGNATURE, null, null); |
| cv_getLinks.visitVarInsn(ALOAD, 0); |
| cv_getLinks.visitFieldInsn(GETFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + "links", ITEM_LINKS_SIGNATURE); |
| cv_getLinks.visitInsn(ARETURN); |
| cv_getLinks.visitMaxs(0, 0); |
| |
| // public void _persistence_setLinks(ItemLinks paramItemLinks) { |
| // this._persistence_links = paramItemLinks; |
| // } |
| MethodVisitor cv_setLinks = cv.visitMethod(ACC_PUBLIC, PERSISTENCE_FIELDNAME_PREFIX + "setLinks", "(" + ITEM_LINKS_SIGNATURE + ")V", null, null); |
| cv_setLinks.visitVarInsn(ALOAD, 0); |
| cv_setLinks.visitVarInsn(ALOAD, 1); |
| cv_setLinks.visitFieldInsn(PUTFIELD, classDetails.getClassName(), PERSISTENCE_FIELDNAME_PREFIX + "links", ITEM_LINKS_SIGNATURE); |
| cv_setLinks.visitInsn(RETURN); |
| cv_setLinks.visitMaxs(0, 0); |
| |
| } |
| |
| public void addPersistenceRestVariables() { |
| // protected transient List<RelationshipInfo> _persistence_relationshipInfo; |
| cv.visitField(ACC_PROTECTED | ACC_TRANSIENT, PERSISTENCE_FIELDNAME_PREFIX + "relationshipInfo", LIST_RELATIONSHIP_INFO_SIGNATURE, LIST_RELATIONSHIP_INFO_GENERIC_SIGNATURE, null); |
| // protected transient Link _persistence_href; |
| cv.visitField(ACC_PROTECTED | ACC_TRANSIENT, PERSISTENCE_FIELDNAME_PREFIX + "href", LINK_SIGNATURE, null, null); |
| // protected transient ItemLinks _persistence_links; |
| cv.visitField(ACC_PROTECTED | ACC_TRANSIENT, PERSISTENCE_FIELDNAME_PREFIX + "links", ITEM_LINKS_SIGNATURE, null, null); |
| } |
| |
| /** |
| * Add an internal shallow clone method. This can be used to optimize uow |
| * cloning. |
| * |
| * public Object _persistence_shallow_clone() { return super.clone(); } |
| */ |
| public void addShallowClone(ClassDetails classDetails) { |
| // create the _persistence_shallow_clone() method |
| MethodVisitor cv_clone = cv.visitMethod(ACC_PUBLIC, "_persistence_shallow_clone", "()Ljava/lang/Object;", null, null); |
| |
| // return super.clone(); |
| cv_clone.visitVarInsn(ALOAD, 0); |
| cv_clone.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "clone", "()Ljava/lang/Object;", false); |
| |
| cv_clone.visitInsn(ARETURN); |
| cv_clone.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add an internal empty constructor, and new method. This is used to avoid |
| * unnecessary initialization and avoid reflection. |
| * |
| * public void _persistence_new(PersistenceObject factory) { return new |
| * ClassType(factory); } |
| * |
| * public ClassType(PersistenceObject factory) { super(); } |
| */ |
| public void addPersistenceNew(ClassDetails classDetails) { |
| // create the _persistence_new() method |
| MethodVisitor cv_new = cv.visitMethod(ACC_PUBLIC, "_persistence_new", "(" + PERSISTENCE_OBJECT_SIGNATURE + ")Ljava/lang/Object;", null, null); |
| |
| // return new ClassType(factory); |
| cv_new.visitTypeInsn(NEW, classDetails.getClassName()); |
| cv_new.visitInsn(DUP); |
| if (!classDetails.canWeaveConstructorOptimization()) { |
| cv_new.visitMethodInsn(INVOKESPECIAL, classDetails.getClassName(), "<init>", "()V", false); |
| cv_new.visitInsn(ARETURN); |
| cv_new.visitMaxs(0, 0); |
| return; |
| } else { |
| cv_new.visitVarInsn(ALOAD, 1); |
| cv_new.visitMethodInsn(INVOKESPECIAL, classDetails.getClassName(), "<init>", "(" + PERSISTENCE_OBJECT_SIGNATURE + ")V", false); |
| } |
| cv_new.visitInsn(ARETURN); |
| cv_new.visitMaxs(0, 0); |
| |
| // create the ClassType() method |
| MethodVisitor cv_constructor = cv.visitMethod(ACC_PUBLIC, "<init>", "(" + PERSISTENCE_OBJECT_SIGNATURE + ")V", null, null); |
| |
| cv_constructor.visitVarInsn(ALOAD, 0); |
| if (classDetails.getSuperClassDetails() == null) { |
| // super(); |
| cv_constructor.visitMethodInsn(INVOKESPECIAL, classDetails.getSuperClassName(), "<init>", "()V", false); |
| } else { |
| // super(factory); |
| cv_constructor.visitVarInsn(ALOAD, 1); |
| cv_constructor.visitMethodInsn(INVOKESPECIAL, classDetails.getSuperClassName(), "<init>", "(" + PERSISTENCE_OBJECT_SIGNATURE + ")V", false); |
| } |
| cv_constructor.visitInsn(RETURN); |
| cv_constructor.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add an internal generic get and set method. This is used to avoid |
| * reflection. |
| * |
| * public Object _persistence_get(String attribute) { if (attribute == |
| * "address") { return this.address; } if (attribute == "city") { return |
| * this.city; } return null; } |
| * |
| * public void _persistence_set(int index, Object value) { if (attribute == |
| * "address") { this.address = (String)value; } else if (attribute == |
| * "city") { this.city = (String)city; } } |
| */ |
| public void addPersistenceGetSet(ClassDetails classDetails) { |
| // create the _persistence_get() method |
| MethodVisitor cv_get = cv.visitMethod(ACC_PUBLIC, "_persistence_get", "(Ljava/lang/String;)Ljava/lang/Object;", null, null); |
| |
| Label label = null; |
| for (AttributeDetails attributeDetails : classDetails.getAttributesMap().values()) { |
| if (!attributeDetails.isAttributeOnSuperClass() && !attributeDetails.isVirtualProperty()) { |
| if (label != null) { |
| cv_get.visitLabel(label); |
| } |
| // else if (attribute == "address") |
| cv_get.visitVarInsn(ALOAD, 1); |
| cv_get.visitLdcInsn(attributeDetails.getAttributeName().intern()); |
| label = new Label(); |
| cv_get.visitJumpInsn(IF_ACMPNE, label); |
| // return this.address |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitFieldInsn(GETFIELD, classDetails.getClassName(), attributeDetails.getAttributeName(), attributeDetails.getReferenceClassType().getDescriptor()); |
| // if this is a primitive, get the wrapper class |
| String wrapper = ClassWeaver.wrapperFor(attributeDetails.getReferenceClassType().getSort()); |
| if (wrapper != null) { |
| // Call valueOf on the wrapper (more optimal than |
| // constructor). |
| cv_get.visitMethodInsn(INVOKESTATIC, wrapper, "valueOf", "(" + attributeDetails.getReferenceClassType().getDescriptor() + ")L" + wrapper + ";", false); |
| } |
| |
| cv_get.visitInsn(ARETURN); |
| } |
| } |
| if (label != null) { |
| cv_get.visitLabel(label); |
| } |
| // call super, or return null |
| if (classDetails.getSuperClassDetails() == null) { |
| // return null; |
| cv_get.visitInsn(ACONST_NULL); |
| } else { |
| cv_get.visitVarInsn(ALOAD, 0); |
| cv_get.visitVarInsn(ALOAD, 1); |
| cv_get.visitMethodInsn(INVOKESPECIAL, classDetails.getSuperClassName(), "_persistence_get", "(Ljava/lang/String;)Ljava/lang/Object;", false); |
| } |
| |
| cv_get.visitInsn(ARETURN); |
| cv_get.visitMaxs(0, 0); |
| |
| // create the _persistence_set() method |
| MethodVisitor cv_set = cv.visitMethod(ACC_PUBLIC, "_persistence_set", "(Ljava/lang/String;Ljava/lang/Object;)V", null, null); |
| |
| label = null; |
| for (AttributeDetails attribute : classDetails.getAttributesMap().values()) { |
| if (!attribute.isAttributeOnSuperClass() && !attribute.isVirtualProperty()) { |
| if (label != null) { |
| cv_set.visitLabel(label); |
| } |
| // else if (attribute == "address") |
| cv_set.visitVarInsn(ALOAD, 1); |
| cv_set.visitLdcInsn(attribute.getAttributeName().intern()); |
| label = new Label(); |
| cv_set.visitJumpInsn(IF_ACMPNE, label); |
| // this.address = (String)value; |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitVarInsn(ALOAD, 2); |
| String wrapper = wrapperFor(attribute.getReferenceClassType().getSort()); |
| if (wrapper == null) { |
| wrapper = attribute.getReferenceClassName().replace('.', '/'); |
| } |
| cv_set.visitTypeInsn(CHECKCAST, wrapper); |
| // Unwrap any primitive wrapper to its value. |
| unwrapPrimitive(attribute, cv_set); |
| cv_set.visitFieldInsn(PUTFIELD, classDetails.getClassName(), attribute.getAttributeName(), attribute.getReferenceClassType().getDescriptor()); |
| // return; |
| cv_set.visitInsn(RETURN); |
| } |
| } |
| if (label != null) { |
| cv_set.visitLabel(label); |
| } |
| // call super, or return null |
| if (classDetails.getSuperClassDetails() != null) { |
| cv_set.visitVarInsn(ALOAD, 0); |
| cv_set.visitVarInsn(ALOAD, 1); |
| cv_set.visitVarInsn(ALOAD, 2); |
| cv_set.visitMethodInsn(INVOKESPECIAL, classDetails.getSuperClassName(), "_persistence_set", "(Ljava/lang/String;Ljava/lang/Object;)V", false); |
| } |
| |
| cv_set.visitInsn(RETURN); |
| cv_set.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Adds get/set method for PersistenceEntity interface. This adds the |
| * following methods: |
| * |
| * public Object _persistence_getId() { return _persistence_primaryKey; } |
| * public void _persistence_setId(Object primaryKey) { |
| * this._persistence_primaryKey = primaryKey; } |
| */ |
| public void addPersistenceEntityMethods(ClassDetails classDetails) { |
| MethodVisitor cv_getPKVector = cv.visitMethod(ACC_PUBLIC, "_persistence_getId", "()" + OBJECT_SIGNATURE, null, null); |
| cv_getPKVector.visitVarInsn(ALOAD, 0); |
| cv_getPKVector.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_primaryKey", OBJECT_SIGNATURE); |
| cv_getPKVector.visitInsn(ARETURN); |
| cv_getPKVector.visitMaxs(0, 0); |
| |
| MethodVisitor cv_setPKVector = cv.visitMethod(ACC_PUBLIC, "_persistence_setId", "(" + OBJECT_SIGNATURE + ")V", null, null); |
| cv_setPKVector.visitVarInsn(ALOAD, 0); |
| cv_setPKVector.visitVarInsn(ALOAD, 1); |
| cv_setPKVector.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_primaryKey", OBJECT_SIGNATURE); |
| cv_setPKVector.visitInsn(RETURN); |
| cv_setPKVector.visitMaxs(0, 0); |
| |
| MethodVisitor cv_getCacheKey = cv.visitMethod(ACC_PUBLIC, "_persistence_getCacheKey", "()" + CACHEKEY_SIGNATURE, null, null); |
| cv_getCacheKey.visitVarInsn(ALOAD, 0); |
| cv_getCacheKey.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_cacheKey", CACHEKEY_SIGNATURE); |
| cv_getCacheKey.visitInsn(ARETURN); |
| cv_getCacheKey.visitMaxs(0, 0); |
| |
| MethodVisitor cv_setCacheKey = cv.visitMethod(ACC_PUBLIC, "_persistence_setCacheKey", "(" + CACHEKEY_SIGNATURE + ")V", null, null); |
| cv_setCacheKey.visitVarInsn(ALOAD, 0); |
| cv_setCacheKey.visitVarInsn(ALOAD, 1); |
| cv_setCacheKey.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_cacheKey", CACHEKEY_SIGNATURE); |
| cv_setCacheKey.visitInsn(RETURN); |
| cv_setCacheKey.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Add a variable of type FetchGroup, Session to the class. When this method |
| * has been run, the class will contain a variable declarations similar to |
| * the following: |
| * |
| * private FetchGroup _persistence_fetchGroup; private boolean |
| * _persistence_shouldRefreshFetchGroup; private Session |
| * _persistence_session; |
| */ |
| public void addFetchGroupVariables() { |
| FieldVisitor fv = cv.visitField(ACC_PROTECTED, "_persistence_fetchGroup", FETCHGROUP_SIGNATURE, null, null); |
| // Only add jakarta.persistence.Transient annotation if attribute access |
| // is being used |
| if (classDetails.usesAttributeAccess()) { |
| fv.visitAnnotation(JPA_TRANSIENT_DESCRIPTION, true).visitEnd(); |
| } |
| if (isJAXBOnPath()) { |
| fv.visitAnnotation(XML_TRANSIENT_DESCRIPTION, true).visitEnd(); |
| } |
| fv.visitEnd(); |
| |
| cv.visitField(ACC_PROTECTED + ACC_TRANSIENT, "_persistence_shouldRefreshFetchGroup", PBOOLEAN_SIGNATURE, null, null).visitEnd(); |
| cv.visitField(ACC_PROTECTED + ACC_TRANSIENT, "_persistence_session", SESSION_SIGNATURE, null, null).visitEnd(); |
| } |
| |
| /** |
| * Adds get/set method for FetchGroupTracker interface. This adds the |
| * following methods: |
| * |
| * public Session _persistence_getSession() { return _persistence_session; } |
| * public void _persistence_setSession(Session session) { |
| * this._persistence_session = session; } |
| * |
| * public FetchGroup _persistence_getFetchGroup() { return |
| * _persistence_fetchGroup; } public void |
| * _persistence_setFetchGroup(FetchGroup fetchGroup) { |
| * this._persistence_fetchGroup = fetchGroup; } |
| * |
| * public boolean _persistence_shouldRefreshFetchGroup() { return |
| * _persistence_shouldRefreshFetchGroup; } public void |
| * _persistence_setShouldRefreshFetchGroup(boolean shouldRefreshFetchGroup) |
| * { this._persistence_shouldRefreshFetchGroup = shouldRefreshFetchGroup; } |
| * |
| * public void _persistence_resetFetchGroup() { } |
| * |
| * public void _persistence_isAttributeFetched(String attribute) { return |
| * this._persistence_fetchGroup == null || |
| * _persistence_fetchGroup.containsAttribute(attribute); } |
| * |
| * public void _persistence_checkFetched(String attribute) { if |
| * (this._persistence_fetchGroup != null) { |
| * EntityManagerImpl.processUnfetchedAttribute(this, attribute); } } |
| * |
| * |
| * public void _persistence_checkSetFetched(String attribute) { if |
| * (this._persistence_fetchGroup != null) { |
| * EntityManagerImpl.processUnfetchedAttributeForSet(this, attribute); } } |
| */ |
| public void addFetchGroupMethods(ClassDetails classDetails) { |
| MethodVisitor cv_getSession = cv.visitMethod(ACC_PUBLIC, "_persistence_getSession", "()" + SESSION_SIGNATURE, null, null); |
| cv_getSession.visitVarInsn(ALOAD, 0); |
| cv_getSession.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_session", SESSION_SIGNATURE); |
| cv_getSession.visitInsn(ARETURN); |
| cv_getSession.visitMaxs(0, 0); |
| |
| MethodVisitor cv_setSession = cv.visitMethod(ACC_PUBLIC, "_persistence_setSession", "(" + SESSION_SIGNATURE + ")V", null, null); |
| cv_setSession.visitVarInsn(ALOAD, 0); |
| cv_setSession.visitVarInsn(ALOAD, 1); |
| cv_setSession.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_session", SESSION_SIGNATURE); |
| cv_setSession.visitInsn(RETURN); |
| cv_setSession.visitMaxs(0, 0); |
| |
| MethodVisitor cv_getFetchGroup = cv.visitMethod(ACC_PUBLIC, "_persistence_getFetchGroup", "()" + FETCHGROUP_SIGNATURE, null, null); |
| cv_getFetchGroup.visitVarInsn(ALOAD, 0); |
| cv_getFetchGroup.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_fetchGroup", FETCHGROUP_SIGNATURE); |
| cv_getFetchGroup.visitInsn(ARETURN); |
| cv_getFetchGroup.visitMaxs(0, 0); |
| |
| MethodVisitor cv_setFetchGroup = cv.visitMethod(ACC_PUBLIC, "_persistence_setFetchGroup", "(" + FETCHGROUP_SIGNATURE + ")V", null, null); |
| cv_setFetchGroup.visitVarInsn(ALOAD, 0); |
| cv_setFetchGroup.visitVarInsn(ALOAD, 1); |
| cv_setFetchGroup.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_fetchGroup", FETCHGROUP_SIGNATURE); |
| cv_setFetchGroup.visitInsn(RETURN); |
| cv_setFetchGroup.visitMaxs(0, 0); |
| |
| MethodVisitor cv_shouldRefreshFetchGroup = cv.visitMethod(ACC_PUBLIC, "_persistence_shouldRefreshFetchGroup", "()" + PBOOLEAN_SIGNATURE, null, null); |
| cv_shouldRefreshFetchGroup.visitVarInsn(ALOAD, 0); |
| cv_shouldRefreshFetchGroup.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_shouldRefreshFetchGroup", PBOOLEAN_SIGNATURE); |
| cv_shouldRefreshFetchGroup.visitInsn(IRETURN); |
| cv_shouldRefreshFetchGroup.visitMaxs(0, 0); |
| |
| MethodVisitor cv_setShouldRefreshFetchGroup = cv.visitMethod(ACC_PUBLIC, "_persistence_setShouldRefreshFetchGroup", "(" + PBOOLEAN_SIGNATURE + ")V", null, null); |
| cv_setShouldRefreshFetchGroup.visitVarInsn(ALOAD, 0); |
| cv_setShouldRefreshFetchGroup.visitVarInsn(ILOAD, 1); |
| cv_setShouldRefreshFetchGroup.visitFieldInsn(PUTFIELD, classDetails.getClassName(), "_persistence_shouldRefreshFetchGroup", PBOOLEAN_SIGNATURE); |
| cv_setShouldRefreshFetchGroup.visitInsn(RETURN); |
| cv_setShouldRefreshFetchGroup.visitMaxs(0, 0); |
| |
| MethodVisitor cv_resetFetchGroup = cv.visitMethod(ACC_PUBLIC, "_persistence_resetFetchGroup", "()V", null, null); |
| cv_resetFetchGroup.visitInsn(RETURN); |
| cv_resetFetchGroup.visitMaxs(0, 0); |
| |
| MethodVisitor cv_isAttributeFetched = cv.visitMethod(ACC_PUBLIC, "_persistence_isAttributeFetched", "(Ljava/lang/String;)Z", null, null); |
| cv_isAttributeFetched.visitVarInsn(ALOAD, 0); |
| cv_isAttributeFetched.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_fetchGroup", FETCHGROUP_SIGNATURE); |
| Label gotoTrue = new Label(); |
| cv_isAttributeFetched.visitJumpInsn(IFNULL, gotoTrue); |
| cv_isAttributeFetched.visitVarInsn(ALOAD, 0); |
| cv_isAttributeFetched.visitFieldInsn(GETFIELD, classDetails.getClassName(), "_persistence_fetchGroup", FETCHGROUP_SIGNATURE); |
| cv_isAttributeFetched.visitVarInsn(ALOAD, 1); |
| cv_isAttributeFetched.visitMethodInsn(INVOKEVIRTUAL, FETCHGROUP_SHORT_SIGNATURE, "containsAttributeInternal", "(Ljava/lang/String;)Z", false); |
| Label gotoFalse = new Label(); |
| cv_isAttributeFetched.visitJumpInsn(IFEQ, gotoFalse); |
| cv_isAttributeFetched.visitLabel(gotoTrue); |
| cv_isAttributeFetched.visitInsn(ICONST_1); |
| Label gotoReturn = new Label(); |
| cv_isAttributeFetched.visitJumpInsn(GOTO, gotoReturn); |
| cv_isAttributeFetched.visitLabel(gotoFalse); |
| cv_isAttributeFetched.visitInsn(ICONST_0); |
| cv_isAttributeFetched.visitLabel(gotoReturn); |
| cv_isAttributeFetched.visitInsn(IRETURN); |
| cv_isAttributeFetched.visitMaxs(0, 0); |
| |
| MethodVisitor cv_checkFetched = cv.visitMethod(ACC_PUBLIC, "_persistence_checkFetched", "(Ljava/lang/String;)V", null, null); |
| cv_checkFetched.visitVarInsn(ALOAD, 0); |
| cv_checkFetched.visitVarInsn(ALOAD, 1); |
| cv_checkFetched.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_isAttributeFetched", "(Ljava/lang/String;)Z", false); |
| gotoReturn = new Label(); |
| cv_checkFetched.visitJumpInsn(IFNE, gotoReturn); |
| cv_checkFetched.visitVarInsn(ALOAD, 0); |
| cv_checkFetched.visitTypeInsn(CHECKCAST, FETCHGROUP_TRACKER_SHORT_SIGNATURE); |
| cv_checkFetched.visitVarInsn(ALOAD, 1); |
| cv_checkFetched.visitMethodInsn(INVOKESTATIC, ENTITY_MANAGER_IMPL_SHORT_SIGNATURE, "processUnfetchedAttribute", "(" + FETCHGROUP_TRACKER_SIGNATURE + "Ljava/lang/String;)V", false); |
| cv_checkFetched.visitLabel(gotoReturn); |
| cv_checkFetched.visitInsn(RETURN); |
| cv_checkFetched.visitMaxs(0, 0); |
| |
| MethodVisitor cv_checkFetchedForSet = cv.visitMethod(ACC_PUBLIC, "_persistence_checkFetchedForSet", "(Ljava/lang/String;)V", null, null); |
| cv_checkFetchedForSet.visitVarInsn(ALOAD, 0); |
| cv_checkFetchedForSet.visitVarInsn(ALOAD, 1); |
| cv_checkFetchedForSet.visitMethodInsn(INVOKEVIRTUAL, classDetails.getClassName(), "_persistence_isAttributeFetched", "(Ljava/lang/String;)Z", false); |
| gotoReturn = new Label(); |
| cv_checkFetchedForSet.visitJumpInsn(IFNE, gotoReturn); |
| cv_checkFetchedForSet.visitVarInsn(ALOAD, 0); |
| cv_checkFetchedForSet.visitTypeInsn(CHECKCAST, FETCHGROUP_TRACKER_SHORT_SIGNATURE); |
| cv_checkFetchedForSet.visitVarInsn(ALOAD, 1); |
| cv_checkFetchedForSet.visitMethodInsn(INVOKESTATIC, ENTITY_MANAGER_IMPL_SHORT_SIGNATURE, "processUnfetchedAttributeForSet", "(" + FETCHGROUP_TRACKER_SIGNATURE + "Ljava/lang/String;)V", false); |
| cv_checkFetchedForSet.visitLabel(gotoReturn); |
| cv_checkFetchedForSet.visitInsn(RETURN); |
| cv_checkFetchedForSet.visitMaxs(0, 0); |
| } |
| |
| /** |
| * Visit the class byte-codes and modify to weave Persistence interfaces. |
| * This add PersistenceWeaved, PersistenceWeavedLazy, |
| * PersistenceWeavedChangeTracking, PersistenceEntity, ChangeTracker. The |
| * new interfaces are pass to the super weaver. |
| */ |
| @Override |
| public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { |
| boolean weaveCloneable = true; |
| // To prevent 'double' weaving: scan for PersistenceWeaved interface. |
| for (int index = 0; index < interfaces.length; index++) { |
| String existingInterface = interfaces[index]; |
| if (PERSISTENCE_WEAVED_SHORT_SIGNATURE.equals(existingInterface)) { |
| this.alreadyWeaved = true; |
| super.visit(version, access, name, signature, superName, interfaces); |
| return; |
| } else if (CT_SHORT_SIGNATURE.equals(existingInterface)) { |
| // Disable weaving of change tracking if already implemented |
| // (such as by user). |
| classDetails.setShouldWeaveChangeTracking(false); |
| } else if (CLONEABLE_SHORT_SIGNATURE.equals(existingInterface)) { |
| weaveCloneable = false; |
| } |
| } |
| int newInterfacesLength = interfaces.length; |
| // Cloneable |
| int cloneableIndex = 0; |
| weaveCloneable = classDetails.shouldWeaveInternal() && weaveCloneable && (classDetails.getSuperClassDetails() == null); |
| if (weaveCloneable) { |
| cloneableIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| // PersistenceWeaved |
| int persistenceWeavedIndex = newInterfacesLength; |
| newInterfacesLength++; |
| // PersistenceEntity |
| int persistenceEntityIndex = 0; |
| boolean persistenceEntity = classDetails.shouldWeaveInternal() && (classDetails.getSuperClassDetails() == null) && (!classDetails.isEmbedable()); |
| if (persistenceEntity) { |
| persistenceEntityIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| // PersistenceObject |
| int persistenceObjectIndex = 0; |
| boolean persistenceObject = classDetails.shouldWeaveInternal(); |
| if (persistenceObject) { |
| persistenceObjectIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| // FetchGroupTracker |
| int fetchGroupTrackerIndex = 0; |
| boolean fetchGroupTracker = classDetails.shouldWeaveFetchGroups() && (classDetails.getSuperClassDetails() == null); |
| if (fetchGroupTracker) { |
| fetchGroupTrackerIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| int persistenceWeavedFetchGroupsIndex = 0; |
| if (classDetails.shouldWeaveFetchGroups()) { |
| persistenceWeavedFetchGroupsIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| // PersistenceWeavedLazy |
| int persistenceWeavedLazyIndex = 0; |
| if (classDetails.shouldWeaveValueHolders()) { |
| persistenceWeavedLazyIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| |
| // ChangeTracker |
| boolean changeTracker = !classDetails.doesSuperclassWeaveChangeTracking() && classDetails.shouldWeaveChangeTracking(); |
| int persistenceWeavedChangeTrackingIndex = 0; |
| int changeTrackerIndex = 0; |
| if (changeTracker) { |
| changeTrackerIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| if (classDetails.shouldWeaveChangeTracking()) { |
| persistenceWeavedChangeTrackingIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| |
| int persistenceWeavedRestIndex = 0; |
| boolean weaveRest = classDetails.shouldWeaveREST() && classDetails.getSuperClassDetails() == null; |
| if (weaveRest) { |
| persistenceWeavedRestIndex = newInterfacesLength; |
| newInterfacesLength++; |
| } |
| |
| String[] newInterfaces = new String[newInterfacesLength]; |
| System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length); |
| // Add 'marker' |
| // org.eclipse.persistence.internal.weaving.PersistenceWeaved interface. |
| newInterfaces[persistenceWeavedIndex] = PERSISTENCE_WEAVED_SHORT_SIGNATURE; |
| weaved = true; |
| // Add Cloneable interface. |
| if (weaveCloneable) { |
| newInterfaces[cloneableIndex] = CLONEABLE_SHORT_SIGNATURE; |
| } |
| // Add org.eclipse.persistence.internal.descriptors.PersistenceEntity |
| // interface. |
| if (persistenceEntity) { |
| newInterfaces[persistenceEntityIndex] = PERSISTENCE_ENTITY_SHORT_SIGNATURE; |
| } |
| // Add org.eclipse.persistence.internal.descriptors.PersistenceObject |
| // interface. |
| if (persistenceObject) { |
| newInterfaces[persistenceObjectIndex] = PERSISTENCE_OBJECT_SHORT_SIGNATURE; |
| } |
| // Add org.eclipse.persistence.queries.FetchGroupTracker interface. |
| if (fetchGroupTracker) { |
| newInterfaces[fetchGroupTrackerIndex] = FETCHGROUP_TRACKER_SHORT_SIGNATURE; |
| } |
| if (classDetails.shouldWeaveFetchGroups()) { |
| newInterfaces[persistenceWeavedFetchGroupsIndex] = WEAVED_FETCHGROUPS_SHORT_SIGNATURE; |
| } |
| // Add marker interface for LAZY. |
| if (classDetails.shouldWeaveValueHolders()) { |
| newInterfaces[persistenceWeavedLazyIndex] = TW_LAZY_SHORT_SIGNATURE; |
| } |
| // Add marker interface and change tracker interface for change |
| // tracking. |
| if (changeTracker) { |
| newInterfaces[changeTrackerIndex] = CT_SHORT_SIGNATURE; |
| } |
| if (classDetails.shouldWeaveChangeTracking()) { |
| newInterfaces[persistenceWeavedChangeTrackingIndex] = TW_CT_SHORT_SIGNATURE; |
| } |
| |
| if (weaveRest) { |
| newInterfaces[persistenceWeavedRestIndex] = WEAVED_REST_LAZY_SHORT_SIGNATURE; |
| } |
| |
| String newSignature = null; |
| // fix the signature to include any new methods we weave |
| if (signature != null) { |
| StringBuffer newSignatureBuf = new StringBuffer(); |
| newSignatureBuf.append(signature); |
| |
| for (int i = interfaces.length; i < newInterfaces.length; i++) { |
| newSignatureBuf.append("L" + newInterfaces[i] + ";"); |
| } |
| newSignature = newSignatureBuf.toString(); |
| } |
| |
| cv.visit(version, access, name, newSignature, superName, newInterfaces); |
| } |
| |
| /** |
| * Construct a MethodWeaver and allow it to process the method. |
| */ |
| @Override |
| public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) { |
| MethodVisitor mv = super.visitMethod(access, methodName, desc, signature, exceptions); |
| if (!alreadyWeaved) { |
| // skip constructors, they will not changed |
| if (!"<init>".equals(methodName) && !"<cinit>".equals(methodName)) { |
| // remaining modifications to the 'body' of the class are |
| // delegated to MethodWeaver |
| mv = new MethodWeaver(this, methodName, desc, mv); |
| } |
| } |
| return mv; |
| } |
| |
| /** |
| * Visit the end of the class byte codes. Add any new methods or variables to the end. |
| */ |
| @Override |
| public void visitEnd() { |
| if (!alreadyWeaved) { |
| if (this.classDetails.shouldWeaveInternal()) { |
| |
| // Add a persistence and shallow clone method. |
| addPersistencePostClone(this.classDetails); |
| if (this.classDetails.getSuperClassDetails() == null) { |
| addShallowClone(this.classDetails); |
| if (!this.classDetails.isEmbedable()) { |
| // Add PersistenceEntity variables and methods. |
| addPersistenceEntityVariables(); |
| addPersistenceEntityMethods(this.classDetails); |
| this.weavedPersistenceEntity = true; |
| } |
| } |
| // Add empty new method and generic get/set methods. |
| addPersistenceNew(this.classDetails); |
| addPersistenceGetSet(this.classDetails); |
| } |
| |
| boolean attributeAccess = false; |
| // For each attribute we need to check what methods and variables to |
| // add. |
| for (Iterator<AttributeDetails> iterator = this.classDetails.getAttributesMap().values().iterator(); iterator.hasNext();) { |
| AttributeDetails attributeDetails = iterator.next(); |
| // Only add to 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 (!attributeDetails.isAttributeOnSuperClass()) { |
| 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 (!attributeDetails.isAttributeOnSuperClass()) { |
| weaved = true; |
| weavedLazy = true; |
| addValueHolder(attributeDetails); |
| addInitializerForValueHolder(classDetails, attributeDetails); |
| addGetterMethodForValueHolder(classDetails, attributeDetails); |
| addSetterMethodForValueHolder(classDetails, attributeDetails); |
| } |
| } |
| if (classDetails.shouldWeaveChangeTracking() || classDetails.shouldWeaveFetchGroups() || attributeDetails.weaveValueHolders()) { |
| if (attributeDetails.hasField()) { |
| weaved = true; |
| addGetterMethodForFieldAccess(classDetails, attributeDetails); |
| addSetterMethodForFieldAccess(classDetails, attributeDetails); |
| attributeAccess = true; |
| } |
| } |
| } |
| } |
| if (classDetails.shouldWeaveChangeTracking()) { |
| weaved = true; |
| weavedChangeTracker = true; |
| if ((classDetails.getSuperClassDetails() == null) || (!classDetails.doesSuperclassWeaveChangeTracking())) { |
| addPropertyChangeListener(attributeAccess); |
| addGetPropertyChangeListener(classDetails); |
| addSetPropertyChangeListener(classDetails); |
| addPropertyChange(classDetails); |
| } |
| } |
| if (classDetails.shouldWeaveFetchGroups()) { |
| weaved = true; |
| weavedFetchGroups = true; |
| if (classDetails.getSuperClassDetails() == null) { |
| addFetchGroupVariables(); |
| addFetchGroupMethods(this.classDetails); |
| } |
| } |
| } |
| if (classDetails.shouldWeaveREST() && classDetails.getSuperClassDetails() == null) { |
| weavedRest = true; |
| addPersistenceRestVariables(); |
| addPersistenceRestMethods(classDetails); |
| } |
| cv.visitEnd(); |
| } |
| } |