AspectJExpressionPointcut consistently resolves superinterface methods
Includes efficient check for same ClassLoader in ClassUtils.isVisible, efficient MethodMatchers check for IntroductionAwareMethodMatcher, and supertype method resolution in MethodMapTransactionAttributeSource. Issue: SPR-16723
This commit is contained in:
parent
c6ed41ec47
commit
b95e05db04
|
|
@ -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.
|
||||
|
|
@ -49,13 +49,13 @@ import org.springframework.aop.ProxyMethodInvocation;
|
|||
import org.springframework.aop.framework.autoproxy.ProxyCreationContext;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.aop.support.AbstractExpressionPointcut;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
|
@ -289,10 +289,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Method method, @Nullable Class<?> targetClass, boolean beanHasIntroductions) {
|
||||
public boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
|
||||
obtainPointcutExpression();
|
||||
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
|
||||
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
|
||||
|
||||
// Special handling for this, target, @this, @target, @annotation
|
||||
// in Spring - we can optimize since we know we have exactly this class,
|
||||
|
|
@ -305,7 +304,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
}
|
||||
else {
|
||||
// the maybe case
|
||||
if (beanHasIntroductions) {
|
||||
if (hasIntroductions) {
|
||||
return true;
|
||||
}
|
||||
// A match test returned maybe - if there are any subtype sensitive variables
|
||||
|
|
@ -331,8 +330,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
@Override
|
||||
public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
|
||||
obtainPointcutExpression();
|
||||
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
|
||||
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
|
||||
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
|
||||
|
||||
// Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
|
||||
// consistent with return of MethodInvocationProceedingJoinPoint
|
||||
|
|
@ -367,7 +365,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
* <p>See SPR-2979 for the original bug.
|
||||
*/
|
||||
if (pmi != null && thisObject != null) { // there is a current invocation
|
||||
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
|
||||
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(getShadowMatch(method, method));
|
||||
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -427,6 +425,23 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
invocation.setUserAttribute(resolveExpression(), jpm);
|
||||
}
|
||||
|
||||
private ShadowMatch getTargetShadowMatch(Method method, @Nullable Class<?> targetClass) {
|
||||
Method targetMethod = method;
|
||||
if (targetClass != null) {
|
||||
targetMethod = ClassUtils.getMostSpecificMethod(method, ClassUtils.getUserClass(targetClass));
|
||||
if (targetMethod.getDeclaringClass().isInterface()) {
|
||||
Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
|
||||
if (ifcs.size() > 1) {
|
||||
Class<?> compositeInterface = ClassUtils.createCompositeInterface(
|
||||
ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
|
||||
targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
targetMethod = BridgeMethodResolver.findBridgedMethod(targetMethod);
|
||||
return getShadowMatch(targetMethod, method);
|
||||
}
|
||||
|
||||
private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
|
||||
// Avoid lock contention for known Methods through concurrent access...
|
||||
ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
|
|
@ -434,9 +449,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
synchronized (this.shadowMatchCache) {
|
||||
// Not found - now check again with full lock...
|
||||
PointcutExpression fallbackExpression = null;
|
||||
Method methodToMatch = targetMethod;
|
||||
shadowMatch = this.shadowMatchCache.get(targetMethod);
|
||||
if (shadowMatch == null) {
|
||||
Method methodToMatch = targetMethod;
|
||||
try {
|
||||
try {
|
||||
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
|
||||
|
|
@ -459,7 +474,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
try {
|
||||
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
catch (ReflectionWorldException ex3) {
|
||||
catch (ReflectionWorldException ex) {
|
||||
// Could neither introspect the target class nor the proxy class ->
|
||||
// let's try the original method's declaring class before we give up...
|
||||
try {
|
||||
|
|
@ -468,7 +483,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
|
|||
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
|
||||
}
|
||||
}
|
||||
catch (ReflectionWorldException ex4) {
|
||||
catch (ReflectionWorldException ex2) {
|
||||
fallbackExpression = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -90,8 +90,8 @@ public abstract class MethodMatchers {
|
|||
*/
|
||||
public static boolean matches(MethodMatcher mm, Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
|
||||
Assert.notNull(mm, "MethodMatcher must not be null");
|
||||
return ((mm instanceof IntroductionAwareMethodMatcher &&
|
||||
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) ||
|
||||
return (mm instanceof IntroductionAwareMethodMatcher ?
|
||||
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
|
||||
mm.matches(method, targetClass));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.tests.sample.beans;
|
||||
|
||||
public interface AgeHolder {
|
||||
|
||||
default int age() {
|
||||
return getAge();
|
||||
}
|
||||
|
||||
int getAge();
|
||||
|
||||
void setAge(int age);
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 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.
|
||||
|
|
@ -27,11 +27,7 @@ import java.io.IOException;
|
|||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public interface ITestBean {
|
||||
|
||||
int getAge();
|
||||
|
||||
void setAge(int age);
|
||||
public interface ITestBean extends AgeHolder {
|
||||
|
||||
String getName();
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -185,7 +185,7 @@ public class AspectJAutoProxyCreatorTests {
|
|||
// Create a child factory with a bean that should be woven
|
||||
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
|
||||
bd.getPropertyValues().addPropertyValue(new PropertyValue("name", "Adrian"))
|
||||
.addPropertyValue(new PropertyValue("age", new Integer(34)));
|
||||
.addPropertyValue(new PropertyValue("age", 34));
|
||||
childAc.registerBeanDefinition("adrian2", bd);
|
||||
// Register the advisor auto proxy creator with subclass
|
||||
childAc.registerBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class.getName(), new RootBeanDefinition(
|
||||
|
|
@ -270,25 +270,45 @@ public class AspectJAutoProxyCreatorTests {
|
|||
assertEquals(3, adrian1.getAge());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoAdviceAspect() {
|
||||
ClassPathXmlApplicationContext bf = newContext("twoAdviceAspect.xml");
|
||||
|
||||
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
|
||||
testAgeAspect(adrian1, 0, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoAdviceAspectSingleton() {
|
||||
doTestTwoAdviceAspectWith("twoAdviceAspect.xml");
|
||||
ClassPathXmlApplicationContext bf = newContext("twoAdviceAspectSingleton.xml");
|
||||
|
||||
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
|
||||
testAgeAspect(adrian1, 0, 1);
|
||||
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
|
||||
assertNotSame(adrian1, adrian2);
|
||||
testAgeAspect(adrian2, 2, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoAdviceAspectPrototype() {
|
||||
doTestTwoAdviceAspectWith("twoAdviceAspectPrototype.xml");
|
||||
}
|
||||
ClassPathXmlApplicationContext bf = newContext("twoAdviceAspectPrototype.xml");
|
||||
|
||||
private void doTestTwoAdviceAspectWith(String location) {
|
||||
ClassPathXmlApplicationContext bf = newContext(location);
|
||||
|
||||
boolean aspectSingleton = bf.isSingleton("aspect");
|
||||
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
|
||||
testPrototype(adrian1, 0);
|
||||
testAgeAspect(adrian1, 0, 1);
|
||||
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
|
||||
assertNotSame(adrian1, adrian2);
|
||||
testPrototype(adrian2, aspectSingleton ? 2 : 0);
|
||||
testAgeAspect(adrian2, 0, 1);
|
||||
}
|
||||
|
||||
private void testAgeAspect(ITestBean adrian, int start, int increment) {
|
||||
assertTrue(AopUtils.isAopProxy(adrian));
|
||||
adrian.setName("");
|
||||
assertEquals(start, adrian.age());
|
||||
int newAge = 32;
|
||||
adrian.setAge(newAge);
|
||||
assertEquals(start + increment, adrian.age());
|
||||
adrian.setAge(0);
|
||||
assertEquals(start + increment * 2, adrian.age());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -312,18 +332,6 @@ public class AspectJAutoProxyCreatorTests {
|
|||
assertEquals(68, adrian.getAge());
|
||||
}
|
||||
|
||||
private void testPrototype(ITestBean adrian1, int start) {
|
||||
assertTrue(AopUtils.isAopProxy(adrian1));
|
||||
//TwoAdviceAspect twoAdviceAspect = (TwoAdviceAspect) bf.getBean(TwoAdviceAspect.class.getName());
|
||||
adrian1.setName("");
|
||||
assertEquals(start++, adrian1.getAge());
|
||||
int newAge = 32;
|
||||
adrian1.setAge(newAge);
|
||||
assertEquals(start++, adrian1.getAge());
|
||||
adrian1.setAge(0);
|
||||
assertEquals(start++, adrian1.getAge());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForceProxyTargetClass() {
|
||||
ClassPathXmlApplicationContext bf = newContext("aspectsWithCGLIB.xml");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,19 @@
|
|||
/**
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package test.aspect;
|
||||
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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,15 +23,17 @@ import org.aspectj.lang.annotation.Before;
|
|||
|
||||
@Aspect
|
||||
public class TwoAdviceAspect {
|
||||
|
||||
private int totalCalls;
|
||||
|
||||
@Around("execution(* getAge())")
|
||||
@Around("execution(* org.springframework.tests.sample.beans.ITestBean.age())")
|
||||
public int returnCallCount(ProceedingJoinPoint pjp) throws Exception {
|
||||
return totalCalls;
|
||||
}
|
||||
|
||||
@Before("execution(* setAge(int)) && args(newAge)")
|
||||
@Before("execution(* org.springframework.tests.sample.beans.ITestBean.setAge(int)) && args(newAge)")
|
||||
public void countSet(int newAge) throws Exception {
|
||||
++totalCalls;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@
|
|||
|
||||
<bean id="aspect" class="test.aspect.TwoAdviceAspect"/>
|
||||
|
||||
<bean id="adrian" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
|
||||
<property name="name" value="adrian"/>
|
||||
<property name="age" value="34"/>
|
||||
<bean id="adrian" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="target">
|
||||
<bean class="org.springframework.tests.sample.beans.TestBean">
|
||||
<property name="name" value="adrian"/>
|
||||
<property name="age" value="34"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
|
||||
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
|
||||
|
||||
<bean id="aspect" class="test.aspect.TwoAdviceAspect"
|
||||
scope="prototype"/>
|
||||
<bean id="aspect" class="test.aspect.TwoAdviceAspect" scope="prototype"/>
|
||||
|
||||
<bean id="adrian" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
|
||||
<property name="name" value="adrian"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
|
||||
|
||||
<bean id="aspect" class="test.aspect.TwoAdviceAspect"/>
|
||||
|
||||
<bean id="adrian" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
|
||||
<property name="name" value="adrian"/>
|
||||
<property name="age" value="34"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
@ -348,13 +348,16 @@ public abstract class ClassUtils {
|
|||
return true;
|
||||
}
|
||||
try {
|
||||
return (clazz == classLoader.loadClass(clazz.getName()));
|
||||
// Else: different class with same name found
|
||||
if (clazz.getClassLoader() == classLoader) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// No corresponding class found at all
|
||||
return false;
|
||||
catch (SecurityException ex) {
|
||||
// Fall through to loadable check below
|
||||
}
|
||||
|
||||
// Visible if same Class can be loaded from given ClassLoader
|
||||
return isLoadable(clazz, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -392,12 +395,29 @@ public abstract class ClassUtils {
|
|||
}
|
||||
}
|
||||
catch (SecurityException ex) {
|
||||
// Fall through to Class reference comparison below
|
||||
// Fall through to loadable check below
|
||||
}
|
||||
|
||||
// Fallback for ClassLoaders without parent/child relationship:
|
||||
// safe if same Class can be loaded from given ClassLoader
|
||||
return (classLoader != null && isVisible(clazz, classLoader));
|
||||
return (classLoader != null && isLoadable(clazz, classLoader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given class is loadable in the given ClassLoader.
|
||||
* @param clazz the class to check (typically an interface)
|
||||
* @param classLoader the ClassLoader to check against
|
||||
* @since 5.0.6
|
||||
*/
|
||||
private static boolean isLoadable(Class<?> clazz, ClassLoader classLoader) {
|
||||
try {
|
||||
return (clazz == classLoader.loadClass(clazz.getName()));
|
||||
// Else: different class with same name found
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// No corresponding class found at all
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -711,14 +731,16 @@ public abstract class ClassUtils {
|
|||
public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz, @Nullable ClassLoader classLoader) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
if (clazz.isInterface() && isVisible(clazz, classLoader)) {
|
||||
return Collections.<Class<?>>singleton(clazz);
|
||||
return Collections.singleton(clazz);
|
||||
}
|
||||
Set<Class<?>> interfaces = new LinkedHashSet<>();
|
||||
Class<?> current = clazz;
|
||||
while (current != null) {
|
||||
Class<?>[] ifcs = current.getInterfaces();
|
||||
for (Class<?> ifc : ifcs) {
|
||||
interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader));
|
||||
if (isVisible(ifc, classLoader)) {
|
||||
interfaces.add(ifc);
|
||||
}
|
||||
}
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
|
|
@ -1211,8 +1233,7 @@ public abstract class ClassUtils {
|
|||
* {@code targetClass} doesn't implement it or is {@code null}
|
||||
*/
|
||||
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
|
||||
if (isOverridable(method, targetClass) &&
|
||||
targetClass != null && targetClass != method.getDeclaringClass()) {
|
||||
if (targetClass != null && targetClass != method.getDeclaringClass() && isOverridable(method, targetClass)) {
|
||||
try {
|
||||
if (Modifier.isPublic(method.getModifiers())) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -32,6 +32,7 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Simple {@link TransactionAttributeSource} implementation that
|
||||
|
|
@ -144,7 +145,7 @@ public class MethodMapTransactionAttributeSource
|
|||
Assert.notNull(mappedName, "Mapped name must not be null");
|
||||
String name = clazz.getName() + '.' + mappedName;
|
||||
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
|
||||
List<Method> matchingMethods = new ArrayList<>();
|
||||
for (Method method : methods) {
|
||||
if (isMatch(method.getName(), mappedName)) {
|
||||
|
|
@ -156,7 +157,7 @@ public class MethodMapTransactionAttributeSource
|
|||
"Couldn't find method '" + mappedName + "' on class [" + clazz.getName() + "]");
|
||||
}
|
||||
|
||||
// register all matching methods
|
||||
// Register all matching methods
|
||||
for (Method method : matchingMethods) {
|
||||
String regMethodName = this.methodNameMap.get(method);
|
||||
if (regMethodName == null || (!regMethodName.equals(name) && regMethodName.length() <= name.length())) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -45,7 +45,6 @@ import org.springframework.transaction.TransactionStatus;
|
|||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test cases for AOP transaction management.
|
||||
*
|
||||
|
|
@ -67,7 +66,7 @@ public class BeanFactoryTransactionTests {
|
|||
|
||||
|
||||
@Test
|
||||
public void testGetsAreNotTransactionalWithProxyFactory1() throws NoSuchMethodException {
|
||||
public void testGetsAreNotTransactionalWithProxyFactory1() {
|
||||
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory1");
|
||||
assertTrue("testBean is a dynamic proxy", Proxy.isProxyClass(testBean.getClass()));
|
||||
assertFalse(testBean instanceof TransactionalProxy);
|
||||
|
|
@ -75,7 +74,7 @@ public class BeanFactoryTransactionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetsAreNotTransactionalWithProxyFactory2DynamicProxy() throws NoSuchMethodException {
|
||||
public void testGetsAreNotTransactionalWithProxyFactory2DynamicProxy() {
|
||||
this.factory.preInstantiateSingletons();
|
||||
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2DynamicProxy");
|
||||
assertTrue("testBean is a dynamic proxy", Proxy.isProxyClass(testBean.getClass()));
|
||||
|
|
@ -84,7 +83,7 @@ public class BeanFactoryTransactionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetsAreNotTransactionalWithProxyFactory2Cglib() throws NoSuchMethodException {
|
||||
public void testGetsAreNotTransactionalWithProxyFactory2Cglib() {
|
||||
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2Cglib");
|
||||
assertTrue("testBean is CGLIB advised", AopUtils.isCglibProxy(testBean));
|
||||
assertTrue(testBean instanceof TransactionalProxy);
|
||||
|
|
@ -92,7 +91,7 @@ public class BeanFactoryTransactionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testProxyFactory2Lazy() throws NoSuchMethodException {
|
||||
public void testProxyFactory2Lazy() {
|
||||
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory2Lazy");
|
||||
assertFalse(factory.containsSingleton("target"));
|
||||
assertEquals(666, testBean.getAge());
|
||||
|
|
@ -100,7 +99,7 @@ public class BeanFactoryTransactionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCglibTransactionProxyImplementsNoInterfaces() throws NoSuchMethodException {
|
||||
public void testCglibTransactionProxyImplementsNoInterfaces() {
|
||||
ImplementsNoInterfaces ini = (ImplementsNoInterfaces) factory.getBean("cglibNoInterfaces");
|
||||
assertTrue("testBean is CGLIB advised", AopUtils.isCglibProxy(ini));
|
||||
assertTrue(ini instanceof TransactionalProxy);
|
||||
|
|
@ -116,7 +115,7 @@ public class BeanFactoryTransactionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetsAreNotTransactionalWithProxyFactory3() throws NoSuchMethodException {
|
||||
public void testGetsAreNotTransactionalWithProxyFactory3() {
|
||||
ITestBean testBean = (ITestBean) factory.getBean("proxyFactory3");
|
||||
assertTrue("testBean is a full proxy", testBean instanceof DerivedTestBean);
|
||||
assertTrue(testBean instanceof TransactionalProxy);
|
||||
|
|
@ -202,7 +201,7 @@ public class BeanFactoryTransactionTests {
|
|||
* Test that we can set the target to a dynamic TargetSource.
|
||||
*/
|
||||
@Test
|
||||
public void testDynamicTargetSource() throws NoSuchMethodException {
|
||||
public void testDynamicTargetSource() {
|
||||
// Install facade
|
||||
CallCountingTransactionManager txMan = new CallCountingTransactionManager();
|
||||
PlatformTransactionManagerFacade.delegate = txMan;
|
||||
|
|
|
|||
Loading…
Reference in New Issue