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
|
* Get the {@link AnnotationAttributes} stored under the specified
|
||||||
* {@code attributeName}.
|
* {@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
|
* @param attributeName the name of the attribute to get; never
|
||||||
* {@code null} or empty
|
* {@code null} or empty
|
||||||
* @return the {@code AnnotationAttributes}
|
* @return the {@code AnnotationAttributes}
|
||||||
@@ -215,12 +217,29 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
|||||||
return doGet(attributeName, AnnotationAttributes.class);
|
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
|
* Get the array of {@link AnnotationAttributes} stored under the specified
|
||||||
* {@code attributeName}.
|
* {@code attributeName}.
|
||||||
* <p>If the value stored under the specified {@code attributeName} is
|
* <p>If the value stored under the specified {@code attributeName} is
|
||||||
* an instance of {@code AnnotationAttributes}, it will be wrapped in
|
* an instance of {@code AnnotationAttributes}, it will be wrapped in
|
||||||
* a single-element array before returning it.
|
* 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
|
* @param attributeName the name of the attribute to get; never
|
||||||
* {@code null} or empty
|
* {@code null} or empty
|
||||||
* @return the array of {@code AnnotationAttributes}
|
* @return the array of {@code AnnotationAttributes}
|
||||||
@@ -231,6 +250,26 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
|||||||
return doGet(attributeName, AnnotationAttributes[].class);
|
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},
|
* Get the value stored under the specified {@code attributeName},
|
||||||
* ensuring that the value is of the {@code expectedType}.
|
* ensuring that the value is of the {@code expectedType}.
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.core.annotation;
|
package org.springframework.core.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
@@ -32,10 +35,6 @@ import static org.junit.Assert.*;
|
|||||||
*/
|
*/
|
||||||
public class AnnotationAttributesTests {
|
public class AnnotationAttributesTests {
|
||||||
|
|
||||||
enum Color {
|
|
||||||
RED, WHITE, BLUE
|
|
||||||
}
|
|
||||||
|
|
||||||
private final AnnotationAttributes attributes = new AnnotationAttributes();
|
private final AnnotationAttributes attributes = new AnnotationAttributes();
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
@@ -72,7 +71,9 @@ public class AnnotationAttributesTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singleElementToSingleElementArrayConversionSupport() {
|
public void singleElementToSingleElementArrayConversionSupport() throws Exception {
|
||||||
|
Filter filter = FilteredClass.class.getAnnotation(Filter.class);
|
||||||
|
|
||||||
AnnotationAttributes nestedAttributes = new AnnotationAttributes();
|
AnnotationAttributes nestedAttributes = new AnnotationAttributes();
|
||||||
nestedAttributes.put("name", "Dilbert");
|
nestedAttributes.put("name", "Dilbert");
|
||||||
|
|
||||||
@@ -80,15 +81,38 @@ public class AnnotationAttributesTests {
|
|||||||
attributes.put("names", "Dogbert");
|
attributes.put("names", "Dogbert");
|
||||||
attributes.put("classes", Number.class);
|
attributes.put("classes", Number.class);
|
||||||
attributes.put("nestedAttributes", nestedAttributes);
|
attributes.put("nestedAttributes", nestedAttributes);
|
||||||
|
attributes.put("filters", filter);
|
||||||
|
|
||||||
// Get back arrays of single elements
|
// Get back arrays of single elements
|
||||||
assertThat(attributes.getStringArray("names"), equalTo(new String[] { "Dogbert" }));
|
assertThat(attributes.getStringArray("names"), equalTo(new String[] { "Dogbert" }));
|
||||||
assertThat(attributes.getClassArray("classes"), equalTo(new Class[] { Number.class }));
|
assertThat(attributes.getClassArray("classes"), equalTo(new Class[] { Number.class }));
|
||||||
|
|
||||||
AnnotationAttributes[] array = attributes.getAnnotationArray("nestedAttributes");
|
AnnotationAttributes[] array = attributes.getAnnotationArray("nestedAttributes");
|
||||||
assertNotNull(array);
|
assertNotNull(array);
|
||||||
assertTrue(array.getClass().isArray());
|
|
||||||
assertThat(array.length, is(1));
|
assertThat(array.length, is(1));
|
||||||
assertThat(array[0].getString("name"), equalTo("Dilbert"));
|
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
|
@Test
|
||||||
@@ -120,4 +144,17 @@ public class AnnotationAttributesTests {
|
|||||||
attributes.getEnum("color");
|
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