Allow multiple @Filter 'value' args for concision

Prior to this change, to specify two or more annotation include/exclude
filters, one would declare @ComponentScan as follows:

    @ComponentScan(basePackages="example.scannable",
       useDefaultFilters=false,
       includeFilters={
           @Filter(MyStereotype.class),
           @Filter(MyComponent.class)
       })

This was because @Filter's 'value' attribute accepted exactly one
argument.

Now, any given @Filter may accept one or more value arguments, allowing
for more concise @ComponentScan declarations:

    @ComponentScan(basePackages="example.scannable",
       useDefaultFilters=false,
       includeFilters=@Filter({MyStereotype.class, MyComponent.class}))

Supplying multiple arguments in this way assumes that they are the same
type of filter, e.g. ANNOTATION, ASSIGNABLE_TYPE, or CUSTOM. To declare
multiple *different* types of filters, multiple @Filter annotations are
still required, e.g.:

    @ComponentScan(
        includeFilters={
            @Filter(type=ANNOTATION, value=MyStereotype.class),
            @Filter(type=ASSIGNABLE_TYPE, value={Foo.class, Bar.class})
        })

Note that specifying zero arguments, e.g. @Filter({}) is nonsensical; it
will have no effect on component scanning, but does not raise an error.

Issue: SPR-8881
This commit is contained in:
Chris Beams
2011-12-06 12:18:10 +00:00
parent df7bda5637
commit 28ff473091
3 changed files with 84 additions and 23 deletions

View File

@@ -41,7 +41,11 @@ import org.springframework.context.annotation.ComponentScanParserTests.CustomAnn
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.SerializationTestUtils;
import example.scannable.CustomComponent;
import example.scannable.CustomStereotype;
import example.scannable.DefaultNamedComponent;
import example.scannable.FooService;
import example.scannable.MessageBean;
import example.scannable.ScopedProxyTestBean;
import example.scannable_scoped.CustomScopeAnnotationBean;
import example.scannable_scoped.MyScope;
@@ -159,6 +163,24 @@ public class ComponentScanAnnotationIntegrationTests {
assertThat(deserialized.foo(1), equalTo("bar"));
}
@Test
public void withMultipleAnnotationIncludeFilters1() throws IOException, ClassNotFoundException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ComponentScanWithMultipleAnnotationIncludeFilters1.class);
ctx.refresh();
ctx.getBean(DefaultNamedComponent.class); // @CustomStereotype-annotated
ctx.getBean(MessageBean.class); // @CustomComponent-annotated
}
@Test
public void withMultipleAnnotationIncludeFilters2() throws IOException, ClassNotFoundException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ComponentScanWithMultipleAnnotationIncludeFilters2.class);
ctx.refresh();
ctx.getBean(DefaultNamedComponent.class); // @CustomStereotype-annotated
ctx.getBean(MessageBean.class); // @CustomComponent-annotated
}
@Test
public void withBasePackagesAndValueAlias() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -222,7 +244,7 @@ class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver {
class ComponentScanWithCustomTypeFilter {
@Bean
@SuppressWarnings({ "rawtypes", "serial", "unchecked" })
public CustomAutowireConfigurer customAutowireConfigurer() {
public static CustomAutowireConfigurer customAutowireConfigurer() {
CustomAutowireConfigurer cac = new CustomAutowireConfigurer();
cac.setCustomQualifierTypes(new HashSet() {{ add(ComponentScanParserTests.CustomAnnotation.class); }});
return cac;
@@ -240,6 +262,23 @@ class ComponentScanWithCustomTypeFilter {
includeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=ScopedProxyTestBean.class))
class ComponentScanWithScopedProxy { }
@Configuration
@ComponentScan(basePackages="example.scannable",
useDefaultFilters=false,
includeFilters={
@Filter(CustomStereotype.class),
@Filter(CustomComponent.class)
}
)
class ComponentScanWithMultipleAnnotationIncludeFilters1 { }
@Configuration
@ComponentScan(basePackages="example.scannable",
useDefaultFilters=false,
includeFilters=@Filter({CustomStereotype.class, CustomComponent.class})
)
class ComponentScanWithMultipleAnnotationIncludeFilters2 { }
@Configuration
@ComponentScan(
value="example.scannable",