From f8272a884494f60853b81e2260e28aaac53a658c Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Mon, 15 Sep 2025 09:16:50 -0600 Subject: [PATCH] Fallback to Object When Determining Overridden Methods Closes gh-17898 --- .../UniqueSecurityAnnotationScanner.java | 2 +- .../UniqueSecurityAnnotationScannerTests.java | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java index 9c5b8b1377..75c12eac47 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java +++ b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java @@ -308,7 +308,7 @@ final class UniqueSecurityAnnotationScanner extends Abstra } for (int i = 0; i < rootParameterTypes.length; i++) { Class resolvedParameterType = ResolvableType.forMethodParameter(candidateMethod, i, sourceDeclaringClass) - .resolve(); + .toClass(); if (rootParameterTypes[i] != resolvedParameterType) { return false; } diff --git a/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java b/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java index 359fda57bc..ffb0c6f6f8 100644 --- a/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java +++ b/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test; import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.ClassUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -326,6 +327,14 @@ public class UniqueSecurityAnnotationScannerTests { .isThrownBy(() -> this.parameterScanner.scan(parameter)); } + // gh-17898 + @Test + void scanWhenAnnotationOnParameterizedUndeclaredMethodAndThenLocates() throws Exception { + Method method = ClassUtils.getMethod(GenericInterfaceImpl.class, "processOneAndTwo", Long.class, Object.class); + PreAuthorize pre = this.scanner.scan(method, method.getDeclaringClass()); + assertThat(pre).isNotNull(); + } + interface UserService { void add(@CustomParameterAnnotation("one") String user); @@ -764,4 +773,27 @@ public class UniqueSecurityAnnotationScannerTests { } + interface GenericInterface { + + @PreAuthorize("hasAuthority('thirtythree')") + void processOneAndTwo(A value1, B value2); + + } + + abstract static class GenericAbstractSuperclass implements GenericInterface { + + @Override + public void processOneAndTwo(Long value1, C value2) { + } + + } + + static class GenericInterfaceImpl extends GenericAbstractSuperclass { + + // The compiler does not require us to declare a concrete + // processOneAndTwo(Long, String) method, and we intentionally + // do not declare one here. + + } + }