34
34
import org .springframework .util .ClassUtils ;
35
35
36
36
/**
37
- * A strategy for synthesizing an annotation from an {@link AnnotatedElement} that
38
- * supports meta-annotations, like the following:
39
- *
40
- * <pre>
41
- * @PreAuthorize("hasRole('ROLE_ADMIN')")
42
- * public @annotation HasRole {
43
- * }
44
- * </pre>
45
- *
46
- * <p>
47
- * In that case, you can use an {@link UniqueMergedAnnotationSynthesizer} of type
48
- * {@link org.springframework.security.access.prepost.PreAuthorize} to synthesize any
49
- * {@code @HasRole} annotation found on a given {@link AnnotatedElement}.
37
+ * Searches for and synthesizes annotations found on types, methods, or method parameters
38
+ * into an annotation of type {@code <A>}, ensuring that there is a unique match.
50
39
*
51
40
* <p>
52
41
* Note that in all cases, Spring Security does not allow for repeatable annotations. As
53
42
* such, this class errors if a repeat is discovered.
54
43
*
55
44
* <p>
56
- * If the given annotation can be applied to types, this class will search for annotations
57
- * across the entire {@link MergedAnnotations.SearchStrategy type hierarchy}; otherwise,
58
- * it will only look for annotations {@link MergedAnnotations.SearchStrategy directly}
59
- * attributed to the element.
45
+ * For example, if a class extends two interfaces, and each interface is annotated with
46
+ * `@PreAuthorize("hasRole('ADMIN')")` and `@PreAuthorize("hasRole('USER')")`
47
+ * respectively, it's not clear which of these should apply, and so this class will throw
48
+ * an exception.
49
+ *
50
+ * <p>
51
+ * If the given annotation can be applied to types or methods, this class will traverse
52
+ * the type hierarchy, starting from the target class and method; in case of a method
53
+ * parameter, it will only consider annotations on the parameter. In all cases, it will
54
+ * consider meta-annotations in its traversal.
60
55
*
61
56
* <p>
62
57
* When traversing the type hierarchy, this class will first look for annotations on the
65
60
* extends and on any interfaces that class implements.
66
61
*
67
62
* <p>
68
- * Since the process of synthesis is expensive, it is recommended to cache the synthesized
63
+ * It supports meta-annotations, like the following:
64
+ *
65
+ * <pre>
66
+ * @PreAuthorize("hasRole('ROLE_ADMIN')")
67
+ * public @annotation HasRole {
68
+ * }
69
+ * </pre>
70
+ *
71
+ * <p>
72
+ * In that case, you can use an {@link UniqueMergedAnnotationSynthesizer} of type
73
+ * {@link org.springframework.security.access.prepost.PreAuthorize} to synthesize any
74
+ * {@code @HasRole} annotation found on a given method or class into its
75
+ * {@link org.springframework.security.access.prepost.PreAuthorize} meta-annotation.
76
+ *
77
+ * <p>
78
+ * Since the process of synthesis is expensive, it's recommended to cache the synthesized
69
79
* result to prevent multiple computations.
70
80
*
71
- * @param <A> the annotation type
81
+ * @param <A> the annotation to search for and synthesize
72
82
* @author Josh Cummings
73
83
* @since 6.4
74
84
*/
75
- final class UniqueMergedAnnotationSynthesizer <A extends Annotation > implements AnnotationSynthesizer <A > {
85
+ final class UniqueMergedAnnotationSynthesizer <A extends Annotation > extends AbstractAnnotationSynthesizer <A > {
76
86
77
87
private final List <Class <A >> types ;
78
88
@@ -87,26 +97,18 @@ final class UniqueMergedAnnotationSynthesizer<A extends Annotation> implements A
87
97
}
88
98
89
99
@ Override
90
- public MergedAnnotation <A > merge (AnnotatedElement element , Class <?> targetClass ) {
100
+ MergedAnnotation <A > merge (AnnotatedElement element , Class <?> targetClass ) {
91
101
if (element instanceof Parameter parameter ) {
92
- return handleParameterElement (parameter );
102
+ List <MergedAnnotation <A >> annotations = findDirectAnnotations (parameter );
103
+ return requireUnique (parameter , annotations );
93
104
}
94
105
if (element instanceof Method method ) {
95
- return handleMethodElement (method , targetClass );
106
+ List <MergedAnnotation <A >> annotations = findMethodAnnotations (method , targetClass );
107
+ return requireUnique (method , annotations );
96
108
}
97
109
throw new AnnotationConfigurationException ("Unsupported element of type " + element .getClass ());
98
110
}
99
111
100
- private MergedAnnotation <A > handleParameterElement (Parameter parameter ) {
101
- List <MergedAnnotation <A >> annotations = findDirectAnnotations (parameter );
102
- return requireUnique (parameter , annotations );
103
- }
104
-
105
- private MergedAnnotation <A > handleMethodElement (Method method , Class <?> targetClass ) {
106
- List <MergedAnnotation <A >> annotations = findMethodAnnotations (method , targetClass );
107
- return requireUnique (method , annotations );
108
- }
109
-
110
112
private MergedAnnotation <A > requireUnique (AnnotatedElement element , List <MergedAnnotation <A >> annotations ) {
111
113
return switch (annotations .size ()) {
112
114
case 0 -> null ;
0 commit comments