/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver.bcel;

import java.util.List;

import org.aspectj.apache.bcel.classfile.Attribute;
import org.aspectj.apache.bcel.classfile.ConstantPool;
import org.aspectj.apache.bcel.classfile.Field;
import org.aspectj.apache.bcel.classfile.Synthetic;
import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
import org.aspectj.apache.bcel.generic.FieldGen;
import org.aspectj.util.GenericSignature;
import org.aspectj.util.GenericSignatureParser;
import org.aspectj.weaver.AjAttribute;
import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException;

An AspectJ Field object that is backed by a Bcel Field object.
Author:PARC, Andy Clement
/** * An AspectJ Field object that is backed by a Bcel Field object. * * @author PARC * @author Andy Clement */
final class BcelField extends ResolvedMemberImpl { public static int AccSynthetic = 0x1000; private Field field; private boolean isAjSynthetic; private boolean isSynthetic = false; private AnnotationAJ[] annotations; private final World world; private final BcelObjectType bcelObjectType; private UnresolvedType genericFieldType = null; private boolean unpackedGenericSignature = false; private boolean annotationsOnFieldObjectAreOutOfDate = false; BcelField(BcelObjectType declaringType, Field field) { super(FIELD, declaringType.getResolvedTypeX(), field.getModifiers(), field.getName(), field.getSignature()); this.field = field; this.world = declaringType.getResolvedTypeX().getWorld(); this.bcelObjectType = declaringType; unpackAttributes(world); checkedExceptions = UnresolvedType.NONE; }
Constructs an instance that wrappers a Field object, but where we do not (yet) have a BcelObjectType - usually because the containing type (and this field) are being constructed at runtime (so there is no .class file to retrieve).
/** * Constructs an instance that wrappers a Field object, but where we do not (yet) have a BcelObjectType - usually because the * containing type (and this field) are being constructed at runtime (so there is no .class file to retrieve). */
BcelField(String declaringTypeName, Field field, World world) { super(FIELD, UnresolvedType.forName(declaringTypeName), field.getModifiers(), field.getName(), field.getSignature()); this.field = field; this.world = world; this.bcelObjectType = null; unpackAttributes(world); checkedExceptions = UnresolvedType.NONE; } private void unpackAttributes(World world) { Attribute[] attrs = field.getAttributes(); if (attrs != null && attrs.length > 0) { ISourceContext sourceContext = getSourceContext(world); List<AjAttribute> as = Utility.readAjAttributes(getDeclaringType().getClassName(), attrs, sourceContext, world, (bcelObjectType != null ? bcelObjectType.getWeaverVersionAttribute() : WeaverVersionInfo.CURRENT), new BcelConstantPoolReader(field.getConstantPool())); as.addAll(AtAjAttributes.readAj5FieldAttributes(field, this, world.resolve(getDeclaringType()), sourceContext, world.getMessageHandler())); // FIXME this code has no effect!!!??? it is set to false immediately after the block // for (AjAttribute a : as) { // if (a instanceof AjAttribute.AjSynthetic) { // isAjSynthetic = true; // } else { // throw new BCException("weird field attribute " + a); // } // } } isAjSynthetic = false; for (int i = attrs.length - 1; i >= 0; i--) { if (attrs[i] instanceof Synthetic) { isSynthetic = true; } } // in 1.5, synthetic is a modifier, not an attribute if ((field.getModifiers() & AccSynthetic) != 0) { isSynthetic = true; } } @Override public boolean isAjSynthetic() { return isAjSynthetic; } @Override public boolean isSynthetic() { return isSynthetic; } @Override public boolean hasAnnotation(UnresolvedType ofType) { ensureAnnotationTypesRetrieved(); for (ResolvedType aType : annotationTypes) { if (aType.equals(ofType)) { return true; } } return false; } @Override public ResolvedType[] getAnnotationTypes() { ensureAnnotationTypesRetrieved(); return annotationTypes; } @Override public AnnotationAJ[] getAnnotations() { ensureAnnotationTypesRetrieved(); return annotations; } @Override public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) { ensureAnnotationTypesRetrieved(); for (AnnotationAJ annotation : annotations) { if (annotation.getTypeName().equals(ofType.getName())) { return annotation; } } return null; } private void ensureAnnotationTypesRetrieved() { if (annotationTypes == null) { AnnotationGen annos[] = field.getAnnotations(); if (annos.length == 0) { annotationTypes = ResolvedType.EMPTY_ARRAY; annotations = AnnotationAJ.EMPTY_ARRAY; } else { int annosCount = annos.length; annotationTypes = new ResolvedType[annosCount]; annotations = new AnnotationAJ[annosCount]; for (int i = 0; i < annosCount; i++) { AnnotationGen anno = annos[i]; annotations[i] = new BcelAnnotation(anno, world); annotationTypes[i] = annotations[i].getType(); } } } } @Override public void addAnnotation(AnnotationAJ annotation) { ensureAnnotationTypesRetrieved(); int len = annotations.length; AnnotationAJ[] ret = new AnnotationAJ[len + 1]; System.arraycopy(annotations, 0, ret, 0, len); ret[len] = annotation; annotations = ret; ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1]; System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len); newAnnotationTypes[len] = annotation.getType(); annotationTypes = newAnnotationTypes; annotationsOnFieldObjectAreOutOfDate = true; } public void removeAnnotation(AnnotationAJ annotation) { ensureAnnotationTypesRetrieved(); int len = annotations.length; AnnotationAJ[] ret = new AnnotationAJ[len - 1]; int p = 0; for (AnnotationAJ anno : annotations) { if (!anno.getType().equals(annotation.getType())) { ret[p++] = anno; } } annotations = ret; ResolvedType[] newAnnotationTypes = new ResolvedType[len - 1]; p = 0; for (ResolvedType anno : annotationTypes) { if (!anno.equals(annotation.getType())) { newAnnotationTypes[p++] = anno; } } annotationTypes = newAnnotationTypes; annotationsOnFieldObjectAreOutOfDate = true; }
Unpack the generic signature attribute if there is one and we haven't already done so, then find the true field type of this field (eg. List).
/** * Unpack the generic signature attribute if there is one and we haven't already done so, then find the true field type of this * field (eg. List<String>). */
@Override public UnresolvedType getGenericReturnType() { unpackGenericSignature(); return genericFieldType; } public Field getFieldAsIs() { return field; } public Field getField(ConstantPool cpool) { if (!annotationsOnFieldObjectAreOutOfDate) { return field; } FieldGen newFieldGen = new FieldGen(field, cpool); newFieldGen.removeAnnotations(); // List<AnnotationGen> alreadyHas = fg.getAnnotations(); // if (annotations != null) { // fg.removeAnnotations(); for (AnnotationAJ annotation : annotations) { newFieldGen.addAnnotation(new AnnotationGen(((BcelAnnotation) annotation).getBcelAnnotation(), cpool, true)); } // for (int i = 0; i < annotations.length; i++) { // AnnotationAJ array_element = annotations[i]; // boolean alreadyHasIt = false; // for (AnnotationGen gen : alreadyHas) { // if (gen.getTypeName().equals(array_element.getTypeName())) { // alreadyHasIt = true; // break; // } // } // if (!alreadyHasIt) { // fg.addAnnotation(new AnnotationGen(((BcelAnnotation) array_element).getBcelAnnotation(), cpg, true)); // // } // // } // } field = newFieldGen.getField(); annotationsOnFieldObjectAreOutOfDate = false; // we are now correct again return field; } private void unpackGenericSignature() { if (unpackedGenericSignature) { return; } if (!world.isInJava5Mode()) { this.genericFieldType = getReturnType(); return; } unpackedGenericSignature = true; String gSig = field.getGenericSignature(); if (gSig != null) { // get from generic GenericSignature.FieldTypeSignature fts = new GenericSignatureParser().parseAsFieldSignature(gSig); GenericSignature.ClassSignature genericTypeSig = bcelObjectType.getGenericClassTypeSignature(); GenericSignature.FormalTypeParameter[] parentFormals = bcelObjectType.getAllFormals(); GenericSignature.FormalTypeParameter[] typeVars = ((genericTypeSig == null) ? new GenericSignature.FormalTypeParameter[0] : genericTypeSig.formalTypeParameters); GenericSignature.FormalTypeParameter[] formals = new GenericSignature.FormalTypeParameter[parentFormals.length + typeVars.length]; // put method formal in front of type formals for overriding in // lookup System.arraycopy(typeVars, 0, formals, 0, typeVars.length); System.arraycopy(parentFormals, 0, formals, typeVars.length, parentFormals.length); try { genericFieldType = BcelGenericSignatureToTypeXConverter.fieldTypeSignature2TypeX(fts, formals, world); } catch (GenericSignatureFormatException e) { // development bug, fail fast with good info throw new IllegalStateException("While determing the generic field type of " + this.toString() + " with generic signature " + gSig + " the following error was detected: " + e.getMessage()); } } else { genericFieldType = getReturnType(); } } @Override public void evictWeavingState() { if (field != null) { unpackGenericSignature(); unpackAttributes(world); ensureAnnotationTypesRetrieved(); // this.sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT; field = null; } } }