AspectJExpressionPointcut defensively handles fallback expression parsing
Issue: SPR-9335
This commit is contained in:
@@ -29,7 +29,6 @@ import org.apache.commons.logging.Log;
|
|||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.aspectj.weaver.BCException;
|
import org.aspectj.weaver.BCException;
|
||||||
import org.aspectj.weaver.patterns.NamePattern;
|
import org.aspectj.weaver.patterns.NamePattern;
|
||||||
import org.aspectj.weaver.reflect.ReflectionWorld;
|
|
||||||
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
|
||||||
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
import org.aspectj.weaver.reflect.ShadowMatchImpl;
|
||||||
import org.aspectj.weaver.tools.ContextBasedMatcher;
|
import org.aspectj.weaver.tools.ContextBasedMatcher;
|
||||||
@@ -108,6 +107,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||||||
|
|
||||||
private BeanFactory beanFactory;
|
private BeanFactory beanFactory;
|
||||||
|
|
||||||
|
private transient ClassLoader pointcutClassLoader;
|
||||||
|
|
||||||
private transient PointcutExpression pointcutExpression;
|
private transient PointcutExpression pointcutExpression;
|
||||||
|
|
||||||
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
|
||||||
@@ -185,20 +186,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||||||
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
throw new IllegalStateException("Must set property 'expression' before attempting to match");
|
||||||
}
|
}
|
||||||
if (this.pointcutExpression == null) {
|
if (this.pointcutExpression == null) {
|
||||||
this.pointcutExpression = buildPointcutExpression();
|
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
||||||
|
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
||||||
|
ClassUtils.getDefaultClassLoader());
|
||||||
|
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the underlying AspectJ pointcut expression.
|
|
||||||
*/
|
|
||||||
private PointcutExpression buildPointcutExpression() {
|
|
||||||
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
|
|
||||||
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
|
|
||||||
ClassUtils.getDefaultClassLoader());
|
|
||||||
return buildPointcutExpression(cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the underlying AspectJ pointcut expression.
|
* Build the underlying AspectJ pointcut expression.
|
||||||
*/
|
*/
|
||||||
@@ -252,23 +246,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||||||
public boolean matches(Class<?> targetClass) {
|
public boolean matches(Class<?> targetClass) {
|
||||||
checkReadyToMatch();
|
checkReadyToMatch();
|
||||||
try {
|
try {
|
||||||
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
|
||||||
}
|
|
||||||
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 don't know enough yet
|
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
|
||||||
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
|
|
||||||
}
|
}
|
||||||
catch (BCException bce) {
|
catch (ReflectionWorldException ex) {
|
||||||
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
|
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
|
||||||
return false;
|
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
|
||||||
|
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
|
||||||
|
if (fallbackExpression != null) {
|
||||||
|
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (BCException ex) {
|
catch (BCException ex) {
|
||||||
logger.debug("PointcutExpression matching rejected target class", ex);
|
logger.debug("PointcutExpression matching rejected target class", ex);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -365,12 +358,19 @@ 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(Class<?> targetClass) {
|
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
|
||||||
ClassLoader classLoader = targetClass.getClassLoader();
|
try {
|
||||||
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
|
ClassLoader classLoader = targetClass.getClassLoader();
|
||||||
|
if (classLoader != null && classLoader != this.pointcutClassLoader) {
|
||||||
|
return buildPointcutExpression(classLoader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
logger.debug("Failed to create fallback PointcutExpression", ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
|
||||||
@@ -396,46 +396,51 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||||||
if (shadowMatch == null) {
|
if (shadowMatch == null) {
|
||||||
synchronized (this.shadowMatchCache) {
|
synchronized (this.shadowMatchCache) {
|
||||||
// Not found - now check again with full lock...
|
// Not found - now check again with full lock...
|
||||||
|
PointcutExpression fallbackExpression = null;
|
||||||
Method methodToMatch = targetMethod;
|
Method methodToMatch = targetMethod;
|
||||||
PointcutExpression fallbackPointcutExpression = null;
|
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||||
shadowMatch = this.shadowMatchCache.get(methodToMatch);
|
|
||||||
if (shadowMatch == null) {
|
if (shadowMatch == null) {
|
||||||
try {
|
try {
|
||||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
|
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||||
}
|
}
|
||||||
catch (ReflectionWorld.ReflectionWorldException ex) {
|
catch (ReflectionWorldException ex) {
|
||||||
// Failed to introspect target method, probably because it has been loaded
|
// Failed to introspect target method, probably because it has been loaded
|
||||||
// in a special ClassLoader. Let's try the original method instead...
|
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
|
||||||
try {
|
try {
|
||||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
if (fallbackExpression != null) {
|
||||||
}
|
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||||
catch (ReflectionWorld.ReflectionWorldException ex2) {
|
|
||||||
if (targetMethod == originalMethod) {
|
|
||||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
try {
|
catch (ReflectionWorldException ex2) {
|
||||||
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
|
fallbackExpression = null;
|
||||||
}
|
}
|
||||||
catch (ReflectionWorld.ReflectionWorldException ex3) {
|
}
|
||||||
// Could neither introspect the target class nor the proxy class ->
|
if (shadowMatch == null && targetMethod != originalMethod) {
|
||||||
// let's simply consider this method as non-matching.
|
methodToMatch = originalMethod;
|
||||||
methodToMatch = originalMethod;
|
try {
|
||||||
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
|
||||||
try {
|
}
|
||||||
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
|
catch (ReflectionWorldException ex3) {
|
||||||
}
|
// Could neither introspect the target class nor the proxy class ->
|
||||||
catch (ReflectionWorld.ReflectionWorldException ex4) {
|
// let's try the original method's declaring class before we give up...
|
||||||
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
try {
|
||||||
}
|
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
|
||||||
|
if (fallbackExpression != null) {
|
||||||
|
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (ReflectionWorldException ex4) {
|
||||||
|
fallbackExpression = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
|
if (shadowMatch == null) {
|
||||||
|
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
|
||||||
|
}
|
||||||
|
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
|
||||||
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
shadowMatch = new DefensiveShadowMatch(shadowMatch,
|
||||||
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
|
fallbackExpression.matchesMethodExecution(methodToMatch));
|
||||||
}
|
}
|
||||||
this.shadowMatchCache.put(targetMethod, shadowMatch);
|
this.shadowMatchCache.put(targetMethod, shadowMatch);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user