Avoid class loading during AspectJ expression evaluation

Fixed through downcasting to AspectJ's ReflectionType and ReflectionBasedReferenceTypeDelegate, obtaining the myClass field there. We only fall back to regular class loading if we encounter any other kind of type.

Issue: SPR-11344
This commit is contained in:
Juergen Hoeller 2014-01-22 18:23:09 +01:00
parent d9ab6aaf6c
commit c406c56d57
2 changed files with 122 additions and 101 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -42,6 +42,7 @@ import org.aspectj.weaver.tools.PointcutParameter;
import org.aspectj.weaver.tools.PointcutParser; import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive; import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.ShadowMatch; import org.aspectj.weaver.tools.ShadowMatch;
import org.springframework.aop.ClassFilter; import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher; import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher; import org.springframework.aop.MethodMatcher;
@ -55,6 +56,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -98,11 +100,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class); private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
private Class pointcutDeclarationScope; private Class<?> pointcutDeclarationScope;
private String[] pointcutParameterNames = new String[0]; private String[] pointcutParameterNames = new String[0];
private Class[] pointcutParameterTypes = new Class[0]; private Class<?>[] pointcutParameterTypes = new Class<?>[0];
private BeanFactory beanFactory; private BeanFactory beanFactory;
@ -123,7 +125,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
* @param paramNames the parameter names for the pointcut * @param paramNames the parameter names for the pointcut
* @param paramTypes the parameter types for the pointcut * @param paramTypes the parameter types for the pointcut
*/ */
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) { public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
this.pointcutDeclarationScope = declarationScope; this.pointcutDeclarationScope = declarationScope;
if (paramNames.length != paramTypes.length) { if (paramNames.length != paramTypes.length) {
throw new IllegalStateException( throw new IllegalStateException(
@ -137,21 +139,21 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
/** /**
* Set the declaration scope for the pointcut. * Set the declaration scope for the pointcut.
*/ */
public void setPointcutDeclarationScope(Class pointcutDeclarationScope) { public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
this.pointcutDeclarationScope = pointcutDeclarationScope; this.pointcutDeclarationScope = pointcutDeclarationScope;
} }
/** /**
* Set the parameter names for the pointcut. * Set the parameter names for the pointcut.
*/ */
public void setParameterNames(String[] names) { public void setParameterNames(String... names) {
this.pointcutParameterNames = names; this.pointcutParameterNames = names;
} }
/** /**
* Set the parameter types for the pointcut. * Set the parameter types for the pointcut.
*/ */
public void setParameterTypes(Class[] types) { public void setParameterTypes(Class<?>... types) {
this.pointcutParameterTypes = types; this.pointcutParameterTypes = types;
} }
@ -188,9 +190,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
* Build the underlying AspectJ pointcut expression. * Build the underlying AspectJ pointcut expression.
*/ */
private PointcutExpression buildPointcutExpression() { private PointcutExpression buildPointcutExpression() {
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory) ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
.getBeanClassLoader() : Thread.currentThread() ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
.getContextClassLoader()); ClassUtils.getDefaultClassLoader());
return buildPointcutExpression(cl); return buildPointcutExpression(cl);
} }
@ -202,8 +204,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length]; PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) { for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter( pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
this.pointcutParameterTypes[i]);
} }
return parser.parsePointcutExpression( return parser.parsePointcutExpression(
replaceBooleanOperators(getExpression()), replaceBooleanOperators(getExpression()),
@ -244,20 +245,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
return this.pointcutExpression; return this.pointcutExpression;
} }
public boolean matches(Class targetClass) { public boolean matches(Class<?> targetClass) {
checkReadyToMatch(); checkReadyToMatch();
try { try {
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass); return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
} catch (ReflectionWorldException e) { }
logger.debug("PointcutExpression matching rejected target class", e); catch (ReflectionWorldException rwe) {
logger.debug("PointcutExpression matching rejected target class", rwe);
try { try {
// Actually this is still a "maybe" - treat the pointcut as dynamic if we // Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
// don't know enough yet
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass); return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
} catch (BCException ex) { }
logger.debug( catch (BCException bce) {
"Fallback PointcutExpression matching rejected target class", logger.debug("Fallback PointcutExpression matching rejected target class", bce);
ex);
return false; return false;
} }
} }
@ -267,7 +267,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
} }
} }
public boolean matches(Method method, Class targetClass, boolean beanHasIntroductions) { public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
checkReadyToMatch(); checkReadyToMatch();
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass); Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method); ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
@ -283,11 +283,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
} }
else { else {
// the maybe case // the maybe case
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass)); if (beanHasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
} }
} }
public boolean matches(Method method, Class targetClass) { public boolean matches(Method method, Class<?> targetClass) {
return matches(method, targetClass, false); return matches(method, targetClass, false);
} }
@ -296,7 +304,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
return this.pointcutExpression.mayNeedDynamicTest(); return this.pointcutExpression.mayNeedDynamicTest();
} }
public boolean matches(Method method, Class targetClass, Object[] args) { public boolean matches(Method method, Class<?> targetClass, Object[] args) {
checkReadyToMatch(); checkReadyToMatch();
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method); ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
ShadowMatch originalShadowMatch = getShadowMatch(method, method); ShadowMatch originalShadowMatch = getShadowMatch(method, method);
@ -336,14 +344,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) { if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false; return false;
} }
} if (joinPointMatch.matches()) {
if (joinPointMatch.matches() && pmi != null) {
bindParameters(pmi, joinPointMatch); bindParameters(pmi, joinPointMatch);
} }
}
return joinPointMatch.matches(); return joinPointMatch.matches();
} }
protected String getCurrentProxiedBeanName() { protected String getCurrentProxiedBeanName() {
return ProxyCreationContext.getCurrentProxiedBeanName(); return ProxyCreationContext.getCurrentProxiedBeanName();
} }
@ -353,29 +360,14 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
* Get a new pointcut expression based on a target class's loader, rather * Get a new pointcut expression based on a target class's loader, rather
* than the default. * than the default.
*/ */
private PointcutExpression getFallbackPointcutExpression( private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
Class<?> targetClass) {
ClassLoader classLoader = targetClass.getClassLoader(); ClassLoader classLoader = targetClass.getClassLoader();
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader); return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
}
/**
* A match test returned maybe - if there are any subtype sensitive variables
* involved in the test (this, target, at_this, at_target, at_annotation) then
* we say this is not a match as in Spring there will never be a different
* runtime subtype.
*/
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
}
private boolean matchesTarget(ShadowMatch shadowMatch, Class targetClass) {
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
} }
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) { private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
if (shadowMatch instanceof DefensiveShadowMatch) { if (shadowMatch instanceof DefensiveShadowMatch) {
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary); return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
} }
return new RuntimeTestWalker(shadowMatch); return new RuntimeTestWalker(shadowMatch);
} }
@ -409,7 +401,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
try { try {
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass()); fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch); shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
} catch (ReflectionWorld.ReflectionWorldException e) { }
catch (ReflectionWorld.ReflectionWorldException ex2) {
if (targetMethod == originalMethod) { if (targetMethod == originalMethod) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null); shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
} }
@ -417,21 +410,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
try { try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod); shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
} }
catch (ReflectionWorld.ReflectionWorldException ex2) { catch (ReflectionWorld.ReflectionWorldException ex3) {
// Could neither introspect the target class nor the proxy class -> // Could neither introspect the target class nor the proxy class ->
// let's simply consider this method as non-matching. // let's simply consider this method as non-matching.
methodToMatch = originalMethod; methodToMatch = originalMethod;
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass()); fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
try { try {
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch); shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
} catch (ReflectionWorld.ReflectionWorldException e2) { }
catch (ReflectionWorld.ReflectionWorldException ex4) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null); shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
} }
} }
} }
} }
} }
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) { if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
shadowMatch = new DefensiveShadowMatch(shadowMatch, shadowMatch = new DefensiveShadowMatch(shadowMatch,
fallbackPointcutExpression.matchesMethodExecution(methodToMatch)); fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
} }
@ -601,9 +595,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32); this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
} }
private static class DefensiveShadowMatch implements ShadowMatch { private static class DefensiveShadowMatch implements ShadowMatch {
private final ShadowMatch primary; private final ShadowMatch primary;
private final ShadowMatch other; private final ShadowMatch other;
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) { public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
@ -612,31 +608,30 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
} }
public boolean alwaysMatches() { public boolean alwaysMatches() {
return primary.alwaysMatches(); return this.primary.alwaysMatches();
} }
public boolean maybeMatches() { public boolean maybeMatches() {
return primary.maybeMatches(); return this.primary.maybeMatches();
} }
public boolean neverMatches() { public boolean neverMatches() {
return primary.neverMatches(); return this.primary.neverMatches();
} }
public JoinPointMatch matchesJoinPoint(Object thisObject, public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
Object targetObject, Object[] args) {
try { try {
return primary.matchesJoinPoint(thisObject, targetObject, args); return this.primary.matchesJoinPoint(thisObject, targetObject, args);
} catch (ReflectionWorldException e) { }
return other.matchesJoinPoint(thisObject, targetObject, args); catch (ReflectionWorldException ex) {
return this.other.matchesJoinPoint(thisObject, targetObject, args);
} }
} }
public void setMatchingContext(MatchingContext aMatchContext) { public void setMatchingContext(MatchingContext aMatchContext) {
primary.setMatchingContext(aMatchContext); this.primary.setMatchingContext(aMatchContext);
other.setMatchingContext(aMatchContext); this.other.setMatchingContext(aMatchContext);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ReferenceTypeDelegate;
import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ast.And; import org.aspectj.weaver.ast.And;
import org.aspectj.weaver.ast.Call; import org.aspectj.weaver.ast.Call;
@ -30,6 +32,7 @@ import org.aspectj.weaver.ast.Not;
import org.aspectj.weaver.ast.Or; import org.aspectj.weaver.ast.Or;
import org.aspectj.weaver.ast.Test; import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest; import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
import org.aspectj.weaver.reflect.ReflectionVar; import org.aspectj.weaver.reflect.ReflectionVar;
import org.aspectj.weaver.reflect.ShadowMatchImpl; import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ShadowMatch; import org.aspectj.weaver.tools.ShadowMatch;
@ -55,25 +58,36 @@ import org.springframework.util.ReflectionUtils;
*/ */
class RuntimeTestWalker { class RuntimeTestWalker {
private static final Field residualTestField;
private static final Field varTypeField;
private static final Field myClassField;
static {
try {
residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
varTypeField = ReflectionVar.class.getDeclaredField("varType");
myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
}
catch (NoSuchFieldException ex) {
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
"on the classpath is incompatible with this version of Spring: " + ex);
}
}
private final Test runtimeTest; private final Test runtimeTest;
public RuntimeTestWalker(ShadowMatch shadowMatch) { public RuntimeTestWalker(ShadowMatch shadowMatch) {
ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch;
try { try {
Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest"); ReflectionUtils.makeAccessible(residualTestField);
ReflectionUtils.makeAccessible(testField); this.runtimeTest = (Test) residualTestField.get(shadowMatch);
this.runtimeTest = (Test) testField.get(shadowMatch);
} }
catch (NoSuchFieldException noSuchFieldEx) { catch (IllegalAccessException ex) {
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " + throw new IllegalStateException(ex);
"on the classpath is incompatible with this version of Spring: Expected field " +
"'runtimeTest' is not present on ShadowMatchImpl class.");
}
catch (IllegalAccessException illegalAccessEx) {
// Famous last words... but I don't see how this can happen given the
// makeAccessible call above
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
} }
} }
@ -87,12 +101,12 @@ class RuntimeTestWalker {
new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest)); new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
} }
public boolean testThisInstanceOfResidue(Class thisClass) { public boolean testThisInstanceOfResidue(Class<?> thisClass) {
return (this.runtimeTest != null && return (this.runtimeTest != null &&
new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest)); new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
} }
public boolean testTargetInstanceOfResidue(Class targetClass) { public boolean testTargetInstanceOfResidue(Class<?> targetClass) {
return (this.runtimeTest != null && return (this.runtimeTest != null &&
new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest)); new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
} }
@ -140,19 +154,11 @@ class RuntimeTestWalker {
protected int getVarType(ReflectionVar v) { protected int getVarType(ReflectionVar v) {
try { try {
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
ReflectionUtils.makeAccessible(varTypeField); ReflectionUtils.makeAccessible(varTypeField);
return (Integer) varTypeField.get(v); return (Integer) varTypeField.get(v);
} }
catch (NoSuchFieldException noSuchFieldEx) { catch (IllegalAccessException ex) {
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " + throw new IllegalStateException(ex);
"on the classpath is incompatible with this version of Spring:- expected field " +
"'varType' is not present on ReflectionVar class");
}
catch (IllegalAccessException illegalAccessEx) {
// Famous last words... but I don't see how this can happen given the
// makeAccessible call above
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
} }
} }
} }
@ -160,11 +166,13 @@ class RuntimeTestWalker {
private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter { private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
private Class matchClass; private final Class<?> matchClass;
private boolean matches;
private int matchVarType;
public InstanceOfResidueTestVisitor(Class matchClass, boolean defaultMatches, int matchVarType) { private boolean matches;
private final int matchVarType;
public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
this.matchClass = matchClass; this.matchClass = matchClass;
this.matches = defaultMatches; this.matches = defaultMatches;
this.matchVarType = matchVarType; this.matchVarType = matchVarType;
@ -172,19 +180,34 @@ class RuntimeTestWalker {
public boolean instanceOfMatches(Test test) { public boolean instanceOfMatches(Test test) {
test.accept(this); test.accept(this);
return matches; return this.matches;
} }
@Override @Override
public void visit(Instanceof i) { public void visit(Instanceof i) {
ResolvedType type = (ResolvedType) i.getType();
int varType = getVarType((ReflectionVar) i.getVar()); int varType = getVarType((ReflectionVar) i.getVar());
if (varType != this.matchVarType) { if (varType != this.matchVarType) {
return; return;
} }
Class<?> typeClass = null;
ResolvedType type = (ResolvedType) i.getType();
if (type instanceof ReferenceType) {
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
if (delegate instanceof ReflectionBasedReferenceTypeDelegate) {
try { try {
Class typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader()); ReflectionUtils.makeAccessible(myClassField);
// Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins typeClass = (Class<?>) myClassField.get(delegate);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
}
try {
// Don't use ResolvedType.isAssignableFrom() as it won't be aware of (Spring) mixins
if (typeClass == null) {
typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
}
this.matches = typeClass.isAssignableFrom(this.matchClass); this.matches = typeClass.isAssignableFrom(this.matchClass);
} }
catch (ClassNotFoundException ex) { catch (ClassNotFoundException ex) {
@ -199,7 +222,7 @@ class RuntimeTestWalker {
*/ */
private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor { private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
public TargetInstanceOfResidueTestVisitor(Class targetClass) { public TargetInstanceOfResidueTestVisitor(Class<?> targetClass) {
super(targetClass, false, TARGET_VAR); super(targetClass, false, TARGET_VAR);
} }
@ -214,7 +237,7 @@ class RuntimeTestWalker {
*/ */
private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor { private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
public ThisInstanceOfResidueTestVisitor(Class thisClass) { public ThisInstanceOfResidueTestVisitor(Class<?> thisClass) {
super(thisClass, true, THIS_VAR); super(thisClass, true, THIS_VAR);
} }
@ -228,8 +251,11 @@ class RuntimeTestWalker {
private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter { private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
private final Object thisObj = new Object(); private final Object thisObj = new Object();
private final Object targetObj = new Object(); private final Object targetObj = new Object();
private final Object[] argsObjs = new Object[0]; private final Object[] argsObjs = new Object[0];
private boolean testsSubtypeSensitiveVars = false; private boolean testsSubtypeSensitiveVars = false;
public boolean testsSubtypeSensitiveVars(Test aTest) { public boolean testsSubtypeSensitiveVars(Test aTest) {
@ -240,8 +266,8 @@ class RuntimeTestWalker {
@Override @Override
public void visit(Instanceof i) { public void visit(Instanceof i) {
ReflectionVar v = (ReflectionVar) i.getVar(); ReflectionVar v = (ReflectionVar) i.getVar();
Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs); Object varUnderTest = v.getBindingAtJoinPoint(this.thisObj, this.targetObj, this.argsObjs);
if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) { if (varUnderTest == this.thisObj || varUnderTest == this.targetObj) {
this.testsSubtypeSensitiveVars = true; this.testsSubtypeSensitiveVars = true;
} }
} }
@ -251,7 +277,7 @@ class RuntimeTestWalker {
// If you thought things were bad before, now we sink to new levels of horror... // If you thought things were bad before, now we sink to new levels of horror...
ReflectionVar v = (ReflectionVar) hasAnn.getVar(); ReflectionVar v = (ReflectionVar) hasAnn.getVar();
int varType = getVarType(v); int varType = getVarType(v);
if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) { if (varType == AT_THIS_VAR || varType == AT_TARGET_VAR || varType == AT_ANNOTATION_VAR) {
this.testsSubtypeSensitiveVars = true; this.testsSubtypeSensitiveVars = true;
} }
} }