Select most specific advice method in case of override
Closes gh-32865
(cherry picked from commit ea596aa211)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 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.
|
||||||
@@ -50,6 +50,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
|||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.core.convert.converter.ConvertingComparator;
|
import org.springframework.core.convert.converter.ConvertingComparator;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
@@ -133,17 +134,19 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
|
|||||||
|
|
||||||
List<Advisor> advisors = new ArrayList<>();
|
List<Advisor> advisors = new ArrayList<>();
|
||||||
for (Method method : getAdvisorMethods(aspectClass)) {
|
for (Method method : getAdvisorMethods(aspectClass)) {
|
||||||
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
|
if (method.equals(ClassUtils.getMostSpecificMethod(method, aspectClass))) {
|
||||||
// to getAdvisor(...) to represent the "current position" in the declared methods list.
|
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
|
||||||
// However, since Java 7 the "current position" is not valid since the JDK no longer
|
// to getAdvisor(...) to represent the "current position" in the declared methods list.
|
||||||
// returns declared methods in the order in which they are declared in the source code.
|
// However, since Java 7 the "current position" is not valid since the JDK no longer
|
||||||
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
|
// returns declared methods in the order in which they are declared in the source code.
|
||||||
// discovered via reflection in order to support reliable advice ordering across JVM launches.
|
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
|
||||||
// Specifically, a value of 0 aligns with the default value used in
|
// discovered via reflection in order to support reliable advice ordering across JVM launches.
|
||||||
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
|
// Specifically, a value of 0 aligns with the default value used in
|
||||||
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
|
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
|
||||||
if (advisor != null) {
|
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
|
||||||
advisors.add(advisor);
|
if (advisor != null) {
|
||||||
|
advisors.add(advisor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2023 the original author or authors.
|
* Copyright 2002-2024 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.
|
||||||
@@ -38,7 +38,6 @@ import org.aspectj.lang.annotation.DeclareParents;
|
|||||||
import org.aspectj.lang.annotation.DeclarePrecedence;
|
import org.aspectj.lang.annotation.DeclarePrecedence;
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.aop.Advisor;
|
import org.springframework.aop.Advisor;
|
||||||
@@ -84,15 +83,15 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
@Test
|
@Test
|
||||||
void rejectsPerCflowAspect() {
|
void rejectsPerCflowAspect() {
|
||||||
assertThatExceptionOfType(AopConfigException.class)
|
assertThatExceptionOfType(AopConfigException.class)
|
||||||
.isThrownBy(() -> getAdvisorFactory().getAdvisors(aspectInstanceFactory(new PerCflowAspect(), "someBean")))
|
.isThrownBy(() -> getAdvisorFactory().getAdvisors(aspectInstanceFactory(new PerCflowAspect(), "someBean")))
|
||||||
.withMessageContaining("PERCFLOW");
|
.withMessageContaining("PERCFLOW");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void rejectsPerCflowBelowAspect() {
|
void rejectsPerCflowBelowAspect() {
|
||||||
assertThatExceptionOfType(AopConfigException.class)
|
assertThatExceptionOfType(AopConfigException.class)
|
||||||
.isThrownBy(() -> getAdvisorFactory().getAdvisors(aspectInstanceFactory(new PerCflowBelowAspect(), "someBean")))
|
.isThrownBy(() -> getAdvisorFactory().getAdvisors(aspectInstanceFactory(new PerCflowBelowAspect(), "someBean")))
|
||||||
.withMessageContaining("PERCFLOWBELOW");
|
.withMessageContaining("PERCFLOWBELOW");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -363,7 +362,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
assertThat(lockable.locked()).as("Already locked").isTrue();
|
assertThat(lockable.locked()).as("Already locked").isTrue();
|
||||||
lockable.lock();
|
lockable.lock();
|
||||||
assertThat(lockable.locked()).as("Real target ignores locking").isTrue();
|
assertThat(lockable.locked()).as("Real target ignores locking").isTrue();
|
||||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> lockable.unlock());
|
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(lockable::unlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -389,9 +388,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
assertThat(lockable.locked()).isTrue();
|
assertThat(lockable.locked()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled
|
|
||||||
void introductionWithArgumentBinding() {
|
void introductionWithArgumentBinding() {
|
||||||
TestBean target = new TestBean();
|
TestBean target = new TestBean();
|
||||||
|
|
||||||
@@ -648,7 +645,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
static class NamedPointcutAspectWithFQN {
|
static class NamedPointcutAspectWithFQN {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
|
private final ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
|
||||||
|
|
||||||
@Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.CommonPointcuts.getAge()()")
|
@Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.CommonPointcuts.getAge()()")
|
||||||
int changeReturnValue(ProceedingJoinPoint pjp) {
|
int changeReturnValue(ProceedingJoinPoint pjp) {
|
||||||
@@ -765,7 +762,7 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
|
|
||||||
|
|
||||||
@Aspect
|
@Aspect
|
||||||
class DoublingAspect {
|
static class DoublingAspect {
|
||||||
|
|
||||||
@Around("execution(* getAge())")
|
@Around("execution(* getAge())")
|
||||||
public Object doubleAge(ProceedingJoinPoint pjp) throws Throwable {
|
public Object doubleAge(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
@@ -773,8 +770,14 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Aspect
|
@Aspect
|
||||||
class IncrementingAspect extends DoublingAspect {
|
static class IncrementingAspect extends DoublingAspect {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object doubleAge(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
|
return ((int) pjp.proceed()) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
@Around("execution(* getAge())")
|
@Around("execution(* getAge())")
|
||||||
public int incrementAge(ProceedingJoinPoint pjp) throws Throwable {
|
public int incrementAge(ProceedingJoinPoint pjp) throws Throwable {
|
||||||
@@ -783,7 +786,6 @@ abstract class AbstractAspectJAdvisorFactoryTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Aspect
|
@Aspect
|
||||||
private static class InvocationTrackingAspect {
|
private static class InvocationTrackingAspect {
|
||||||
|
|
||||||
@@ -1083,7 +1085,7 @@ class PerThisAspect {
|
|||||||
|
|
||||||
// Just to check that this doesn't cause problems with introduction processing
|
// Just to check that this doesn't cause problems with introduction processing
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
|
private final ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
|
||||||
|
|
||||||
@Around("execution(int *.getAge())")
|
@Around("execution(int *.getAge())")
|
||||||
int returnCountAsAge() {
|
int returnCountAsAge() {
|
||||||
|
|||||||
Reference in New Issue
Block a user