Support nested annotations in AnnotationAttributes
This commit introduces support in AnnotationAttributes for retrieving nested annotations that is on par with the existing type-safe support for retrieving nested AnnotationAttributes. Issue: SPR-13074
This commit is contained in:
@@ -205,6 +205,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
/**
|
||||
* Get the {@link AnnotationAttributes} stored under the specified
|
||||
* {@code attributeName}.
|
||||
* <p>Note: if you expect an actual annotation, invoke
|
||||
* {@link #getAnnotation(String, Class)} instead.
|
||||
* @param attributeName the name of the attribute to get; never
|
||||
* {@code null} or empty
|
||||
* @return the {@code AnnotationAttributes}
|
||||
@@ -215,12 +217,29 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
return doGet(attributeName, AnnotationAttributes.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the annotation of type {@code annotationType} stored under the
|
||||
* specified {@code attributeName}.
|
||||
* @param attributeName the name of the attribute to get; never
|
||||
* {@code null} or empty
|
||||
* @param annotationType the expected annotation type; never {@code null}
|
||||
* @return the annotation
|
||||
* @throws IllegalArgumentException if the attribute does not exist or
|
||||
* if it is not of the expected type
|
||||
* @since 4.2
|
||||
*/
|
||||
public <A extends Annotation> A getAnnotation(String attributeName, Class<A> annotationType) {
|
||||
return doGet(attributeName, annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of {@link AnnotationAttributes} stored under the specified
|
||||
* {@code attributeName}.
|
||||
* <p>If the value stored under the specified {@code attributeName} is
|
||||
* an instance of {@code AnnotationAttributes}, it will be wrapped in
|
||||
* a single-element array before returning it.
|
||||
* <p>Note: if you expect an actual array of annotations, invoke
|
||||
* {@link #getAnnotationArray(String, Class)} instead.
|
||||
* @param attributeName the name of the attribute to get; never
|
||||
* {@code null} or empty
|
||||
* @return the array of {@code AnnotationAttributes}
|
||||
@@ -231,6 +250,26 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
return doGet(attributeName, AnnotationAttributes[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of type {@code annotationType} stored under the specified
|
||||
* {@code attributeName}.
|
||||
* <p>If the value stored under the specified {@code attributeName} is
|
||||
* an {@code Annotation}, it will be wrapped in a single-element array
|
||||
* before returning it.
|
||||
* @param attributeName the name of the attribute to get; never
|
||||
* {@code null} or empty
|
||||
* @param annotationType the expected annotation type; never {@code null}
|
||||
* @return the annotation array
|
||||
* @throws IllegalArgumentException if the attribute does not exist or
|
||||
* if it is not of the expected type
|
||||
* @since 4.2
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A extends Annotation> A[] getAnnotationArray(String attributeName, Class<A> annotationType) {
|
||||
Object array = Array.newInstance(annotationType, 0);
|
||||
return (A[]) doGet(attributeName, array.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value stored under the specified {@code attributeName},
|
||||
* ensuring that the value is of the {@code expectedType}.
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.core.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
@@ -32,10 +35,6 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class AnnotationAttributesTests {
|
||||
|
||||
enum Color {
|
||||
RED, WHITE, BLUE
|
||||
}
|
||||
|
||||
private final AnnotationAttributes attributes = new AnnotationAttributes();
|
||||
|
||||
@Rule
|
||||
@@ -72,7 +71,9 @@ public class AnnotationAttributesTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleElementToSingleElementArrayConversionSupport() {
|
||||
public void singleElementToSingleElementArrayConversionSupport() throws Exception {
|
||||
Filter filter = FilteredClass.class.getAnnotation(Filter.class);
|
||||
|
||||
AnnotationAttributes nestedAttributes = new AnnotationAttributes();
|
||||
nestedAttributes.put("name", "Dilbert");
|
||||
|
||||
@@ -80,15 +81,38 @@ public class AnnotationAttributesTests {
|
||||
attributes.put("names", "Dogbert");
|
||||
attributes.put("classes", Number.class);
|
||||
attributes.put("nestedAttributes", nestedAttributes);
|
||||
attributes.put("filters", filter);
|
||||
|
||||
// Get back arrays of single elements
|
||||
assertThat(attributes.getStringArray("names"), equalTo(new String[] { "Dogbert" }));
|
||||
assertThat(attributes.getClassArray("classes"), equalTo(new Class[] { Number.class }));
|
||||
|
||||
AnnotationAttributes[] array = attributes.getAnnotationArray("nestedAttributes");
|
||||
assertNotNull(array);
|
||||
assertTrue(array.getClass().isArray());
|
||||
assertThat(array.length, is(1));
|
||||
assertThat(array[0].getString("name"), equalTo("Dilbert"));
|
||||
|
||||
Filter[] filters = attributes.getAnnotationArray("filters", Filter.class);
|
||||
assertNotNull(filters);
|
||||
assertThat(filters.length, is(1));
|
||||
assertThat(filters[0].pattern(), equalTo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedAnnotations() throws Exception {
|
||||
Filter filter = FilteredClass.class.getAnnotation(Filter.class);
|
||||
|
||||
attributes.put("filter", filter);
|
||||
attributes.put("filters", new Filter[] { filter, filter });
|
||||
|
||||
Filter retrievedFilter = attributes.getAnnotation("filter", Filter.class);
|
||||
assertThat(retrievedFilter, equalTo(filter));
|
||||
assertThat(retrievedFilter.pattern(), equalTo("foo"));
|
||||
|
||||
Filter[] retrievedFilters = attributes.getAnnotationArray("filters", Filter.class);
|
||||
assertNotNull(retrievedFilters);
|
||||
assertEquals(2, retrievedFilters.length);
|
||||
assertThat(retrievedFilters[1].pattern(), equalTo("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -120,4 +144,17 @@ public class AnnotationAttributesTests {
|
||||
attributes.getEnum("color");
|
||||
}
|
||||
|
||||
|
||||
enum Color {
|
||||
RED, WHITE, BLUE
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Filter {
|
||||
String pattern();
|
||||
}
|
||||
|
||||
@Filter(pattern = "foo")
|
||||
static class FilteredClass {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user