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
For clarity, add @Target({}) to definition of @Filter, constraining it
to complex annotation composition only; i.e. it cannot be placed on
any element, only within annotations, e.g.
@ComponentScan(includeFilters=@Filter(...))
is legal, while
@Filter
public class MyType { }
is not.
Also, widen @Retention from SOURCE to RUNTIME, even though it is not
technically necessary, as all parsing of @Filter annotations happens via
ASM, i.e. at the source level. This change is made primarily for
consistency (@ComponentScan's Retention is RUNTIME) and in avoidance of
potential confusion or surprise on the part of those casually browsing
the code.
This method allows a view to access the combined context path and
servlet mapping path for prefixing URLs without having to specify
the literal part of a servlet mapping such as "/main/*")
explicitly everywhere. For example:
${requestContext.pathToServlet}/css/main.css
Prior to this change, a @Configuration classes that @ComponentScan
themselves would result in a ConflictingBeanDefinitionException.
For example:
package com.foo.config;
@Configuration
@ComponentScan("com.foo");
public class AppConfig {
// ...
}
This resulted in a ConflictingBeanDefinitionException that users have
typically worked around in the following fashion:
package com.foo.config;
@Configuration
@ComponentScan(basePackages="com.foo",
excludeFilters=@Filter(value=ANNOTATION_TYPE, type=Configuration.class);
public class AppConfig {
// ...
}
This is obviously more verbose and cumbersome than would be desirable,
and furthermore potentially too constraining as it prohibits the ability
to include other legitimate @Configuration classes via scanning.
The exception was being thrown because of a logic problem in
ClassPathBeanDefinitionScanner. The bean definition for AppConfig gets
registered once by the user (e.g. when constructing an
AnnotationConfigApplicationContext), then again when performing the
component scan for 'com.foo'. Prior to this change,
ClassPathBeanDefinitionScanner's #isCompatible returned false if the new
bean definition was anything other than an AnnotatedBeanDefinition. The
intention of this check is really to see whether the new bean definition
is a *scanned* bean definition, i.e. the result of a component-scanning
operation. If so, then it becomes safe to assume that the original bean
definition is the one that should be kept, as it is the one explicitly
registered by the user.
Therefore, the fix is as simple as narrowing the instanceof check from
AnnotatedBeanDefinition to its ScannedGenericBeanDefinition subtype.
Note that this commit partially reverts changes introduced in SPR-8307
that explicitly caught ConflictingBeanDefinitionExceptions when
processing recursive @ComponentScan definitions, and rethrew as a
"CircularComponentScanException. With the changes in this commit,
such CBDEs will no longer occur, obviating the need for this check and
for this custom exception type altogether.
Issue: SPR-8808, SPR-8307