org.aspectj.weaver.reflect.Java15ReflectionBasedReferenceTypeDelegate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
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.
/* *******************************************************************
* 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);
}
}