For the particular use case detailed in SPR-8514, with this change we
now attempt to determine the object type of a FactoryBean through its
generic type parameter if possible.
For (a contrived) example:
@Configuration
public MyConfig {
@Bean
public FactoryBean<String> fb() {
return new StringFactoryBean("foo");
}
}
The implementation will now look at the <String> generic parameter
instead of attempting to instantiate the FactoryBean in order to call
its #getObjectType() method.
This is important in order to avoid the autowiring lifecycle issues
detailed in SPR-8514. For example, prior to this change, the following
code would fail:
@Configuration
public MyConfig {
@Autowired Foo foo;
@Bean
public FactoryBean<String> fb() {
Assert.notNull(foo);
return new StringFactoryBean("foo");
}
}
The reason for this failure is that in order to perform autowiring,
the container must first determine the object type of all configured
FactoryBeans. Clearly a chicken-and-egg issue, now fixed by this
change.
And lest this be thought of as an obscure bug, keep in mind the use case
of our own JPA support: in order to configure and return a
LocalContainerEntityManagerFactoryBean from a @Bean method, one will
need access to a DataSource, etc -- resources that are likely to
be @Autowired across @Configuration classes for modularity purposes.
Note that while the examples above feature methods with return
types dealing directly with the FactoryBean interface, of course
the implementation deals with subclasses/subinterfaces of FactoryBean
equally as well. See ConfigurationWithFactoryBeanAndAutowiringTests
for complete examples.
There is at least a slight risk here, in that the signature of a
FactoryBean-returing @Bean method may advertise a generic type for the
FactoryBean less specific than the actual object returned (or than
advertised by #getObjectType for that matter). This could mean that an
autowiring target may be missed, that we end up with a kind of
autowiring 'false negative' where FactoryBeans are concerned. This is
probably a less common scenario than the need to work with an autowired
field within a FactoryBean-returning @Bean method, and also has a clear
workaround of making the generic return type more specific.
Issue: SPR-8514
Prior to this change, (Context)SingletonBeanFactoryLocator used
BeanFactoryUtils#beanOfType(ListableBeanFactory, Class) to locate the
bean of type BeanFactory.
The more modern approach is to use BeanFactory#getBean(Class), which
removes a dependency on ListableBeanFactory interface while at the same
time opening the implementation up to respecting autowiring exclusions,
primary metadata, etc.
Issue: SPR-8489
Prior to this change, @Autowired injection against an instance of a
subclass having different visibility than its superclass would fail
if the @Autowired method is declared only in the superclass. This is due
to an apparent change in the rules around bridge method generation
between Java 5 and Java 6, and possibly even varying across compiler
vendors.
Now, BridgeMethodResolver is used consistently when detecting
@Autowired, @Inject and @Resource metadata to bypass these bridge
methods if they exist.
Issue: SPR-7900
Prior to this change, AbstractAutowireCapableBeanFactory did not support
a default ParameterNameDiscoverer. This meant that attempting to use
<constructor-arg name=".."> syntax would fail (with a fairly obscure
exception) as that feature depends on a ParameterNameDiscoverer to
introspect the constructor arguments.
This lack of a default was originally intended to avoid a dependency on
ASM, but now that (a) .asm is a built-in module and (b) .beans has a
non-optional compile-time dependency on .asm, there is no reason not to
provide this default.
The net effect is that in a number of locations throughout the
framework, namely in GenericApplicationContext and
AbstractRefreshableApplicationContext, it is no longer necessary to
explicitly call AACBF#setParameterNameDiscoverer. This also means that
using a naked BeanFactory (likely for testing scenarios) is that much
easier.
Issue: SPR-8184
Prior to this change, DirectFieldAccessor would ignore fields shadowed
in subclasses, favoring the last field processed, which happens to be
the most super declaration based on the way ReflectionUtils.doWithFields
works.
Because the locally shadowed field may be of a different type that the
superclass declaration, it is most correct to preserve and work with
the shadowed field.
Issue: SPR-8398
Attempt to access and modify the system environment works on OS X /
Linux but not under Windows. Does not represent any real failure for
production code - the need to modify the system environment is a
testing concern only, and one we can probably live without, considering
the losing battle necessary to make such a hack cross-platform.
Issue: SPR-8245
AbstractEnvironment and subclasses now register a reserved default
profile named literally 'default' such that with no action on the part
of the user, beans defined against the 'default' profile will be
registered - if no other profiles are explicitly activated.
For example, given the following three files a.xml, b.xml and c.xml:
a.xml
-----
<beans> <!-- no 'profile' attribute -->
<bean id="a" class="com.acme.A"/>
</beans>
b.xml
-----
<beans profile="default">
<bean id="b" class="com.acme.B"/>
</beans>
c.xml
-----
<beans profile="custom">
<bean id="c" class="com.acme.C"/>
</beans>
bootstrapping all of the files in a Spring ApplicationContext as
follows will result in beans 'a' and 'b', but not 'c' being registered:
ApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("a.xml");
ctx.load("b.xml");
ctx.load("c.xml");
ctx.refresh();
ctx.containsBean("a"); // true
ctx.containsBean("b"); // true
ctx.containsBean("c"); // false
whereas activating the 'custom' profile will result in beans 'a' and
'c', but not 'b' being registered:
ApplicationContext ctx = new GenericXmlApplicationContext();
ctx.load("a.xml");
ctx.load("b.xml");
ctx.load("c.xml");
ctx.getEnvironment().setActiveProfiles("custom");
ctx.refresh();
ctx.containsBean("a"); // true
ctx.containsBean("b"); // false
ctx.containsBean("c"); // true
that is, once the 'custom' profile is activated, beans defined against
the the reserved default profile are no longer registered. Beans not
defined against any profile ('a') are always registered regardless of
which profiles are active, and of course beans registered
against specific active profiles ('c') are registered.
The reserved default profile is, in practice, just another 'default
profile', as might be added through calling env.setDefaultProfiles() or
via the 'spring.profiles.default' property. The only difference is that
the reserved default is added automatically by AbstractEnvironment
implementations. As such, any call to setDefaultProfiles() or value set
for the 'spring.profiles.default' will override the reserved default
profile. If a user wishes to add their own default profile while
keeping the reserved default profile as well, it will need to be
explicitly redeclared, e.g.:
env.addDefaultProfiles("my-default-profile", "default")
The reserved default profile(s) are determined by the value returned
from AbstractEnvironment#getReservedDefaultProfiles(). This protected
method may be overridden by subclasses in order to customize the
set of reserved default profiles.
Issue: SPR-8203
@Autowired, @Value and other annotations cannot be applied within
Spring Bean(Factory)PostProcessor types, because they themselves
are processed using BeanPostProcessors. Javadoc and reference docs
have been updated to reflect.
Issue: SPR-4935, SPR-8213
A subtle issue existed with the way we relied on isCurrentlyInCreation
to determine whether a @Bean method is being called by the container
or by user code. This worked in most cases, but in the particular
scenario laid out by SPR-8080, this approach was no longer sufficient.
This change introduces a ThreadLocal that contains the factory method
currently being invoked by the container, such that enhanced @Bean
methods can check against it to see if they are being called by the
container or not. If so, that is the cue that the user-defined @Bean
method implementation should be invoked in order to actually create
the bean for the first time. If not, then the cached instance of
the already-created bean should be looked up and returned.
See ConfigurationClassPostConstructAndAutowiringTests for
reproduction cases and more detail.
Issue: SPR-8080
This change is in support of certain polymorphism cases in
@Configuration class inheritance hierarchies. Consider the following
scenario:
@Configuration
public abstract class AbstractConfig {
public abstract Object bean();
}
@Configuration
public class ConcreteConfig {
@Override@Bean
public BeanPostProcessor bean() { ... }
}
ConcreteConfig overrides AbstractConfig's #bean() method with a
covariant return type, in this case returning an object of type
BeanPostProcessor. It is critically important that the container
is able to detect the return type of ConcreteConfig#bean() in order
to instantiate the BPP at the right point in the lifecycle.
Prior to this change, the container could not do this.
AbstractAutowireCapableBeanFactory#getTypeForFactoryMethod called
ReflectionUtils#getAllDeclaredMethods, which returned Method objects
for both the Object and BeanPostProcessor signatures of the #bean()
method. This confused the implementation sufficiently as not to
choose a type for the factory method at all. This means that the
BPP never gets detected as a BPP.
The new method being introduced here, #getUniqueDeclaredMethods, takes
covariant return types into account, and filters out duplicates,
favoring the most specific / narrow return type.
Additionally, it filters out any CGLIB 'rewritten' methods, which
is important in the case of @Configuration classes, which are
enhanced by CGLIB. See the implementation for further details.
The overloading necessary to preserve the new signature as well as
the old causes ambiguities leading to deprecation warnings in some
caller scenarios.
Previously, ExtendedBeanInfo would attempt to process methods named
exactly 'set'. JavaBeans properties must have at least one character
following the 'set' prefix in order to qualify, and this is now
respected by EBI.
Thanks to Rob Winch for the patch fixing this problem.
Issue: SPR-8175
Decorator for instances returned from
Introspector#getBeanInfo(Class<?>) that supports detection and inclusion
of non-void returning setter methods. Fully supports indexed properties
and otherwise faithfully mimics the default
BeanInfo#getPropertyDescriptors() behavior, e.g., PropertyDescriptor
ordering, etc.
This decorator has been integrated with CachedIntrospectionResults
meaning that, in simple terms, the Spring container now supports
injection of setter methods having any return type.
Issue: SPR-8079
Previously, only commas could delimit <beans profile="p1,p2"/>. Now, as
with <bean alias="..."/>, the profile attribute allows for delimiting
by comma, space and/or semicolon.
BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS has been
added as a constant to reflect the fact this set of delimiters is used
in multiple locations throughout the framework.
BDPD.BEAN_NAME_DELIMITERS now refers to the above and has been has been
preserved but deprecated for backward compat (though use outside the
framework is unlikely).
Changes originally based on user comment at
http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/comment-page-1/#comment-184455
Issue: SPR-8033