Skip to content

Commit 9f71787

Browse files
committed
Introduce getAnnotation() in AnnotatedElementUtils
This commit introduces a "synthesized annotation" alternative to getAnnotationAttributes() in AnnotatedElementUtils, analogous to the recently introduced findAnnotation() methods. Issue: SPR-13082
1 parent 9afcd17 commit 9f71787

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,32 @@ public Boolean process(AnnotatedElement annotatedElement, Annotation annotation,
218218
}));
219219
}
220220

221+
/**
222+
* Get the first annotation of the specified {@code annotationType} within
223+
* the annotation hierarchy <em>above</em> the supplied {@code element},
224+
* merge that annotation's attributes with <em>matching</em> attributes from
225+
* annotations in lower levels of the annotation hierarchy, and synthesize
226+
* the result back into an annotation of the specified {@code annotationType}.
227+
*
228+
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both
229+
* within a single annotation and within the annotation hierarchy.
230+
*
231+
* <p>This method delegates to {@link #getAnnotationAttributes(AnnotatedElement, Class)}
232+
* and {@link AnnotationUtils#synthesizeAnnotation(Map, Class, AnnotatedElement)}.
233+
*
234+
* @param element the annotated element; never {@code null}
235+
* @param annotationType the annotation type to find; never {@code null}
236+
* @return the merged {@code AnnotationAttributes}, or {@code null} if not found
237+
* @since 4.2
238+
* @see #getAnnotationAttributes(AnnotatedElement, Class)
239+
* @see #findAnnotation(AnnotatedElement, Class)
240+
* @see AnnotationUtils#synthesizeAnnotation(Map, Class, AnnotatedElement)
241+
*/
242+
public static <A extends Annotation> A getAnnotation(AnnotatedElement element, Class<A> annotationType) {
243+
AnnotationAttributes attributes = getAnnotationAttributes(element, annotationType);
244+
return ((attributes != null) ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null);
245+
}
246+
221247
/**
222248
* Get the first annotation of the specified {@code annotationType} within
223249
* the annotation hierarchy <em>above</em> the supplied {@code element} and
@@ -232,9 +258,10 @@ public Boolean process(AnnotatedElement annotatedElement, Annotation annotation,
232258
* @param element the annotated element; never {@code null}
233259
* @param annotationType the annotation type to find; never {@code null}
234260
* @return the merged {@code AnnotationAttributes}, or {@code null} if not found
261+
* @since 4.2
235262
* @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
236-
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
237263
* @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
264+
* @see #getAnnotation(AnnotatedElement, Class)
238265
* @see #findAnnotation(AnnotatedElement, Class)
239266
*/
240267
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element,
@@ -945,8 +972,9 @@ public final void postProcess(AnnotatedElement annotatedElement, Annotation anno
945972
* target annotation during the {@link #process} phase and then merges
946973
* annotation attributes from lower levels in the annotation hierarchy
947974
* during the {@link #postProcess} phase.
948-
* @see AnnotationUtils#getAnnotationAttributes(Annotation)
949975
* @since 4.2
976+
* @see AnnotationUtils#getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean, boolean)
977+
* @see AnnotationUtils#postProcessAnnotationAttributes
950978
*/
951979
private static class MergedAnnotationAttributesProcessor implements Processor<AnnotationAttributes> {
952980

spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,8 @@ public static AnnotationAttributes getAnnotationAttributes(Annotation annotation
766766
* @param annotation the annotation to retrieve the attributes for
767767
* @return the annotation attributes (a specialized Map) with attribute names as keys
768768
* and corresponding attribute values as values; never {@code null}
769-
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
770769
* @since 4.2
770+
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
771771
*/
772772
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement, Annotation annotation) {
773773
return getAnnotationAttributes(annotatedElement, annotation, false, false);
@@ -1233,8 +1233,8 @@ else if (Annotation.class.isAssignableFrom(returnType)) {
12331233
* not from an annotation, or if the supplied target type is {@link Annotation}
12341234
* @throws AnnotationConfigurationException if invalid configuration of
12351235
* {@code @AliasFor} is detected
1236-
* @see #getAliasedAttributeName(Method, Class)
12371236
* @since 4.2
1237+
* @see #getAliasedAttributeName(Method, Class)
12381238
*/
12391239
static String getAliasedAttributeName(Method attribute) {
12401240
return getAliasedAttributeName(attribute, null);

spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,19 @@ public void getAnnotationAttributesWithAliasedValueComposedAnnotation() {
322322
assertTrue(isAnnotated(element, name));
323323
}
324324

325+
@Test
326+
public void getAnnotationWithAliasedValueComposedAnnotation() {
327+
Class<?> element = AliasedValueComposedContextConfigClass.class;
328+
ContextConfig contextConfig = getAnnotation(element, ContextConfig.class);
329+
330+
assertNotNull("Should find @ContextConfig on " + element.getSimpleName(), contextConfig);
331+
assertArrayEquals("locations", new String[] { "test.xml" }, contextConfig.locations());
332+
assertArrayEquals("value", new String[] { "test.xml" }, contextConfig.value());
333+
334+
// Verify contracts between utility methods:
335+
assertTrue(isAnnotated(element, ContextConfig.class.getName()));
336+
}
337+
325338
@Test
326339
public void getAnnotationAttributesWithInvalidConventionBasedComposedAnnotation() {
327340
Class<?> element = InvalidConventionBasedComposedContextConfigClass.class;

0 commit comments

Comments
 (0)