All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/* *******************************************************************
 * Copyright (c) 2005 Contributors.
 * All rights reserved.
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v 2.0
 * which accompanies this distribution and is available at
 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
 *
 * Contributors:
 *   Adrian Colyer			Initial implementation
 * ******************************************************************/
package org.aspectj.weaver.reflect;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Set;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjType;
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.Pointcut;
import org.aspectj.weaver.AnnotationAJ;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.TypeVariable;
import org.aspectj.weaver.TypeVariableReferenceType;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.tools.PointcutDesignatorHandler;
import org.aspectj.weaver.tools.PointcutParameter;

/**
 * Provides Java 5 behaviour in reflection based delegates (overriding 1.4 behaviour from superclass where
 * appropriate)
 *
 * @author Adrian Colyer
 * @author Andy Clement
 */
public class Java15ReflectionBasedReferenceTypeDelegate extends ReflectionBasedReferenceTypeDelegate {

	private AjType myType;
	private ResolvedType[] annotations;
	private ResolvedMember[] pointcuts;
	private ResolvedMember[] methods;
	private ResolvedMember[] fields;
	private TypeVariable[] typeVariables;
	private ResolvedType superclass;
	private ResolvedType[] superInterfaces;
	private String genericSignature = null;
	private JavaLangTypeToResolvedTypeConverter typeConverter;
	private Java15AnnotationFinder annotationFinder = null;
	private ArgNameFinder argNameFinder = null;

	public Java15ReflectionBasedReferenceTypeDelegate() {
	}

	@Override
	public void initialize(ReferenceType aType, Class aClass, ClassLoader classLoader, World aWorld) {
		super.initialize(aType, aClass, classLoader, aWorld);
		myType = AjTypeSystem.getAjType(aClass);
		annotationFinder = new Java15AnnotationFinder();
		argNameFinder = annotationFinder;
		annotationFinder.setClassLoader(this.classLoaderReference.getClassLoader());
		annotationFinder.setWorld(aWorld);
		this.typeConverter = new JavaLangTypeToResolvedTypeConverter(aWorld);
	}

	@Override
	public ReferenceType buildGenericType() {
		return (ReferenceType) UnresolvedType.forGenericTypeVariables(getResolvedTypeX().getSignature(), getTypeVariables())
				.resolve(getWorld());
	}

	@Override
	public AnnotationAJ[] getAnnotations() {
		// AMC - we seem not to need to implement this method...
		// throw new UnsupportedOperationException(
		// "getAnnotations on Java15ReflectionBasedReferenceTypeDelegate is not implemented yet"
		// );
		// FIXME is this the right implementation in the reflective case?
		return super.getAnnotations();
	}

	@Override
	public ResolvedType[] getAnnotationTypes() {
		if (annotations == null) {
			annotations = annotationFinder.getAnnotations(getBaseClass(), getWorld());
		}
		return annotations;
	}

	@Override
	public boolean hasAnnotations() {
		if (annotations == null) {
			annotations = annotationFinder.getAnnotations(getBaseClass(), getWorld());
		}
		return annotations.length != 0;
	}

	@Override
	public boolean hasAnnotation(UnresolvedType ofType) {
		ResolvedType[] myAnns = getAnnotationTypes();
		ResolvedType toLookFor = ofType.resolve(getWorld());
		for (ResolvedType myAnn : myAnns) {
			if (myAnn == toLookFor) {
				return true;
			}
		}
		return false;
	}

	// use the MAP to ensure that any aj-synthetic fields are filtered out
	@Override
	public ResolvedMember[] getDeclaredFields() {
		if (fields == null) {
			Field[] reflectFields = this.myType.getDeclaredFields();
			ResolvedMember[] rFields = new ResolvedMember[reflectFields.length];
			for (int i = 0; i < reflectFields.length; i++) {
				rFields[i] = createGenericFieldMember(reflectFields[i]);
			}
			this.fields = rFields;
		}
		return fields;
	}

	@Override
	public String getDeclaredGenericSignature() {
		if (this.genericSignature == null && isGeneric()) {
			// BUG? what the hell is this doing - see testcode in MemberTestCase15.testMemberSignatureCreation() and run it
			// off a Reflection World
		}
		return genericSignature;
	}

	@Override
	public ResolvedType[] getDeclaredInterfaces() {
		if (superInterfaces == null) {
			Type[] genericInterfaces = getBaseClass().getGenericInterfaces();
			this.superInterfaces = typeConverter.fromTypes(genericInterfaces);
		}
		return superInterfaces;
	}

	@Override
	public ResolvedType getSuperclass() {
		// Superclass of object is null
		if (superclass == null && getBaseClass() != Object.class) {
			Type t = this.getBaseClass().getGenericSuperclass();
			if (t != null) {
				superclass = typeConverter.fromType(t);
			}
			if (t == null) {
				// If the superclass is null, return Object - same as bcel does
				superclass = getWorld().resolve(UnresolvedType.OBJECT);
			}
		}
		return superclass;
	}

