|
|
|
@ -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); |
|
|
|
} |
|
|
|
} |
|
|
|
|