Reverted change for @Bean methods that declare FactoryBean as their return type: The effects of trying to create the FactoryBean to find out about its implementation type are too far-reaching. It's better to recommend declaring a specific return type in the method signature if you want the container to specifically react to your implementation type.
Issue: SPR-9857
Includes a change for factory methods that declare their return type as FactoryBean: When asked for a specific type match (e.g. LoadTimeWeaverAware), we do check early singleton instances as well (reusing the instances that we create for getObjectType checks). This is necessary in order to make @Bean method introspection as capable as XML bean definition introspection, even in case of the @Bean method using a generic FactoryBean declaration for its return type (instead of the FactoryBean impl class).
Issue: SPR-9857
This change fixes further cases under JDK 6 in which setting a bridged
(e.g. String-returning) read method can conflict with an existing
corresponding bridge write method that accepts an Object parameter.
This appears to be a implementation difference between JDKs 6 and 7,
where the JDK 6 Introspector adds bridge methods and JDK 7 does not.
The solution here is to consistently null-out any existing write method
before setting the read method. We were doing this elsewhere in
ExtendedBeanInfo already, but these two changes make the approach
consistent throuhout.
Issue: SPR-8806
Backport-Commit: 0c0a563a24
- Ensure that ExtendedBeanInfoTests succeeds when building under JDK 7
- Improve handling of read and write method registration where
generic interfaces are involved, per SPR-9453
- Add repro test for SPR-9702, in which EBI fails to register
an indexed read method under certain circumstances
Issue: SPR-9778
Backport-Issue: SPR-9702, SPR-9414, SPR-9453
Backport-Commit: b50bb5071a
Autowired methods might have been skipped on subsequent creation of further bean instances due to the 'skip' flag set to false outside of the synchronized block, with another thread entering the block and setting the flag to true in the meantime.
Issue: SPR-9806
Prior to this change, by-type lookups using DLBF#getBeanNamesForType
required traversal of all bean definitions within the bean factory
in order to inspect their bean class for assignability to the target
type. These operations are comparatively expensive and when there are a
large number of beans registered within the container coupled with a
large number of by-type lookups at runtime, the performance impact can
be severe. The test introduced here demonstrates such a scenario clearly.
This performance problem is likely to manifest in large Spring-based
applications using non-singleton beans, particularly request-scoped
beans that may be created and wired many thousands of times per second.
This commit introduces a simple ConcurrentHashMap-based caching strategy
for by-type lookups; container-wide assignability checks happen only
once on the first by-type lookup and are afterwards cached by type
with the values in the map being an array of all bean names assignable
to that type. This means that at runtime when creating and autowiring
non-singleton beans, the cost of by-type lookups is reduced to that of
ConcurrentHashMap#get.
Issue: SPR-9448
Backport-Issue: SPR-6870
Backport-Commit: 4c7a1c0a54
Commit 3f387eb9cf refactored and
deprecated TransactionAspectUtils, moving its #qualifiedBeanOfType
and related methods into BeanFactoryUtils. This created a package cycle
between beans.factory and beans.factory.annotation due to use of the
beans.factory.annotation.Qualifier annotation in these methods.
This commit breaks the package cycle by introducing
beans.factory.annotation.BeanFactoryAnnotationUtils and moving these
@Qualifier-related methods to it. It is intentionally similar in name
and style to the familiar BeanFactoryUtils class for purposes of
discoverability.
There are no backward-compatibilty concerns associated with this change
as the cycle was introduced, caught and now fixed before a release.
Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: a4b00c732b
TransactionAspectUtils contains a number of methods useful in
retrieving a bean by type+qualifier. These methods are functionally
general-purpose save for the hard coding of PlatformTransactionManager
class literals throughout.
This commit generifies these methods and moves them into
BeanFactoryUtils primarily in anticipation of their use by async method
execution interceptors and aspects when performing lookups for qualified
executor beans e.g. via @Async(qualifier).
The public API of TransactionAspectUtils remains backward compatible;
all methods within have been deprecated, and all calls to those methods
throughout the framework refactored to use the new BeanFactoryUtils
variants instead.
Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: 096693c46f
Prior to this commit, and based on earlier changes supporting SPR-9023,
ConfigurationClassBeanDefinitionReader employed a simplistic strategy
for extracting the 'value' attribute (if any) from @Configuration in
order to determine the bean name for imported and nested configuration
classes. An example case follows:
@Configuration("myConfig")
public class AppConfig { ... }
This approach is too simplistic however, given that it is possible in
'configuration lite' mode to specify a @Component-annotated class with
@Bean methods, e.g.
@Component("myConfig")
public class AppConfig {
@Bean
public Foo foo() { ... }
}
In this case, it's the 'value' attribute of @Component, not
@Configuration, that should be consulted for the bean name. Or indeed if
it were any other stereotype annotation meta-annotated with @Component,
the value attribute should respected.
This kind of sophisticated discovery is exactly what
AnnotationBeanNameGenerator was designed to do, and
ConfigurationClassBeanDefinitionReader now uses it in favor of the
custom approach described above.
To enable this refactoring, nested and imported configuration classes
are no longer registered as GenericBeanDefinition, but rather as
AnnotatedGenericBeanDefinition given that AnnotationBeanNameGenerator
falls back to a generic strategy unless the bean definition in question
is assignable to AnnotatedBeanDefinition.
A new constructor accepting AnnotationMetadata
has been added to AnnotatedGenericBeanDefinition in order to support
the ASM-based approach in use by configuration class processing. Javadoc
has been updated for both AnnotatedGenericBeanDefinition and its now
very similar cousin ScannedGenericBeanDefinition to make clear the
semantics and intention of these two variants.
Issue: SPR-9023
Prior to JDK 7, java.beans.Introspector registered indexed write methods
irrespective of return type, for example either of the following methods
were legal
void setFoo(int i, Foo foo)
Object setFoo(int i, Foo foo)
This was considered a bug and disallowed starting with JDK 7, such that
only the former signature is a candidate.
Supporting non-void returning setter methods is exactly what
ExtendedBeanInfo was designed to do, and prior to this commit, the
implementation of ExtendedBeanInfo assumed this (somewhat surprising)
behavior from the underlying Introspector, and because it worked out of
the box, took no extra steps to recognize and register these methods.
For this reason, non-void returning indexed write methods were not
registered under JDK 7+, causing test failures in ExtendedBeanInfoTests.
Now the implementation is careful to detect these methods without any
assumption about Introspector behavior, such that they are registered in
exactly the same fashion across JDK versions.
Issue: SPR-9014
Prior to this commit, ExtendedBeanInfo would add non-indexed write
methods without consideration for the presence of indexed read/write
methods, which is invalid per the JavaBeans spec and per the behavior
of java.beans.Introspector. That is, a method with the signature
void setFoo(Foo foo)
Should never be registered as a write method if the following method
signature is also present in the class
void setFoo(int i, Foo foo)
In most cases, this oversight caused no problems, but in certain
situations where a bean actually contains such a mismatch of methods,
"type mismatch" errors were thrown when ExtendedBeanInfo attempted the
illegal addition against the underlying property descriptor.
The implementation is now more careful about checking the parameter type
of write methods -- if the property descriptor in question is an
IndexedPropertyDescriptor, i.e. has an indexed write method, then any
non-indexed write method candidate must have a single *array* parameter,
which conforms to the spec and to Introspector behavior.
Issue: SPR-8937
Prior to this commit, and due to idiosyncracies of
java.beans.Introspector, overridden boolean getter methods were not
detected by Spring's ExtendedBeanInfo, which relied on too-strict
Method equality checks when selecting read and write methods.
Now ExtendedBeanInfo uses Spring's ClassUtils#getMostSpecificMethod
against the methods returned from java.beans.Introspector in order
to ensure that subsequent equality checks are reasonable to make.
Issue: SPR-8949
Background
Spring 3.1 introduced the @ComponentScan annotation, which can accept
an optional array of include and/or exclude @Filter annotations, e.g.
@ComponentScan(
basePackages = "com.acme.app",
includeFilters = { @Filter(MyStereotype.class), ... }
)
@Configuration
public class AppConfig { ... }
@ComponentScan and other annotations related to @Configuration class
processing such as @Import, @ImportResource and the @Enable*
annotations are parsed using reflection in certain code paths, e.g.
when registered directly against AnnotationConfigApplicationContext,
and via ASM in other code paths, e.g. when a @Configuration class is
discovered via an XML bean definition or when included via the
@Import annotation.
The ASM-based approach is designed to avoid premature classloading of
user types and is instrumental in providing tooling support (STS, etc).
Prior to this commit, the ASM-based routines for reading annotation
attributes were unable to recurse into nested annotations, such as in
the @Filter example above. Prior to Spring 3.1 this was not a problem,
because prior to @ComponentScan, there were no cases of nested
annotations in the framework.
This limitation manifested itself in cases where users encounter
the ASM-based annotation parsing code paths AND declare
@ComponentScan annotations with explicit nested @Filter annotations.
In these cases, the 'includeFilters' and 'excludeFilters' attributes
are simply empty where they should be populated, causing the framework
to ignore the filter directives and provide incorrect results from
component scanning.
The purpose of this change then, is to introduce the capability on the
ASM side to recurse into nested annotations and annotation arrays. The
challenge in doing so is that the nested annotations themselves cannot
be realized as annotation instances, so must be represented as a
nested Map (or, as described below, the new AnnotationAttributes type).
Furthermore, the reflection-based annotation parsing must also be
updated to treat nested annotations in a similar fashion; even though
the reflection-based approach has no problem accessing nested
annotations (it just works out of the box), for substitutability
against the AnnotationMetadata SPI, both ASM- and reflection-based
implementations should return the same results in any case. Therefore,
the reflection-based StandardAnnotationMetadata has also been updated
with an optional 'nestedAnnotationsAsMap' constructor argument that is
false by default to preserve compatibility in the rare case that
StandardAnnotationMetadata is being used outside the core framework.
Within the framework, all uses of StandardAnnotationMetadata have been
updated to set this new flag to true, meaning that nested annotation
results will be consistent regardless the parsing approach used.
Spr9031Tests corners this bug and demonstrates that nested @Filter
annotations can be parsed and read in both the ASM- and
reflection-based paths.
Major changes
- AnnotationAttributes has been introduced as a concrete
LinkedHashMap<String, Object> to be used anywhere annotation
attributes are accessed, providing error reporting on attribute
lookup and convenient type-safe access to common annotation types
such as String, String[], boolean, int, and nested annotation and
annotation arrays, with the latter two also returned as
AnnotationAttributes instances.
- AnnotationUtils#getAnnotationAttributes methods now return
AnnotationAttributes instances, even though for binary compatibility
the signatures of these methods have been preserved as returning
Map<String, Object>.
- AnnotationAttributes#forMap provides a convenient mechanism for
adapting any Map<String, Object> into an AnnotationAttributes
instance. In the case that the Map is already actually of
type AnnotationAttributes, it is simply casted and returned.
Otherwise, the map is supplied to the AnnotationAttributes(Map)
constructor and wrapped in common collections style.
- The protected MetadataUtils#attributesFor(Metadata, Class) provides
further convenience in the many locations throughout the
.context.annotation packagage that depend on annotation attribute
introspection.
- ASM-based core.type.classreading package reworked
Specifically, AnnotationAttributesReadingVisitor has been enhanced to
support recursive reading of annotations and annotation arrays, for
example in @ComponentScan's nested array of @Filter annotations,
ensuring that nested AnnotationAttributes objects are populated as
described above.
AnnotationAttributesReadingVisitor has also been refactored for
clarity, being broken up into several additional ASM
AnnotationVisitor implementations. Given that all types are
package-private here, these changes represent no risk to binary
compatibility.
- Reflection-based StandardAnnotationMetadata updated
As described above, the 'nestedAnnotationsAsMap' constructor argument
has been added, and all framework-internal uses of this class have
been updated to set this flag to true.
Issue: SPR-7979, SPR-8719, SPR-9031
A number of users reported issues with comparing method identity vs
equivalence when discovering JavaBeans property methods in
ExtendedBeanInfo.
This commit updates the implementation to consistently use '.equals()'
instead of '=='.
Issue: SPR-8079, SPR-8347
This issue originates from a need in Spring Data JPA, wherein a custom
InstantiationAwareBeanPostProcessor may alter the predicted type of
FactoryBean objects, effectively preventing retrieval of those beans via
calls to #getBeansOfType(FactoryBean.class).
The reason for this "masking effect" is that prior to this change, the
implementation of AbstractBeanFactory#isFactoryBean considered only the
"predicted type" returned from #predictBeanType when evaluating
assignability to FactoryBean.class
The implementation of #isFactoryBean now ensures that not only the
predicted bean type is considered, but also the original bean
definition's beanClass (if one is available).
Issue: SPR-8954
Prior to this change, roughly 5% (~300 out of 6000+) of files under the
source tree had CRLF line endings as opposed to the majority which have
LF endings.
This change normalizes these files to LF for consistency going forward.
Command used:
$ git ls-files | xargs file | grep CRLF | cut -d":" -f1 | xargs dos2unix
Issue: SPR-5608
Prior to this change, an assumption was made in
AbstractAutowireCapableBeanFactory that any factory-method would have
zero parameters. This may not be the case in @Bean methods.
We now look for the factory-method by name in a more flexible fashion
that accomodates the possibility of method parameters.
There remains at least one edge cases here where things could still fail,
for example a @Configuration class could have two FactoryBean-returning
methods of the same name, but each with different generic FactoryBean
types and different parameter lists. In this case, the implementation
may infer and return the wrong object type, as it currently returns
the first match for the given factory-method name. The complexity cost
of ensuring that this never happens is not likely worth the trouble
given the very low likelihood of such an arrangement.
Issue: SPR-8762