	@Override
	public TypeVariable[] getTypeVariables() {
		TypeVariable[] workInProgressSetOfVariables = getResolvedTypeX().getWorld().getTypeVariablesCurrentlyBeingProcessed(
				getBaseClass());
		if (workInProgressSetOfVariables != null) {
			return workInProgressSetOfVariables;
		}
		if (this.typeVariables == null) {
			java.lang.reflect.TypeVariable[] tVars = this.getBaseClass().getTypeParameters();
			TypeVariable[] rTypeVariables = new TypeVariable[tVars.length];
			// basic initialization
			for (int i = 0; i < tVars.length; i++) {
				rTypeVariables[i] = new TypeVariable(tVars[i].getName());
			}
			// stash it
			this.getResolvedTypeX().getWorld().recordTypeVariablesCurrentlyBeingProcessed(getBaseClass(), rTypeVariables);
			// now fill in the details...
			for (int i = 0; i < tVars.length; i++) {
				TypeVariableReferenceType tvrt = ((TypeVariableReferenceType) typeConverter.fromType(tVars[i]));
				TypeVariable tv = tvrt.getTypeVariable();
				rTypeVariables[i].setSuperclass(tv.getSuperclass());
				rTypeVariables[i].setAdditionalInterfaceBounds(tv.getSuperInterfaces());
				rTypeVariables[i].setDeclaringElement(tv.getDeclaringElement());
				rTypeVariables[i].setDeclaringElementKind(tv.getDeclaringElementKind());
				rTypeVariables[i].setRank(tv.getRank());
			}
			this.typeVariables = rTypeVariables;
			this.getResolvedTypeX().getWorld().forgetTypeVariablesCurrentlyBeingProcessed(getBaseClass());
		}
		return this.typeVariables;
	}

	// overrides super method since by using the MAP we can filter out advice
	// methods that really shouldn't be seen in this list
	@Override
	public ResolvedMember[] getDeclaredMethods() {
		if (methods == null) {
			Method[] reflectMethods = this.myType.getDeclaredMethods();
			Constructor[] reflectCons = this.myType.getDeclaredConstructors();
			ResolvedMember[] rMethods = new ResolvedMember[reflectMethods.length + reflectCons.length];
			for (int i = 0; i < reflectMethods.length; i++) {
				rMethods[i] = createGenericMethodMember(reflectMethods[i]);
			}
			for (int i = 0; i < reflectCons.length; i++) {
				rMethods[i + reflectMethods.length] = createGenericConstructorMember(reflectCons[i]);
			}
			this.methods = rMethods;
		}
		return methods;
	}

	/**
	 * Returns the generic type, regardless of the resolvedType we 'know about'
	 */
	public ResolvedType getGenericResolvedType() {
		ResolvedType rt = getResolvedTypeX();
		if (rt.isParameterizedType() || rt.isRawType()) {
			return rt.getGenericType();
		}
		return rt;
	}

