Favor local @ComponentScan annotations over meta-annotations
Work performed in conjunction with gh-30941 resulted in a regression. Specifically, prior to Spring Framework 6.1 a locally declared @ComponentScan annotation took precedence over @ComponentScan meta-annotations, which allowed "local" configuration to override "meta-present" configuration. This commit modifies the @ComponentScan search algorithm so that locally declared @ComponentScan annotations are once again favored over @ComponentScan meta-annotations (and, indirectly, composed annotations). See gh-30941 Closes gh-31704
This commit is contained in:
@@ -137,6 +137,50 @@ class ComponentScanAnnotationIntegrationTests {
|
||||
assertContextContainsBean(ctx, "barComponent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void localAnnotationOverridesMultipleMetaAnnotations() { // gh-31704
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(LocalAnnotationOverridesMultipleMetaAnnotationsConfig.class);
|
||||
|
||||
assertContextContainsBean(ctx, "componentScanAnnotationIntegrationTests.LocalAnnotationOverridesMultipleMetaAnnotationsConfig");
|
||||
assertContextContainsBean(ctx, "barComponent");
|
||||
|
||||
assertContextDoesNotContainBean(ctx, "simpleComponent");
|
||||
assertContextDoesNotContainBean(ctx, "configurableComponent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void localAnnotationOverridesMultipleComposedAnnotations() { // gh-31704
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(LocalAnnotationOverridesMultipleComposedAnnotationsConfig.class);
|
||||
|
||||
assertContextContainsBean(ctx, "componentScanAnnotationIntegrationTests.LocalAnnotationOverridesMultipleComposedAnnotationsConfig");
|
||||
assertContextContainsBean(ctx, "barComponent");
|
||||
|
||||
assertContextDoesNotContainBean(ctx, "simpleComponent");
|
||||
assertContextDoesNotContainBean(ctx, "configurableComponent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void localRepeatedAnnotationsOverrideComposedAnnotations() { // gh-31704
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(LocalRepeatedAnnotationsOverrideComposedAnnotationsConfig.class);
|
||||
|
||||
assertContextContainsBean(ctx, "componentScanAnnotationIntegrationTests.LocalRepeatedAnnotationsOverrideComposedAnnotationsConfig");
|
||||
assertContextContainsBean(ctx, "barComponent");
|
||||
assertContextContainsBean(ctx, "configurableComponent");
|
||||
|
||||
assertContextDoesNotContainBean(ctx, "simpleComponent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void localRepeatedAnnotationsInContainerOverrideComposedAnnotations() { // gh-31704
|
||||
ApplicationContext ctx = new AnnotationConfigApplicationContext(LocalRepeatedAnnotationsInContainerOverrideComposedAnnotationsConfig.class);
|
||||
|
||||
assertContextContainsBean(ctx, "componentScanAnnotationIntegrationTests.LocalRepeatedAnnotationsInContainerOverrideComposedAnnotationsConfig");
|
||||
assertContextContainsBean(ctx, "barComponent");
|
||||
assertContextContainsBean(ctx, "configurableComponent");
|
||||
|
||||
assertContextDoesNotContainBean(ctx, "simpleComponent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void viaBeanRegistration() {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
@@ -299,6 +343,20 @@ class ComponentScanAnnotationIntegrationTests {
|
||||
String[] basePackages() default {};
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("org.springframework.context.annotation.componentscan.simple")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface MetaConfiguration1 {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("example.scannable_implicitbasepackage")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface MetaConfiguration2 {
|
||||
}
|
||||
|
||||
@ComposedConfiguration(basePackages = "org.springframework.context.annotation.componentscan.simple")
|
||||
static class ComposedAnnotationConfig {
|
||||
}
|
||||
@@ -308,6 +366,32 @@ class ComponentScanAnnotationIntegrationTests {
|
||||
static class MultipleComposedAnnotationsConfig {
|
||||
}
|
||||
|
||||
@MetaConfiguration1
|
||||
@MetaConfiguration2
|
||||
@ComponentScan("example.scannable.sub")
|
||||
static class LocalAnnotationOverridesMultipleMetaAnnotationsConfig {
|
||||
}
|
||||
|
||||
@ComposedConfiguration(basePackages = "org.springframework.context.annotation.componentscan.simple")
|
||||
@ComposedConfiguration2(basePackages = "example.scannable_implicitbasepackage")
|
||||
@ComponentScan("example.scannable.sub")
|
||||
static class LocalAnnotationOverridesMultipleComposedAnnotationsConfig {
|
||||
}
|
||||
|
||||
@ComposedConfiguration(basePackages = "org.springframework.context.annotation.componentscan.simple")
|
||||
@ComponentScan("example.scannable_implicitbasepackage")
|
||||
@ComponentScan("example.scannable.sub")
|
||||
static class LocalRepeatedAnnotationsOverrideComposedAnnotationsConfig {
|
||||
}
|
||||
|
||||
@ComposedConfiguration(basePackages = "org.springframework.context.annotation.componentscan.simple")
|
||||
@ComponentScans({
|
||||
@ComponentScan("example.scannable_implicitbasepackage"),
|
||||
@ComponentScan("example.scannable.sub")
|
||||
})
|
||||
static class LocalRepeatedAnnotationsInContainerOverrideComposedAnnotationsConfig {
|
||||
}
|
||||
|
||||
|
||||
static class AwareTypeFilter implements TypeFilter, EnvironmentAware,
|
||||
ResourceLoaderAware, BeanClassLoaderAware, BeanFactoryAware {
|
||||
|
||||
Reference in New Issue
Block a user