TopLinkClassWeaverpublic class TopLinkClassWeaver extends ClassAdapter implements ConstantsINTERNAL:
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. |
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 void | addGetterMethodForFieldAccess(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 void | addGetterMethodForValueHolder(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 void | addSetterMethodForFieldAccess(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 void | addSetterMethodForValueHolder(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 void | addValueHolder(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.RuntimeVisibleAnnotations | getTransientAnnotation()
RuntimeVisibleAnnotations attrs = new RuntimeVisibleAnnotations();
Annotation transientAnnotation = new Annotation("Ljavax/persistence/Transient;");
attrs.annotations.add(transientAnnotation);
return attrs;
| public void | visit(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 void | visitAttribute(oracle.toplink.libraries.asm.Attribute attr)
if (!alreadyWeaved) {
cv.visitAttribute(attr);
} else {
super.visitAttribute(attr);
}
| public void | visitEnd()
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.CodeVisitor | visitMethod(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);
}
|
|