	private ResolvedMember createGenericMethodMember(Method forMethod) {
		ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.METHOD,
				getGenericResolvedType(), forMethod.getModifiers(), typeConverter.fromType(forMethod.getReturnType()),
				forMethod.getName(), typeConverter.fromTypes(forMethod.getParameterTypes()), typeConverter.fromTypes(forMethod
						.getExceptionTypes()), forMethod);
		ret.setAnnotationFinder(this.annotationFinder);
		ret.setGenericSignatureInformationProvider(new Java15GenericSignatureInformationProvider(this.getWorld()));
		return ret;
	}

	private ResolvedMember createGenericConstructorMember(Constructor forConstructor) {
		ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.METHOD,
				getGenericResolvedType(), forConstructor.getModifiers(),
				// to return what BCEL returns the return type is void
				UnresolvedType.VOID,// getGenericResolvedType(),
				"", typeConverter.fromTypes(forConstructor.getParameterTypes()), typeConverter.fromTypes(forConstructor
						.getExceptionTypes()), forConstructor);
		ret.setAnnotationFinder(this.annotationFinder);
		ret.setGenericSignatureInformationProvider(new Java15GenericSignatureInformationProvider(this.getWorld()));
		return ret;
	}

	private ResolvedMember createGenericFieldMember(Field forField) {
		ReflectionBasedResolvedMemberImpl ret = new ReflectionBasedResolvedMemberImpl(org.aspectj.weaver.Member.FIELD,
				getGenericResolvedType(), forField.getModifiers(), typeConverter.fromType(forField.getType()), forField.getName(),
				UnresolvedType.NONE, forField);
		ret.setAnnotationFinder(this.annotationFinder);
		ret.setGenericSignatureInformationProvider(new Java15GenericSignatureInformationProvider(this.getWorld()));
		return ret;
	}

	@Override
	public ResolvedMember[] getDeclaredPointcuts() {
		if (pointcuts == null) {
			Pointcut[] pcs = this.myType.getDeclaredPointcuts();
			pointcuts = new ResolvedMember[pcs.length];
			InternalUseOnlyPointcutParser parser = null;
			World world = getWorld();
			if (world instanceof ReflectionWorld) {
				parser = new InternalUseOnlyPointcutParser(classLoaderReference.getClassLoader(), (ReflectionWorld) getWorld());
			} else {
				parser = new InternalUseOnlyPointcutParser(classLoaderReference.getClassLoader());
			}
			Set additionalPointcutHandlers = world.getRegisteredPointcutHandlers();
			for (PointcutDesignatorHandler handler : additionalPointcutHandlers) {
				parser.registerPointcutDesignatorHandler(handler);
			}

			// phase 1, create legitimate entries in pointcuts[] before we
			// attempt to resolve *any* of the pointcuts
			// resolution can sometimes cause us to recurse, and this two stage
			// process allows us to cope with that
			for (int i = 0; i < pcs.length; i++) {
				AjType[] ptypes = pcs[i].getParameterTypes();
				UnresolvedType[] weaverPTypes = new UnresolvedType[ptypes.length];
				for (int j = 0; j < weaverPTypes.length; j++) {
					weaverPTypes[j] = this.typeConverter.fromType(ptypes[j].getJavaClass());
				}
				pointcuts[i] = new DeferredResolvedPointcutDefinition(getResolvedTypeX(), pcs[i].getModifiers(), pcs[i].getName(),
						weaverPTypes);
			}
			// phase 2, now go back round and resolve in-place all of the
			// pointcuts
			PointcutParameter[][] parameters = new PointcutParameter[pcs.length][];
			for (int i = 0; i < pcs.length; i++) {
				AjType[] ptypes = pcs[i].getParameterTypes();
				String[] pnames = pcs[i].getParameterNames();
				if (pnames.length != ptypes.length) {
					pnames = tryToDiscoverParameterNames(pcs[i]);
					if (pnames == null || (pnames.length != ptypes.length)) {
						throw new IllegalStateException("Required parameter names not available when parsing pointcut "
								+ pcs[i].getName() + " in type " + getResolvedTypeX().getName());
					}
				}
				parameters[i] = new PointcutParameter[ptypes.length];
				for (int j = 0; j < parameters[i].length; j++) {
					parameters[i][j] = parser.createPointcutParameter(pnames[j], ptypes[j].getJavaClass());
				}
				String pcExpr = pcs[i].getPointcutExpression().toString();
				org.aspectj.weaver.patterns.Pointcut pc = parser.resolvePointcutExpression(pcExpr, getBaseClass(), parameters[i]);
				((ResolvedPointcutDefinition) pointcuts[i]).setParameterNames(pnames);
				((ResolvedPointcutDefinition) pointcuts[i]).setPointcut(pc);
			}
			// phase 3, now concretize them all
			for (int i = 0; i < pointcuts.length; i++) {
				ResolvedPointcutDefinition rpd = (ResolvedPointcutDefinition) pointcuts[i];
				rpd.setPointcut(parser.concretizePointcutExpression(rpd.getPointcut(), getBaseClass(), parameters[i]));
			}
		}
		return pointcuts;
	}

	// for @AspectJ pointcuts compiled by javac only...
	private String[] tryToDiscoverParameterNames(Pointcut pcut) {
		Method[] ms = pcut.getDeclaringType().getJavaClass().getDeclaredMethods();
		for (Method m : ms) {
			if (m.getName().equals(pcut.getName())) {
				return argNameFinder.getParameterNames(m);
			}
		}
		return null;
	}

	@Override
	public boolean isAnnotation() {
		return getBaseClass().isAnnotation();
	}

	@Override
	public boolean isAnnotationStyleAspect() {
		return getBaseClass().isAnnotationPresent(Aspect.class);
	}

	@Override
	public boolean isAnnotationWithRuntimeRetention() {
		if (!isAnnotation()) {
			return false;
		}
		if (getBaseClass().isAnnotationPresent(Retention.class)) {
			Retention retention = (Retention) getBaseClass().getAnnotation(Retention.class);
			RetentionPolicy policy = retention.value();
			return policy == RetentionPolicy.RUNTIME;
		} else {
			return false;
		}
	}

	@Override
	public boolean isAspect() {
		return this.myType.isAspect();
	}

	@Override
	public boolean isEnum() {
		return getBaseClass().isEnum();
	}

	@Override
	public boolean isGeneric() {
		// return false; // for now
		return getBaseClass().getTypeParameters().length > 0;
	}

	@Override
	public boolean isAnonymous() {
		return this.myClass.isAnonymousClass();
	}

	@Override
	public boolean isNested() {
		return this.myClass.isMemberClass();
	}

	@Override
	public ResolvedType getOuterClass() {
		 return ReflectionBasedReferenceTypeDelegateFactory.resolveTypeInWorld(
				 	myClass.getEnclosingClass(),world);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy