This change revisits the implementation of ExtendedBeanInfo, simplifying
the overall approach while also ensuring that ExtendedBeanInfo is fully
isolated from the BeanInfo instance it wraps. This includes any existing
PropertyDescriptors in the wrapped BeanInfo - along with being copied
locally into ExtendedBeanInfo, each property descriptor is now also
wrapped with our own new "simple" PropertyDescriptor variants that
bypass the soft/weak reference management that goes on in both
java.beans.PropertyDescriptor and java.beans.IndexedPropertyDescriptor,
maintaining hard references to methods and bean classes instead. This
ensures that changes we make to property descriptors, e.g. adding write
methods, do not cause subtle conflicts during garbage collection (as was
reported and reproduced in SPR-9702).
Eliminating soft/weak reference management means that we must take extra
care to ensure that we do not cause ClassLoader leaks by maintaining
hard references to methods, and therefore transitively to the
ClassLoader in which the bean class was loaded. The forthcoming
SPR-10028 addresses this aspect.
See the updated ExtendedBeanInfo Javadoc for further details.
Issue: SPR-8079, SPR-8175, SPR-8347, SPR-8432, SPR-8491, SPR-8522,
SPR-8806, SPR-8931, SPR-8937, SPR-8949, SPR-9007, SPR-9059,
SPR-9414, SPR-9453, SPR-9542, SPR-9584, SPR-9677, SPR-9702,
SPR-9723, SPR-9943, SPR-9978, SPR-10028, SPR-10029
- Increase max heap size in gradle wrapper.
- Use MockProperties implementation to protect against security
exceptions.
- Replace windows CRLF with LF in various tests.
- Increase Thread.sleep times to account for lack of precision on
Windows.
Issue: SPR-9717
This commit refactors the BeanInfoFactory so that:
- supports() and getBeanInfo() are folded into one, so that getBeanInfo()
returns null if a given class is not supported.
- CachedIntrospectionResults now uses SpringFactoriesLoader
Prior to this change, CachedIntrospectionResults delegated to
ExtendedBeanInfo by default in order to inspect JavaBean
PropertyDescriptor information for bean classes.
Originally introduced with SPR-8079, ExtendedBeanInfo was designed to
go beyond the capabilities of the default JavaBeans Introspector in
order to support non-void returning setter methods, principally to
support use of builder-style APIs within Spring XML. This is a complex
affair, and the non-trivial logic in ExtendedBeanInfo has led to various
bugs including regressions for bean classes that do not declare
non-void returning setters.
This commit takes advantage of the new BeanInfoFactory mechanism
introduced in SPR-9677 to take ExtendedBeanInfo out of the default code
path for CachedIntrospectionResults. Now, the new
ExtendedBeanInfoFactory class will be detected and instantiated (per its
entry in the META-INF/spring.beanInfoFactories properties file shipped
with the spring-beans jar). ExtendedBeanInfoFactory#supports is invoked
for all bean classes in order to determine whether they are candidates
for ExtendedBeanInfo introspection, i.e. whether they declare non-void
returning setter methods.
If a class does not declare any such non-standard setter methods (the
99% case), then CachedIntrospectionResults will fall back to the
default JavaBeans Introspector. While efforts have been made to fix any
bugs with ExtendedBeanInfo, this change means that EBI will not pose
any future risk for bean classes that do not declare non-standard
setter methods, and also means greater efficiency in general.
Issue: SPR-9723, SPR-9677, SPR-8079
- 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-9702, SPR-9414, SPR-9453
Before this commit, the CachedIntrospectionResults was hard-coded to
create ExtendedBeanInfos for bean classes. The ExtendedBeanInfo support
the JavaBeans property contract only.
This commit introduces the BeanInfoFactory, a strategy for creating
BeanInfos. Through this strategy, it is possible to support
beans that do not necessarily implement the JavaBeans contract (i.e.
have a different getter or setter style).
BeanInfoFactories are are instantiated by the
CachedIntrospectionResults, which looks for
'META-INF/spring.beanInfoFactories' files on the class path. These files
contain one or more BeanInfoFactory class names. When a BeanInfo is to
be created, the CachedIntrospectionResults will iterate through the
factories, asking it to create a BeanInfo for the given bean class. If
none of the factories support it, an ExtendedBeanInfo is created as a
default.
This commit also contains a change to Property, allowing BeanWrapperImpl
to specify the property name at construction time (as opposed to using
Property#resolveName(), which supports the JavaBeans contract only).
Issue: SPR-9677
CGLIB 3 has been released in order to depend on ASM 4, which Spring now
depends on internally (see previous commit).
This commit eliminates spring-beans' optional dependency on cglib-nodep
v2.2 and instead repackages net.sf.cglib => org.springframework.cglib
much in the same way we have historically done with ASM.
This change is beneficial to users in several ways:
- Eliminates the need to manually add CGLIB to the application
classpath; especially important for the growing number of
@Configuration class users. Java-based configuration functionality,
along with proxy-target-class and method injection features now
work 'out of the box' in Spring 3.2.
- Eliminates the possibility of conflicts with other libraries that
may dependend on differing versions of CGLIB, e.g. Hibernate
3.3.1.ga and its dependency on CGLIB 2.1.3 would easily cause a
conflict if the application were depending on CGLIB 3 for
Spring-related purposes.
- Picks up CGLIB 3's changes to support ASM 4, meaning that CGLIB is
that much less likely to work well in a Java 7 environment due to
ASM 4's support for transforming classes with invokedynamic
bytecode instructions.
On CGLIB and ASM:
CGLIB's own dependency on ASM is also transformed along the way to
depend on Spring's repackaged org.springframework.asm, primarily to
eliminate unnecessary duplication of ASM classfiles in spring-core and
in the process save around 100K in the final spring-core JAR file size.
It is coincidental that spring-core and CGLIB currently depend on the
exact same version of ASM (4.0), but it is also unlikely to change any
time soon. If this change does occur and versions of ASM drift, then
the size optimization mentioned above will have to be abandoned. This
would have no compatibility impact, however, so this is a reasonable
solution now and for the forseeable future.
On a mysterious NoClassDefFoundError:
During the upgrade to CGLIB 3.0, Spring test cases began failing due to
NoClassDefFoundErrors being thrown from CGLIB's DebuggingClassWriter
regarding its use of asm-util's TraceClassVisitor type. previous
versions of cglib-nodep, particularly 2.2, did not cause this behavior,
even though cglib-nodep has never actually repackaged and bundled
asm-util classes. The reason for these NoClassDefFoundErrors occurring
now is still not fully understood, but appears to be due to subtle JVM
bytecode preverification rules. The hypothesis is that due to minor
changes in DebuggingClassWriter such as additional casts, access to
instance variables declared in the superclass, and indeed a change in
the superclass hierarchy, preverification may be kicking in on the
toByteArray method body, at which point the reference to the missing
TraceClassVisitor type is noticed and the NCDFE is thrown. For this
reason, a dummy implementation of TraceClassVisitor has been added to
spring-core in the org.springframework.asm.util package. This class
simply ensures that Spring's own tests never result in the NCDFE
described above, and more importantly that Spring's users never
encounter the same.
Other changes include:
- rename package-private Cglib2AopProxy => CglibAopProxy
- eliminate all 'cglibAvailable' checks, warnings and errors
- eliminate all 'CGLIB2' language in favor of 'CGLIB'
- eliminate all mention in reference and java docs of needing to add
cglib(-nodep) to one's application classpath
Issue: SPR-9669
Currently, if a factory method is parameterized and the corresponding
variable types are declared on the method itself instead of on the
enclosing class or interface, Spring always predicts the return type to
be Object, even if the return type can be explicitly inferred from the
method signature and supplied arguments (which are available in the bean
definition).
This commit introduces a new resolveParameterizedReturnType() method in
GenericTypeResolver that attempts to infer the concrete type for the
generic return type of a given parameterized method, falling back to the
standard return type if necessary. Furthermore,
AbstractAutowireCapableBeanFactory now delegates to
resolveParameterizedReturnType() when predicting the return type for
factory methods.
resolveParameterizedReturnType() is capable of inferring the concrete
type for return type T for method signatures similar to the following.
Such methods may potentially be static. Also, the formal argument list
for such methods is not limited to a single argument.
- public <T> T foo(Class<T> clazz)
- public <T> T foo(Object obj, Class<T> clazz)
- public <V, T> T foo(V obj, Class<T> clazz)
- public <T> T foo(T obj)
Issue: SPR-9493
The failure of the conversion service is not fatal, but the check that
was in there (line 248) was inadequate to detect the cases that could
already be handled by the default property editors. This code path
was also not tested anywhere in spring-beans tests until now.
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-6870
Previously, the <value> subelement of a map <entry> allowed one to
specify the type of a specific map entry value. This patch allows a
value-type attribute as well, such that instead of the following
syntax
<entry key="x-message-ttl">
<value type="java.lang.Long">100</value>
</entry>
<entry key="x-ha-policy" value="all" />
one can now use the more concise form
<entry key="x-message-ttl" value="100" value-type="java.lang.Long"/>
<entry key="x-ha-policy" value="all"/>
The new value-type attribute may be used at the <map> level as well,
indicating that all elements are of the same type.
Appropriate tests have been added exercising value-type at the <map> and
<entry> levels.
Issue: SPR-9249
Each of these tests began failing during the Gradle build porting
process. None seem severe, many are likely due to classpath issues.
In the case of TestNG support, this needs to be added to the Gradle
build in order to execute these tests. See SPR-8116.txt
This renaming more intuitively expresses the relationship between
subprojects and the JAR artifacts they produce.
Tracking history across these renames is possible, but it requires
use of the --follow flag to `git log`, for example
$ git log spring-aop/src/main/java/org/springframework/aop/Advisor.java
will show history up until the renaming event, where
$ git log --follow spring-aop/src/main/java/org/springframework/aop/Advisor.java
will show history for all changes to the file, before and after the
renaming.
See http://chrisbeams.com/git-diff-across-renamed-directories