Browse Source

Clarified getAllAnnotationAttributes behavior

Issue: SPR-12473
(cherry picked from commit 5ac8680)
pull/701/head
Juergen Hoeller 11 years ago
parent
commit
f44217a0c2
  1. 24
      spring-core/src/main/java/org/springframework/core/type/AnnotatedTypeMetadata.java
  2. 26
      spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java

24
spring-core/src/main/java/org/springframework/core/type/AnnotatedTypeMetadata.java

@ -38,8 +38,8 @@ import org.springframework.util.MultiValueMap;
public interface AnnotatedTypeMetadata { public interface AnnotatedTypeMetadata {
/** /**
* Determine whether the underlying type has an annotation or * Determine whether the underlying element has an annotation or meta-annotation
* meta-annotation of the given type defined. * of the given type defined.
* <p>If this method returns {@code true}, then * <p>If this method returns {@code true}, then
* {@link #getAnnotationAttributes} will return a non-null Map. * {@link #getAnnotationAttributes} will return a non-null Map.
* @param annotationType the annotation type to look for * @param annotationType the annotation type to look for
@ -48,9 +48,9 @@ public interface AnnotatedTypeMetadata {
boolean isAnnotated(String annotationType); boolean isAnnotated(String annotationType);
/** /**
* Retrieve the attributes of the annotation of the given type, * Retrieve the attributes of the annotation of the given type, if any (i.e. if
* if any (i.e. if defined on the underlying class, as direct * defined on the underlying element, as direct annotation or meta-annotation),
* annotation or as meta-annotation). * also taking attribute overrides on composed annotations into account.
* @param annotationType the annotation type to look for * @param annotationType the annotation type to look for
* @return a Map of attributes, with the attribute name as key (e.g. "value") * @return a Map of attributes, with the attribute name as key (e.g. "value")
* and the defined attribute value as Map value. This return value will be * and the defined attribute value as Map value. This return value will be
@ -59,9 +59,9 @@ public interface AnnotatedTypeMetadata {
Map<String, Object> getAnnotationAttributes(String annotationType); Map<String, Object> getAnnotationAttributes(String annotationType);
/** /**
* Retrieve the attributes of the annotation of the given type, * Retrieve the attributes of the annotation of the given type, if any (i.e. if
* if any (i.e. if defined on the underlying class, as direct * defined on the underlying element, as direct annotation or meta-annotation),
* annotation or as meta-annotation). * also taking attribute overrides on composed annotations into account.
* @param annotationType the annotation type to look for * @param annotationType the annotation type to look for
* @param classValuesAsString whether to convert class references to String * @param classValuesAsString whether to convert class references to String
* class names for exposure as values in the returned Map, instead of Class * class names for exposure as values in the returned Map, instead of Class
@ -74,8 +74,8 @@ public interface AnnotatedTypeMetadata {
/** /**
* Retrieve all attributes of all annotations of the given type, if any (i.e. if * Retrieve all attributes of all annotations of the given type, if any (i.e. if
* defined on the underlying type ({@link AnnotationMetadata class} or * defined on the underlying element, as direct annotation or meta-annotation).
* {@link MethodMetadata method}), as direct annotation or as meta-annotation). * Note that this variant does <i>not</i> take attribute overrides into account.
* @param annotationType the annotation type to look for * @param annotationType the annotation type to look for
* @return a MultiMap of attributes, with the attribute name as key (e.g. "value") * @return a MultiMap of attributes, with the attribute name as key (e.g. "value")
* and a list of the defined attribute values as Map value. This return value will * and a list of the defined attribute values as Map value. This return value will
@ -86,8 +86,8 @@ public interface AnnotatedTypeMetadata {
/** /**
* Retrieve all attributes of all annotations of the given type, if any (i.e. if * Retrieve all attributes of all annotations of the given type, if any (i.e. if
* defined on the underlying type ({@link AnnotationMetadata class} or * defined on the underlying element, as direct annotation or meta-annotation).
* {@link MethodMetadata method}), as direct annotation or as meta-annotation). * Note that this variant does <i>not</i> take attribute overrides into account.
* @param annotationType the annotation type to look for * @param annotationType the annotation type to look for
* @param classValuesAsString whether to convert class references to String * @param classValuesAsString whether to convert class references to String
* @return a MultiMap of attributes, with the attribute name as key (e.g. "value") * @return a MultiMap of attributes, with the attribute name as key (e.g. "value")

26
spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java

@ -244,6 +244,7 @@ public class AnnotationMetadataTests {
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata); assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
} }
private void assertMultipleAnnotationsWithIdenticalAttributeNames(AnnotationMetadata metadata) { private void assertMultipleAnnotationsWithIdenticalAttributeNames(AnnotationMetadata metadata) {
AnnotationAttributes attributes1 = (AnnotationAttributes) metadata.getAnnotationAttributes( AnnotationAttributes attributes1 = (AnnotationAttributes) metadata.getAnnotationAttributes(
NamedAnnotation1.class.getName(), false); NamedAnnotation1.class.getName(), false);
@ -292,6 +293,8 @@ public class AnnotationMetadataTests {
assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value")); assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
List<Object> allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value"); List<Object> allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional");
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct")))));
assertTrue(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName())); assertTrue(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()));
@ -332,6 +335,8 @@ public class AnnotationMetadataTests {
assertEquals("direct", metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value")); assertEquals("direct", metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value"); allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta"))))); assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("additional");
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct")))));
} }
{ // perform tests with classValuesAsString = true { // perform tests with classValuesAsString = true
AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes( AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(
@ -407,14 +412,16 @@ public class AnnotationMetadataTests {
NestedAnno[] optionalArray() default { @NestedAnno(value = "optional", anEnum = SomeEnum.DEFAULT, classArray = Void.class) }; NestedAnno[] optionalArray() default { @NestedAnno(value = "optional", anEnum = SomeEnum.DEFAULT, classArray = Void.class) };
} }
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface DirectAnnotation { public @interface DirectAnnotation {
String value(); String value();
String additional() default "direct";
} }
@Target({ ElementType.TYPE }) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface IsAnnotatedAnnotation { public @interface IsAnnotatedAnnotation {
} }
@ -424,9 +431,11 @@ public class AnnotationMetadataTests {
@DirectAnnotation("meta") @DirectAnnotation("meta")
@IsAnnotatedAnnotation @IsAnnotatedAnnotation
public @interface MetaAnnotation { public @interface MetaAnnotation {
String additional() default "meta";
} }
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@MetaAnnotation @MetaAnnotation
public @interface MetaMetaAnnotation { public @interface MetaMetaAnnotation {
@ -446,17 +455,18 @@ public class AnnotationMetadataTests {
}, },
BAR { BAR {
/* Do not delete! This subclassing is intentional. */ /* Do not delete! This subclassing is intentional. */
}; }
} }
@Component("myName") @Component("myName")
@Scope("myScope") @Scope("myScope")
@SpecialAttr(clazz = String.class, state = Thread.State.NEW, nestedAnno = @NestedAnno(value = "na", anEnum = SomeEnum.LABEL1, classArray = { String.class }), nestedAnnoArray = { @SpecialAttr(clazz = String.class, state = Thread.State.NEW,
@NestedAnno, @NestedAnno(value = "na1", anEnum = SomeEnum.LABEL2, classArray = { Number.class }) }) nestedAnno = @NestedAnno(value = "na", anEnum = SomeEnum.LABEL1, classArray = {String.class}),
@SuppressWarnings({ "serial", "unused" }) nestedAnnoArray = {@NestedAnno, @NestedAnno(value = "na1", anEnum = SomeEnum.LABEL2, classArray = {Number.class})})
@SuppressWarnings({"serial", "unused"})
@DirectAnnotation("direct") @DirectAnnotation("direct")
@MetaMetaAnnotation @MetaMetaAnnotation
@EnumSubclasses({ SubclassEnum.FOO, SubclassEnum.BAR }) @EnumSubclasses({SubclassEnum.FOO, SubclassEnum.BAR})
private static class AnnotatedComponent implements Serializable { private static class AnnotatedComponent implements Serializable {
@TestAutowired @TestAutowired

Loading…
Cancel
Save