Description
Chris Beams opened SPR-8079 and commented
The JavaBeans specification considers property 'write methods' (setters) to be those:
- starting with the string 'set', followed by the capitalized name of the property. (
setFoo(Foo)
,setBar(Bar)
) - accepting a single argument that matches the return type of the 'read method' (getter), if any. (
public Foo getFoo()
,public void setFoo(Foo)
- having a
void
return type.
These requirements are reflected in the implementation of the static java.beans.Introspector#getBeanInfo(Class)
method, which Spring uses to determine what properties are available for injection (see org.springframework.beans.CachedIntrospectionResults
.
The third constraint above poses a problem in certain cases, particularly where a 'builder-style' API is being used -- one that allows for method chaining setters by returning the this
reference of the builder object.
Such builder-style objects are convenient for use when configuring Spring beans programmatically within @Configuration
class @Bean
methods, for example, but if one attempts to use them as <bean/>
definitions within a Spring XML file, the container will throw a NotWritablePropertyException
. This is not because Spring is incapable of calling the non-standard setter style, but rather because Introspector#getBeanInfo()
never notices the non-standard setter in the first place, and any subsequent call to BeanInfo#getPropertyDescriptors()
will fail to report its existence.
For this reason, we will introduce a decorator for the BeanInfo
object returned from Introspector#getBeanInfo()
that takes one more pass against the specified class, looking for any setter methods with non-void return types. Calls to the decorated BeanInfo
type will faithfully report these methods, and Spring's injection facilities will operate normally from there.
It is important that:
- this work play nicely with the existing decoration approach in
GenericTypeAwarePropertyDescriptor
. - non-void returning setter methods are detected even if there is no matching getter method declared. This is a common scenario within framework classes.
While this is a generally useful addition to the framework, it is getting priority now in order to support the work described in #12076 -- specifically #12721, which deals with refactoring Spring's *SessionFactoryBean
types to extend the new @Configuration
-friendly *SessionFactoryBuilder
types. When doing this, the signature of the FactoryBeans' setter methods changes to non-void return types and causes the issue described above. Implementing this new feature will eliminate this problem.
Issue Links:
- Introduce (Annotation)SessionFactoryBuilder types [SPR-8066] #12721 Introduce (Annotation)SessionFactoryBuilder types
- Provide alternatives to using FactoryBean types within @Bean methods [SPR-7418] #12076 Provide alternatives to using FactoryBean types within
@Bean
methods - Overhaul non-void JavaBean write method support [SPR-10029] #14663 Overhaul non-void JavaBean write method support
- ExtendedBeanInfo exception - java.beans.IntrospectionException [SPR-9702] #14336 ExtendedBeanInfo exception - java.beans.IntrospectionException
- ExtendedBeanInfo Passes Empty Property Name to PropertyDescriptor Causing IntrospectionException: bad property name [SPR-8175] #12826 ExtendedBeanInfo Passes Empty Property Name to PropertyDescriptor Causing IntrospectionException: bad property name
- Use ExtendedBeanInfo on an as-needed basis only [SPR-9723] #14357 Use ExtendedBeanInfo on an as-needed basis only
- Overhaul non-void JavaBean write method support [SPR-10029] #14663 Overhaul non-void JavaBean write method support