Ensure direct @PropertySource annotations override meta-annotations
Prior to this commit, there was an issue with the semantics of property source overrides. Specifically, a @PropertySource annotation present as a meta-annotation on a @Configuration class was registered with higher precedence than a @PropertySource annotation declared closer to (or directly on) the @Configuration class. Consequently, there was no way for a "local" @PropertySource annotation to override properties registered via @PropertySource as a meta-annotation. This commit addresses this issue by introducing a new overloaded getMergedRepeatableAnnotationAttributes() variant in AnnotatedTypeMetadata that allows the caller to supply a sortByReversedMetaDistance flag. When set to `true`, the annotation search results will be sorted in reversed order based on each annotation's meta distance, which effectively orders meta-annotations before annotations that are declared directly on the underlying element. ConfigurationClassParser and AnnotationConfigUtils have been updated to use this new repeatable annotation search method for @PropertySource. Closes gh-31074
This commit is contained in:
@@ -263,6 +263,20 @@ class AnnotationMetadataTests {
|
||||
assertRepeatableAnnotations(metadata);
|
||||
}
|
||||
|
||||
@Test // gh-31074
|
||||
void multipleComposedRepeatableAnnotationsSortedByReversedMetaDistanceUsingStandardAnnotationMetadata() {
|
||||
AnnotationMetadata metadata = AnnotationMetadata.introspect(MultipleComposedRepeatableAnnotationsClass.class);
|
||||
assertRepeatableAnnotationsSortedByReversedMetaDistance(metadata);
|
||||
}
|
||||
|
||||
@Test // gh-31074
|
||||
void multipleComposedRepeatableAnnotationsSortedByReversedMetaDistanceUsingSimpleAnnotationMetadata() throws Exception {
|
||||
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(MultipleComposedRepeatableAnnotationsClass.class.getName());
|
||||
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
|
||||
assertRepeatableAnnotationsSortedByReversedMetaDistance(metadata);
|
||||
}
|
||||
|
||||
@Test // gh-31041
|
||||
void multipleRepeatableAnnotationsInContainersUsingStandardAnnotationMetadata() {
|
||||
AnnotationMetadata metadata = AnnotationMetadata.introspect(MultipleRepeatableAnnotationsInContainersClass.class);
|
||||
@@ -318,6 +332,18 @@ class AnnotationMetadataTests {
|
||||
.containsExactly("A", "B", "C", "D");
|
||||
}
|
||||
|
||||
private static void assertRepeatableAnnotationsSortedByReversedMetaDistance(AnnotationMetadata metadata) {
|
||||
// Note: although the real @ComponentScan annotation is not looked up using
|
||||
// "sortByReversedMetaDistance" semantics, we can still use @TestComponentScan
|
||||
// to verify the expected behavior.
|
||||
Set<AnnotationAttributes> attributesSet =
|
||||
metadata.getMergedRepeatableAnnotationAttributes(TestComponentScan.class, TestComponentScans.class, false, true);
|
||||
assertThat(attributesSet.stream().map(attributes -> attributes.getStringArray("value")).flatMap(Arrays::stream))
|
||||
.containsExactly("C", "D", "A", "B");
|
||||
assertThat(attributesSet.stream().map(attributes -> attributes.getStringArray("basePackages")).flatMap(Arrays::stream))
|
||||
.containsExactly("C", "D", "A", "B");
|
||||
}
|
||||
|
||||
private static void assertRepeatableAnnotations(Set<TestComponentScan> annotations) {
|
||||
assertThat(annotations.stream().map(TestComponentScan::value).flatMap(Arrays::stream))
|
||||
.containsExactly("A", "B", "C", "D");
|
||||
|
||||
Reference in New Issue
Block a user