Browse Source

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
pull/808/head
Sam Brannen 10 years ago
parent
commit
a2f152ce8b
  1. 39
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java
  2. 49
      spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java

39
spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java

@ -205,6 +205,8 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -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> { @@ -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> { @@ -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}.

49
spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java

@ -16,6 +16,9 @@ @@ -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.*; @@ -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 { @@ -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 { @@ -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 { @@ -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 {
}
}

Loading…
Cancel
Save