diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAnnotationUtils.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAnnotationUtils.java index fa883a2089c..9f37603826c 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAnnotationUtils.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationAnnotationUtils.java @@ -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"); * you may not use this file except in compliance with the License. @@ -17,31 +17,36 @@ package org.springframework.security.authorization.method; import java.lang.annotation.Annotation; -import java.lang.reflect.Executable; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; +import java.util.List; import org.springframework.core.annotation.AnnotationConfigurationException; -import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; +import org.springframework.core.annotation.MergedAnnotations.SearchStrategy; import org.springframework.core.annotation.RepeatableContainers; /** - * A wrapper around {@link AnnotationUtils} that checks for, and errors on, conflicting - * annotations. This is specifically important for Spring Security annotations which are - * not designed to be repeatable. + * A collection of utility methods that check for, and error on, conflicting annotations. + * This is specifically important for Spring Security annotations which are not designed + * to be repeatable. * + *
* There are numerous ways that two annotations of the same type may be attached to the * same method. For example, a class may implement a method defined in two separate - * interfaces. If both of those interfaces have a `@PreAuthorize` annotation, then it's - * unclear which `@PreAuthorize` expression Spring Security should use. + * interfaces. If both of those interfaces have a {@code @PreAuthorize} annotation, then + * it's unclear which {@code @PreAuthorize} expression Spring Security should use. * + *
* Another way is when one of Spring Security's annotations is used as a meta-annotation. * In that case, two custom annotations can be declared, each with their own - * `@PreAuthorize` declaration. If both custom annotations are used on the same method, - * then it's unclear which `@PreAuthorize` expression Spring Security should use. + * {@code @PreAuthorize} declaration. If both custom annotations are used on the same + * method, then it's unclear which {@code @PreAuthorize} expression Spring Security should + * use. * * @author Josh Cummings + * @author Sam Brannen */ final class AuthorizationAnnotationUtils { @@ -50,23 +55,17 @@ final class AuthorizationAnnotationUtils { * the annotation of type {@code annotationType}, including any annotations using * {@code annotationType} as a meta-annotation. * - * If more than one is found, then throw an error. + *
+ * If more than one unique annotation is found, then throw an error.
* @param method the method declaration to search from
* @param annotationType the annotation type to search for
- * @return the unique instance of the annotation attributed to the method,
- * {@code null} otherwise
- * @throws AnnotationConfigurationException if more than one instance of the
+ * @return a unique instance of the annotation attributed to the method, {@code null}
+ * otherwise
+ * @throws AnnotationConfigurationException if more than one unique instance of the
* annotation is found
*/
static A findUniqueAnnotation(Method method, Class annotationType) {
- MergedAnnotations mergedAnnotations = MergedAnnotations.from(method,
- MergedAnnotations.SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none());
- if (hasDuplicate(mergedAnnotations, annotationType)) {
- throw new AnnotationConfigurationException("Found more than one annotation of type " + annotationType
- + " attributed to " + method
- + " Please remove the duplicate annotations and publish a bean to handle your authorization logic.");
- }
- return AnnotationUtils.findAnnotation(method, annotationType);
+ return findDistinctAnnotation(method, annotationType);
}
/**
@@ -74,60 +73,38 @@ static A findUniqueAnnotation(Method method, Class ann
* the annotation of type {@code annotationType}, including any annotations using
* {@code annotationType} as a meta-annotation.
*
- * If more than one is found, then throw an error.
+ *
+ * If more than one unique annotation is found, then throw an error.
* @param type the type to search from
* @param annotationType the annotation type to search for
- * @return the unique instance of the annotation attributed to the method,
- * {@code null} otherwise
- * @throws AnnotationConfigurationException if more than one instance of the
+ * @return a unique instance of the annotation attributed to the class, {@code null}
+ * otherwise
+ * @throws AnnotationConfigurationException if more than one unique instance of the
* annotation is found
*/
static A findUniqueAnnotation(Class> type, Class annotationType) {
- MergedAnnotations mergedAnnotations = MergedAnnotations.from(type,
- MergedAnnotations.SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none());
- if (hasDuplicate(mergedAnnotations, annotationType)) {
- throw new AnnotationConfigurationException("Found more than one annotation of type " + annotationType
- + " attributed to " + type
- + " Please remove the duplicate annotations and publish a bean to handle your authorization logic.");
- }
- return AnnotationUtils.findAnnotation(type, annotationType);
+ return findDistinctAnnotation(type, annotationType);
}
- private static boolean hasDuplicate(MergedAnnotations mergedAnnotations,
+ private static A findDistinctAnnotation(AnnotatedElement annotatedElement,
Class annotationType) {
- MergedAnnotation