Clarified getAllAnnotationAttributes behavior
Issue: SPR-12473
This commit is contained in:
parent
58bea23f1d
commit
5ac868036f
|
@ -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")
|
||||||
|
|
|
@ -164,6 +164,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);
|
||||||
|
@ -211,6 +212,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()));
|
||||||
|
|
||||||
|
@ -251,6 +254,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(
|
||||||
|
@ -341,14 +346,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 {
|
||||||
}
|
}
|
||||||
|
@ -358,9 +365,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 {
|
||||||
|
@ -380,17 +389,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
|
||||||
|
@ -406,9 +416,8 @@ public class AnnotationMetadataTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "serial" })
|
@SuppressWarnings("serial")
|
||||||
private static class AnnotatedComponentSubClass extends AnnotatedComponent {
|
private static class AnnotatedComponentSubClass extends AnnotatedComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
|
|
Loading…
Reference in New Issue