Tighten (IntroductionAware)MethodMatcher contract
Provides a non-null guarantee for MethodMatcher's targetClass argument and strict separation between IntroductionAwareMethodMatcher and regular MethodMatcher, enabling DefaultAdvisorChainFactory to defer its IntroductionAdvisor determination until encountering an actual IntroductionAwareMethodMatcher (even behind union/intersection). Issue: SPR-17068
This commit is contained in:
		
							parent
							
								
									867b3d233d
								
							
						
					
					
						commit
						252f52ab07
					
				| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2013 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -18,8 +18,6 @@ package org.springframework.aop;
 | 
			
		|||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A specialized type of {@link MethodMatcher} that takes into account introductions
 | 
			
		||||
 * when matching methods. If there are no introductions on the target class,
 | 
			
		||||
| 
						 | 
				
			
			@ -35,12 +33,11 @@ public interface IntroductionAwareMethodMatcher extends MethodMatcher {
 | 
			
		|||
	 * instead of the 2-arg {@link #matches(java.lang.reflect.Method, Class)} method
 | 
			
		||||
	 * if the caller supports the extended IntroductionAwareMethodMatcher interface.
 | 
			
		||||
	 * @param method the candidate method
 | 
			
		||||
	 * @param targetClass the target class (may be {@code null}, in which case
 | 
			
		||||
	 * the candidate class must be taken to be the method's declaring class)
 | 
			
		||||
	 * @param targetClass the target class
 | 
			
		||||
	 * @param hasIntroductions {@code true} if the object on whose behalf we are
 | 
			
		||||
	 * asking is the subject on one or more introductions; {@code false} otherwise
 | 
			
		||||
	 * @return whether or not this method matches statically
 | 
			
		||||
	 */
 | 
			
		||||
	boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions);
 | 
			
		||||
	boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2015 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -18,8 +18,6 @@ package org.springframework.aop;
 | 
			
		|||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Part of a {@link Pointcut}: Checks whether the target method is eligible for advice.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -50,16 +48,16 @@ import org.springframework.lang.Nullable;
 | 
			
		|||
public interface MethodMatcher {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Perform static checking whether the given method matches. If this
 | 
			
		||||
	 * returns {@code false} or if the {@link #isRuntime()} method
 | 
			
		||||
	 * returns {@code false}, no runtime check (i.e. no.
 | 
			
		||||
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made.
 | 
			
		||||
	 * Perform static checking whether the given method matches.
 | 
			
		||||
	 * <p>If this returns {@code false} or if the {@link #isRuntime()}
 | 
			
		||||
	 * method returns {@code false}, no runtime check (i.e. no
 | 
			
		||||
	 * {@link #matches(java.lang.reflect.Method, Class, Object[])} call)
 | 
			
		||||
	 * will be made.
 | 
			
		||||
	 * @param method the candidate method
 | 
			
		||||
	 * @param targetClass the target class (may be {@code null}, in which case
 | 
			
		||||
	 * the candidate class must be taken to be the method's declaring class)
 | 
			
		||||
	 * @param targetClass the target class
 | 
			
		||||
	 * @return whether or not this method matches statically
 | 
			
		||||
	 */
 | 
			
		||||
	boolean matches(Method method, @Nullable Class<?> targetClass);
 | 
			
		||||
	boolean matches(Method method, Class<?> targetClass);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Is this MethodMatcher dynamic, that is, must a final call be made on the
 | 
			
		||||
| 
						 | 
				
			
			@ -82,13 +80,12 @@ public interface MethodMatcher {
 | 
			
		|||
	 * immediately before potential running of the advice, after any
 | 
			
		||||
	 * advice earlier in the advice chain has run.
 | 
			
		||||
	 * @param method the candidate method
 | 
			
		||||
	 * @param targetClass the target class (may be {@code null}, in which case
 | 
			
		||||
	 * the candidate class must be taken to be the method's declaring class)
 | 
			
		||||
	 * @param targetClass the target class
 | 
			
		||||
	 * @param args arguments to the method
 | 
			
		||||
	 * @return whether there's a runtime match
 | 
			
		||||
	 * @see MethodMatcher#matches(Method, Class)
 | 
			
		||||
	 */
 | 
			
		||||
	boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
 | 
			
		||||
	boolean matches(Method method, Class<?> targetClass, Object... args);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,8 +19,6 @@ package org.springframework.aop;
 | 
			
		|||
import java.io.Serializable;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Canonical MethodMatcher instance that matches all methods.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -45,12 +43,12 @@ final class TrueMethodMatcher implements MethodMatcher, Serializable {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
		// Should never be invoked as isRuntime returns false.
 | 
			
		||||
		throw new UnsupportedOperationException();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -715,7 +715,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
			return !this.adviceMethod.equals(method);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -290,7 +290,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
		obtainPointcutExpression();
 | 
			
		||||
		ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -313,13 +313,12 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
 | 
			
		|||
			// 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() ||
 | 
			
		||||
					(targetClass != null && walker.testTargetInstanceOfResidue(targetClass)));
 | 
			
		||||
			return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		return matches(method, targetClass, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +328,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
		obtainPointcutExpression();
 | 
			
		||||
		ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -426,9 +425,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
 | 
			
		|||
		invocation.setUserAttribute(resolveExpression(), jpm);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private ShadowMatch getTargetShadowMatch(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	private ShadowMatch getTargetShadowMatch(Method method, Class<?> targetClass) {
 | 
			
		||||
		Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
 | 
			
		||||
		if (targetClass != null && targetMethod.getDeclaringClass().isInterface()) {
 | 
			
		||||
		if (targetMethod.getDeclaringClass().isInterface()) {
 | 
			
		||||
			// Try to build the most specific interface possible for inherited methods to be
 | 
			
		||||
			// considered for sub-interface matches as well, in particular for proxy classes.
 | 
			
		||||
			// Note: AspectJ is only going to take Method.getDeclaringClass() into account.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -284,14 +284,14 @@ final class InstantiationModelAwarePointcutAdvisorImpl
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
			// We're either instantiated and matching on declared pointcut, or uninstantiated matching on either pointcut
 | 
			
		||||
			return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass)) ||
 | 
			
		||||
					this.preInstantiationPointcut.getMethodMatcher().matches(method, targetClass);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
			// This can match only on declared pointcut.
 | 
			
		||||
			return (isAspectMaterialized() && this.declaredPointcut.matches(method, targetClass));
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,11 +152,12 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
 | 
			
		|||
	 * @see #setTargetSource
 | 
			
		||||
	 * @see #setTarget
 | 
			
		||||
	 */
 | 
			
		||||
	public void setTargetClass(Class<?> targetClass) {
 | 
			
		||||
	public void setTargetClass(@Nullable Class<?> targetClass) {
 | 
			
		||||
		this.targetSource = EmptyTargetSource.forClass(targetClass);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public Class<?> getTargetClass() {
 | 
			
		||||
		return this.targetSource.getTargetClass();
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,10 +70,10 @@ public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializ
 | 
			
		|||
						if (hasIntroductions == null) {
 | 
			
		||||
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
 | 
			
		||||
						}
 | 
			
		||||
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions);
 | 
			
		||||
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						match = mm.matches(method, targetClass);
 | 
			
		||||
						match = mm.matches(method, actualClass);
 | 
			
		||||
					}
 | 
			
		||||
					if (match) {
 | 
			
		||||
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2017 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +170,8 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
 | 
			
		|||
			// been evaluated and found to match.
 | 
			
		||||
			InterceptorAndDynamicMethodMatcher dm =
 | 
			
		||||
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
 | 
			
		||||
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
 | 
			
		||||
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
 | 
			
		||||
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
 | 
			
		||||
				return dm.interceptor.invoke(this);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2016 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,6 @@ import java.io.Serializable;
 | 
			
		|||
import java.lang.reflect.Method;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
import org.springframework.util.ObjectUtils;
 | 
			
		||||
| 
						 | 
				
			
			@ -130,9 +129,10 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
 | 
			
		|||
	 * plus the name of the method.
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) ||
 | 
			
		||||
				matchesPattern(ClassUtils.getQualifiedMethodName(method)));
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		return (matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass)) ||
 | 
			
		||||
				(targetClass != method.getDeclaringClass() &&
 | 
			
		||||
						matchesPattern(ClassUtils.getQualifiedMethodName(method, method.getDeclaringClass()))));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
 | 
			
		|||
	 * some candidate classes.
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +91,7 @@ public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
		this.evaluations++;
 | 
			
		||||
 | 
			
		||||
		for (StackTraceElement element : new Throwable().getStackTrace()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,6 @@ package org.springframework.aop.support;
 | 
			
		|||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
import org.springframework.aop.MethodMatcher;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convenient abstract superclass for dynamic method matchers,
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +38,7 @@ public abstract class DynamicMethodMatcher implements MethodMatcher {
 | 
			
		|||
	 * always returns true.
 | 
			
		||||
	 */
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ import java.lang.reflect.Method;
 | 
			
		|||
import org.springframework.aop.ClassFilter;
 | 
			
		||||
import org.springframework.aop.IntroductionAwareMethodMatcher;
 | 
			
		||||
import org.springframework.aop.MethodMatcher;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +48,8 @@ public abstract class MethodMatchers {
 | 
			
		|||
	 * of the given MethodMatchers matches
 | 
			
		||||
	 */
 | 
			
		||||
	public static MethodMatcher union(MethodMatcher mm1, MethodMatcher mm2) {
 | 
			
		||||
		return new UnionMethodMatcher(mm1, mm2);
 | 
			
		||||
		return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
 | 
			
		||||
				new UnionIntroductionAwareMethodMatcher(mm1, mm2) : new UnionMethodMatcher(mm1, mm2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,9 @@ public abstract class MethodMatchers {
 | 
			
		|||
	 * of the given MethodMatchers matches
 | 
			
		||||
	 */
 | 
			
		||||
	static MethodMatcher union(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) {
 | 
			
		||||
		return new ClassFilterAwareUnionMethodMatcher(mm1, cf1, mm2, cf2);
 | 
			
		||||
		return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
 | 
			
		||||
				new ClassFilterAwareUnionIntroductionAwareMethodMatcher(mm1, cf1, mm2, cf2) :
 | 
			
		||||
				new ClassFilterAwareUnionMethodMatcher(mm1, cf1, mm2, cf2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +75,8 @@ public abstract class MethodMatchers {
 | 
			
		|||
	 * of the given MethodMatchers match
 | 
			
		||||
	 */
 | 
			
		||||
	public static MethodMatcher intersection(MethodMatcher mm1, MethodMatcher mm2) {
 | 
			
		||||
		return new IntersectionMethodMatcher(mm1, mm2);
 | 
			
		||||
		return (mm1 instanceof IntroductionAwareMethodMatcher || mm2 instanceof IntroductionAwareMethodMatcher ?
 | 
			
		||||
				new IntersectionIntroductionAwareMethodMatcher(mm1, mm2) : new IntersectionMethodMatcher(mm1, mm2));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -82,13 +85,12 @@ public abstract class MethodMatchers {
 | 
			
		|||
	 * (if applicable).
 | 
			
		||||
	 * @param mm the MethodMatcher to apply (may be an IntroductionAwareMethodMatcher)
 | 
			
		||||
	 * @param method the candidate method
 | 
			
		||||
	 * @param targetClass the target class (may be {@code null}, in which case
 | 
			
		||||
	 * the candidate class must be taken to be the method's declaring class)
 | 
			
		||||
	 * @param targetClass the target class
 | 
			
		||||
	 * @param hasIntroductions {@code true} if the object on whose behalf we are
 | 
			
		||||
	 * asking is the subject on one or more introductions; {@code false} otherwise
 | 
			
		||||
	 * @return whether or not this method matches statically
 | 
			
		||||
	 */
 | 
			
		||||
	public static boolean matches(MethodMatcher mm, Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
	public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
		Assert.notNull(mm, "MethodMatcher must not be null");
 | 
			
		||||
		return (mm instanceof IntroductionAwareMethodMatcher ?
 | 
			
		||||
				((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
 | 
			
		||||
| 
						 | 
				
			
			@ -100,11 +102,11 @@ public abstract class MethodMatchers {
 | 
			
		|||
	 * MethodMatcher implementation for a union of two given MethodMatchers.
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("serial")
 | 
			
		||||
	private static class UnionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
 | 
			
		||||
	private static class UnionMethodMatcher implements MethodMatcher, Serializable {
 | 
			
		||||
 | 
			
		||||
		private final MethodMatcher mm1;
 | 
			
		||||
		protected final MethodMatcher mm1;
 | 
			
		||||
 | 
			
		||||
		private final MethodMatcher mm2;
 | 
			
		||||
		protected final MethodMatcher mm2;
 | 
			
		||||
 | 
			
		||||
		public UnionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
 | 
			
		||||
			Assert.notNull(mm1, "First MethodMatcher must not be null");
 | 
			
		||||
| 
						 | 
				
			
			@ -114,22 +116,16 @@ public abstract class MethodMatchers {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
			return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) ||
 | 
			
		||||
					(matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
			return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) ||
 | 
			
		||||
					(matchesClass2(targetClass) && this.mm2.matches(method, targetClass));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected boolean matchesClass1(@Nullable Class<?> targetClass) {
 | 
			
		||||
		protected boolean matchesClass1(Class<?> targetClass) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		protected boolean matchesClass2(@Nullable Class<?> targetClass) {
 | 
			
		||||
		protected boolean matchesClass2(Class<?> targetClass) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +135,7 @@ public abstract class MethodMatchers {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
			return this.mm1.matches(method, targetClass, args) || this.mm2.matches(method, targetClass, args);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +158,27 @@ public abstract class MethodMatchers {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * MethodMatcher implementation for a union of two given MethodMatchers
 | 
			
		||||
	 * of which at least one is an IntroductionAwareMethodMatcher.
 | 
			
		||||
	 * @since 5.1
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("serial")
 | 
			
		||||
	private static class UnionIntroductionAwareMethodMatcher extends UnionMethodMatcher
 | 
			
		||||
			implements IntroductionAwareMethodMatcher {
 | 
			
		||||
 | 
			
		||||
		public UnionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
 | 
			
		||||
			super(mm1, mm2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
			return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) ||
 | 
			
		||||
					(matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * MethodMatcher implementation for a union of two given MethodMatchers,
 | 
			
		||||
	 * supporting an associated ClassFilter per MethodMatcher.
 | 
			
		||||
| 
						 | 
				
			
			@ -180,13 +197,13 @@ public abstract class MethodMatchers {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		protected boolean matchesClass1(@Nullable Class<?> targetClass) {
 | 
			
		||||
			return (targetClass != null && this.cf1.matches(targetClass));
 | 
			
		||||
		protected boolean matchesClass1(Class<?> targetClass) {
 | 
			
		||||
			return this.cf1.matches(targetClass);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		protected boolean matchesClass2(@Nullable Class<?> targetClass) {
 | 
			
		||||
			return (targetClass != null && this.cf2.matches(targetClass));
 | 
			
		||||
		protected boolean matchesClass2(Class<?> targetClass) {
 | 
			
		||||
			return this.cf2.matches(targetClass);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -215,15 +232,39 @@ public abstract class MethodMatchers {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * MethodMatcher implementation for a union of two given MethodMatchers
 | 
			
		||||
	 * of which at least one is an IntroductionAwareMethodMatcher,
 | 
			
		||||
	 * supporting an associated ClassFilter per MethodMatcher.
 | 
			
		||||
	 * @since 5.1
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("serial")
 | 
			
		||||
	private static class ClassFilterAwareUnionIntroductionAwareMethodMatcher extends ClassFilterAwareUnionMethodMatcher
 | 
			
		||||
			implements IntroductionAwareMethodMatcher {
 | 
			
		||||
 | 
			
		||||
		public ClassFilterAwareUnionIntroductionAwareMethodMatcher(
 | 
			
		||||
				MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) {
 | 
			
		||||
 | 
			
		||||
			super(mm1, cf1, mm2, cf2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
			return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) ||
 | 
			
		||||
					(matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * MethodMatcher implementation for an intersection of two given MethodMatchers.
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("serial")
 | 
			
		||||
	private static class IntersectionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
 | 
			
		||||
	private static class IntersectionMethodMatcher implements MethodMatcher, Serializable {
 | 
			
		||||
 | 
			
		||||
		private final MethodMatcher mm1;
 | 
			
		||||
		protected final MethodMatcher mm1;
 | 
			
		||||
 | 
			
		||||
		private final MethodMatcher mm2;
 | 
			
		||||
		protected final MethodMatcher mm2;
 | 
			
		||||
 | 
			
		||||
		public IntersectionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
 | 
			
		||||
			Assert.notNull(mm1, "First MethodMatcher must not be null");
 | 
			
		||||
| 
						 | 
				
			
			@ -233,13 +274,7 @@ public abstract class MethodMatchers {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
			return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
 | 
			
		||||
					MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
			return (this.mm1.matches(method, targetClass) && this.mm2.matches(method, targetClass));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +284,7 @@ public abstract class MethodMatchers {
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
			// Because a dynamic intersection may be composed of a static and dynamic part,
 | 
			
		||||
			// we must avoid calling the 3-arg matches method on a dynamic matcher, as
 | 
			
		||||
			// it will probably be an unsupported operation.
 | 
			
		||||
| 
						 | 
				
			
			@ -278,4 +313,25 @@ public abstract class MethodMatchers {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * MethodMatcher implementation for an intersection of two given MethodMatchers
 | 
			
		||||
	 * of which at least one is an IntroductionAwareMethodMatcher.
 | 
			
		||||
	 * @since 5.1
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("serial")
 | 
			
		||||
	private static class IntersectionIntroductionAwareMethodMatcher extends IntersectionMethodMatcher
 | 
			
		||||
			implements IntroductionAwareMethodMatcher {
 | 
			
		||||
 | 
			
		||||
		public IntersectionIntroductionAwareMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
 | 
			
		||||
			super(mm1, mm2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
 | 
			
		||||
			return (MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
 | 
			
		||||
					MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ import java.util.ArrayList;
 | 
			
		|||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.PatternMatchUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +74,7 @@ public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut impleme
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		for (String mappedName : this.mappedNames) {
 | 
			
		||||
			if (mappedName.equals(method.getName()) || isMatch(method.getName(), mappedName)) {
 | 
			
		||||
				return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,6 @@ import java.lang.reflect.Method;
 | 
			
		|||
 | 
			
		||||
import org.springframework.aop.MethodMatcher;
 | 
			
		||||
import org.springframework.aop.Pointcut;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +97,7 @@ public abstract class Pointcuts {
 | 
			
		|||
		public static final SetterPointcut INSTANCE = new SetterPointcut();
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
			return (method.getName().startsWith("set") &&
 | 
			
		||||
					method.getParameterCount() == 1 &&
 | 
			
		||||
					method.getReturnType() == Void.TYPE);
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +118,7 @@ public abstract class Pointcuts {
 | 
			
		|||
		public static final GetterPointcut INSTANCE = new GetterPointcut();
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
		public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
			return (method.getName().startsWith("get") &&
 | 
			
		||||
					method.getParameterCount() == 0);
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,6 @@ package org.springframework.aop.support;
 | 
			
		|||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
import org.springframework.aop.MethodMatcher;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convenient abstract superclass for static method matchers, which don't care
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +34,7 @@ public abstract class StaticMethodMatcher implements MethodMatcher {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public final boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
 | 
			
		||||
	public final boolean matches(Method method, Class<?> targetClass, Object... args) {
 | 
			
		||||
		// should never be invoked because isRuntime() returns false
 | 
			
		||||
		throw new UnsupportedOperationException("Illegal MethodMatcher usage");
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,6 @@ import java.lang.reflect.Proxy;
 | 
			
		|||
import org.springframework.aop.support.AopUtils;
 | 
			
		||||
import org.springframework.aop.support.StaticMethodMatcher;
 | 
			
		||||
import org.springframework.core.annotation.AnnotationUtils;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -68,12 +67,12 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		if (matchesMethod(method)) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		// Proxy classes never have annotations on their redeclared methods.
 | 
			
		||||
		if (targetClass != null && Proxy.isProxyClass(targetClass)) {
 | 
			
		||||
		if (Proxy.isProxyClass(targetClass)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		// The method may be on an interface, so let's check on the target class as well.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ import org.springframework.util.ObjectUtils;
 | 
			
		|||
public abstract class JCacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		JCacheOperationSource cas = getCacheOperationSource();
 | 
			
		||||
		return (cas != null && cas.getCacheOperation(method, targetClass) != null);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2012 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ import org.springframework.util.ObjectUtils;
 | 
			
		|||
abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		CacheOperationSource cas = getCacheOperationSource();
 | 
			
		||||
		return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2015 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -23,8 +23,10 @@ import java.util.concurrent.Executor;
 | 
			
		|||
import java.util.concurrent.Future;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
import org.aopalliance.intercept.MethodInterceptor;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
import org.springframework.aop.framework.ProxyFactory;
 | 
			
		||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
 | 
			
		||||
import org.springframework.aop.support.AopUtils;
 | 
			
		||||
import org.springframework.beans.factory.config.BeanDefinition;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +64,26 @@ public class AsyncAnnotationBeanPostProcessorTests {
 | 
			
		|||
	public void invokedAsynchronously() {
 | 
			
		||||
		ConfigurableApplicationContext context = initContext(
 | 
			
		||||
				new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
 | 
			
		||||
 | 
			
		||||
		ITestBean testBean = context.getBean("target", ITestBean.class);
 | 
			
		||||
		testBean.test();
 | 
			
		||||
		Thread mainThread = Thread.currentThread();
 | 
			
		||||
		testBean.await(3000);
 | 
			
		||||
		Thread asyncThread = testBean.getThread();
 | 
			
		||||
		assertNotSame(mainThread, asyncThread);
 | 
			
		||||
		context.close();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void invokedAsynchronouslyOnProxyTarget() {
 | 
			
		||||
		StaticApplicationContext context = new StaticApplicationContext();
 | 
			
		||||
		context.registerBeanDefinition("postProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
 | 
			
		||||
		TestBean tb = new TestBean();
 | 
			
		||||
		ProxyFactory pf = new ProxyFactory(ITestBean.class,
 | 
			
		||||
				(MethodInterceptor) invocation -> invocation.getMethod().invoke(tb, invocation.getArguments()));
 | 
			
		||||
		context.registerBean("target", ITestBean.class, () -> (ITestBean) pf.getProxy());
 | 
			
		||||
		context.refresh();
 | 
			
		||||
 | 
			
		||||
		ITestBean testBean = context.getBean("target", ITestBean.class);
 | 
			
		||||
		testBean.test();
 | 
			
		||||
		Thread mainThread = Thread.currentThread();
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +101,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
 | 
			
		|||
		executor.afterPropertiesSet();
 | 
			
		||||
		processorDefinition.getPropertyValues().add("executor", executor);
 | 
			
		||||
		ConfigurableApplicationContext context = initContext(processorDefinition);
 | 
			
		||||
 | 
			
		||||
		ITestBean testBean = context.getBean("target", ITestBean.class);
 | 
			
		||||
		testBean.test();
 | 
			
		||||
		testBean.await(3000);
 | 
			
		||||
| 
						 | 
				
			
			@ -246,8 +269,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
 | 
			
		|||
 | 
			
		||||
	private ConfigurableApplicationContext initContext(BeanDefinition asyncAnnotationBeanPostProcessorDefinition) {
 | 
			
		||||
		StaticApplicationContext context = new StaticApplicationContext();
 | 
			
		||||
		BeanDefinition targetDefinition =
 | 
			
		||||
				new RootBeanDefinition(AsyncAnnotationBeanPostProcessorTests.TestBean.class);
 | 
			
		||||
		BeanDefinition targetDefinition = new RootBeanDefinition(TestBean.class);
 | 
			
		||||
		context.registerBeanDefinition("postProcessor", asyncAnnotationBeanPostProcessorDefinition);
 | 
			
		||||
		context.registerBeanDefinition("target", targetDefinition);
 | 
			
		||||
		context.refresh();
 | 
			
		||||
| 
						 | 
				
			
			@ -259,6 +281,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
 | 
			
		|||
 | 
			
		||||
		Thread getThread();
 | 
			
		||||
 | 
			
		||||
		@Async
 | 
			
		||||
		void test();
 | 
			
		||||
 | 
			
		||||
		Future<Object> failWithFuture();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2017 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +34,8 @@ import org.springframework.util.ObjectUtils;
 | 
			
		|||
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
 | 
			
		||||
		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
 | 
			
		||||
	public boolean matches(Method method, Class<?> targetClass) {
 | 
			
		||||
		if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		TransactionAttributeSource tas = getTransactionAttributeSource();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2017 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2018 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ public class TransactionInterceptor extends TransactionAspectSupport implements
 | 
			
		|||
 | 
			
		||||
	@Override
 | 
			
		||||
	@Nullable
 | 
			
		||||
	public Object invoke(final MethodInvocation invocation) throws Throwable {
 | 
			
		||||
	public Object invoke(MethodInvocation invocation) throws Throwable {
 | 
			
		||||
		// Work out the target class: may be {@code null}.
 | 
			
		||||
		// The TransactionAttributeSource should be passed the target class
 | 
			
		||||
		// as well as the method, which may be from an interface.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue