Compare commits

...

248 Commits

Author SHA1 Message Date
Spring Buildmaster f440f92719 Release version 3.2.6.RELEASE 2013-12-12 01:06:43 -08:00
Phillip Webb c2d98de6a6 Update changelog 2013-12-12 00:28:01 -08:00
Juergen Hoeller bf31f7178d Polishing
(cherry picked from commit a3a4344)
2013-12-11 23:58:16 +01:00
Juergen Hoeller 249d8379ae Polishing
(cherry picked from commit aa6e6c1)
2013-12-11 23:12:34 +01:00
Juergen Hoeller bfcfbe41a1 Made BeanUtils.copyProperties defensive about property type mismatches
Issue: SPR-11209
(cherry picked from commit bc5affa)
2013-12-11 23:12:33 +01:00
Phillip Webb f17ae5a7a8 Replace references to VMware with Pivotal
Replace references to VMware in license, notices and maven generation
with Pivotal, Inc.

Issue: SPR-11073
(cherry picked from commit b085ec9)
2013-12-11 14:10:28 -08:00
Juergen Hoeller 779d5716e5 Moved RequiredAnnotationBeanPostProcessorTests to correct package beans.factory.annotation 2013-12-11 18:45:23 +01:00
Juergen Hoeller 2a6c642408 Added tests for custom qualifier annotations on scoped @Bean methods
Issue: SPR-11116
(cherry picked from commit c5d7977)
2013-12-11 18:44:13 +01:00
Juergen Hoeller 126116e759 DispatcherPortlet never uses a resource forward on Liferay
Issue: SPR-10791
(cherry picked from commit 9c157ea)
2013-12-11 18:43:58 +01:00
Juergen Hoeller 1ea218cee2 MBean registration happens in a fully synchronized fashion for consistent results
Issue: SPR-11002
(cherry picked from commit 8d6d6be)
2013-12-11 18:43:33 +01:00
Juergen Hoeller ec78165072 Component scanning ignores attributes and meta-annotations on non-public annotations
Issue: SPR-11091
(cherry picked from commit 161819f)
2013-12-11 18:42:48 +01:00
Juergen Hoeller e4fb72f6e3 Fixed CGLIB class validation to not raising warning for static final methods
Issue: SPR-11107
(cherry picked from commit 9fbb57c)
2013-12-11 17:46:23 +01:00
Juergen Hoeller 6fb10981b0 Fixed extractOutputParameters to properly extract ResultSet in all cases
Issue: SPR-11076
(cherry picked from commit 3ff3805)
2013-12-11 17:45:51 +01:00
Juergen Hoeller d48b9b1ef7 Actually accept String expressions for "prefetch" and "receive-timeout" in jms namespace
Issue: SPR-10986
(cherry picked from commit ccafccb)
2013-12-11 17:45:15 +01:00
Juergen Hoeller c3907cdae5 Added 546 to Sybase data integrity violation codes
Issue: SPR-11097
(cherry picked from commit 2d2226b)
2013-12-11 17:44:47 +01:00
Juergen Hoeller 7f895222e1 Revised exclusion of java.lang.Class properties
Issue: SPR-11098
(cherry picked from commit 62ea627)
2013-12-11 17:44:16 +01:00
Phillip Webb 22ece06b39 Add a 'bill of materials' project for Maven users
Add 'spring-framework-bom' meta-project that contains the other projects
in a dependencyManagement section.

Issue: SPR-11138
2013-12-11 10:01:23 -06:00
Sam Brannen b20b7415d8 Make methods of TestContext non-final
This commit makes several methods of TestContext non-final in order to
allow TestContext to be mocked — for example with Mockito.

Note, however, that TestContext has been converted to an interface in
Spring Framework 4.0.

Issue: SPR-11144
2013-12-11 01:23:03 +01:00
Sam Brannen 38ad39f467 Do not repopulate RequestContextHolder in ServTEL
This commit fixes a bug introduced in the last commit.

ServletTestExecutionListener (STEL) now tracks whether it has already
populated the RequestContextHolder.

Issue: SPR-11144

Backport-Commit: 800018a817
2013-12-11 01:02:05 +01:00
Sam Brannen 6ded287144 Honor presence of @WebAppConfiguration in ServTEL
The previous commit for issue SPR-11144 revealed a bug in
ServletTestExecutionListener (STEL). Specifically, STEL acted on the
fact that the ApplicationContext for a given TestContext was an
instance of WebApplicationContext. This behavior could potentially
break test code from previous releases of the Spring Framework that
relied on a custom setup of the RequestAttributes in the
RequestContextHolder with a custom WebApplicationContext ContextLoader.

This commit addresses this issue by ensuring that STEL only comes into
play if the test class is annotated with @WebAppConfiguration (for
prepareTestInstance() and beforeTestMethod()) or if the TestContext
attribute named RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE is set to
Boolean.TRUE (for afterTestMethod()).

Issue: SPR-11144

Backport-Commit: 099b10d23b
2013-12-10 23:54:05 +01:00
Juergen Hoeller 6e275b7663 Polishing 2013-12-10 22:48:42 +01:00
Juergen Hoeller 882726377f Fixed ExtendedBeanInfo and its tests to accept JDK 8 b117+ introspection results
Specifically, read and write methods are allowed to express property types with superclass/subclass relationships in both directions now.

Issue: SPR-11139
(cherry picked from commit cb624e2)
2013-12-10 22:48:35 +01:00
Juergen Hoeller 2e15f94cf2 Optimized use of JDBC 3.0 ParameterMetaData.getParameterType, caching information about drivers which do not support that feature
Issue: SPR-11100
(cherry picked from commit 4c8a789)
2013-12-10 13:14:13 +01:00
Juergen Hoeller d0fc38ec76 Fixed inner bean name determination for multi-level nesting scenario, calculating a unique bean name as early as possible now (and for any kind of bean scope)
Our per-bean caching in AutowiredAnnotationBeanPostProcessor and co relies on unique bean names, so this change fixes potential cache mismatch problems occuring there.

Issue: SPR-11131
(cherry picked from commit 242ecdc)
2013-12-10 13:12:41 +01:00
Juergen Hoeller 8e52e650f4 Fixed type resolution for uninitialized factory-method declaration
Issue: SPR-11112
(cherry picked from commit 5dcd287)
2013-12-10 13:12:32 +01:00
Juergen Hoeller 71650c0a44 Fixed evaluation of "!" operator in case of multiple profile expressions
Issue: SPR-11093
(cherry picked from commit 6078c27)
2013-12-10 12:16:22 +01:00
Sam Brannen c89985c1db Ensure ServTEL doesn't reset ReqAttrs by accident
Prior to this commit, the ServletTestExecutionListener did not
overwrite RequestAttributes in the RequestContextHolder if the
ApplicationContext associated with the given TestContext was not a
WebApplicationContext; however, the ServletTestExecutionListener would
clear the RequestAttributes after every test method execution,
regardless of whether the context was a WebApplicationContext or not.
This behavior breaks backwards compatibility with integration tests
that managed the RequestAttributes in RequestContextHolder themselves.

This commit addresses this issue by introducing a TestContext attribute
named RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE in
ServletTestExecutionListener. This attribute is used internally within
ServletTestExecutionListener to ensure that the RequestContextHolder is
only cleared (i.e., reset) if the ServletTestExecutionListener actually
populated the RequestContextHolder.

Issue: SPR-11144

Backport-Commit: a3b022aa48
2013-12-09 15:43:32 +01:00
Juergen Hoeller d4b0751626 Polishing 2013-12-09 00:12:03 +01:00
Juergen Hoeller 6bed18004e Fixed detection of qualifier annotations on scoped-proxy factory methods
Issue: SPR-11116
2013-12-09 00:11:41 +01:00
Phillip Webb dfed8afb26 Only consider "is" methods with boolean returns
Fix regression introduced in b25e91a5 where ReflectivePropertyAccessor
does not consider the return type for "is" getters.

Issue: SPR-11142
(cherry picked from commit 85b0bfff)
2013-12-03 12:06:26 -08:00
Rossen Stoyanchev 236981aaa9 Support multi-value x-forwarded-host header
Issue: SPR-11140
2013-12-03 09:55:47 -05:00
Juergen Hoeller 6ce2eb9622 EhCacheFactoryBean calls CacheManager.addCache before setStatisticsEnabled
Issue: SPR-11080
Issue: SPR-11092
2013-12-03 01:30:22 +01:00
Juergen Hoeller 6224ddd0cb Polishing (including removal of javadoc imports that show as package cycles in IntelliJ)
(cherry picked from commit 2a52dec)
2013-12-03 01:28:45 +01:00
Juergen Hoeller 25c7e3645b Polishing (including removal of javadoc imports that show as package cycles in IntelliJ)
(cherry picked from commit 2a52dec)
2013-12-03 00:00:31 +01:00
Juergen Hoeller 9c9cc7fcb4 Use AnnotationTransactionAttributeSource class name to avoid hard dependency on transaction.annotation package
(cherry picked from commit 4133272)
2013-12-02 23:59:36 +01:00
Juergen Hoeller 5639eb66b6 Polishing 2013-12-02 16:32:02 +01:00
Juergen Hoeller 1dc79f7f9c Synchronized cache creation on CacheManager
Issue: SPR-11132
(cherry picked from commit de890fd)
2013-12-02 16:10:44 +01:00
Juergen Hoeller c1b772cd9c Optimized ImportAware processing to avoid re-reading class files
(cherry picked from commit 519f78c)
2013-12-02 16:10:34 +01:00
Phillip Webb 73a8a1b966 Detect cache hit with multiple @Cachables
Fix CacheAspectSupport to consider a cache hit from any of the multiple
@Cachables that may have been specified using the @Caching annotation.

Prior to this commit the following scenario would never produce a hit:

    @Caching(cacheable = {
            @Cacheable(value = "c1", unless = "#result.size() < 4"),
            @Cacheable(value = "c2", unless = "#result.size() > 3")
     })

Issue: SPR-11124
2013-11-26 17:13:50 -08:00
Spring Buildmaster 0f26a7795d Next development version 2013-11-06 11:51:48 -08:00
Phillip Webb 47ae15b7ee Update changelog 2013-11-06 11:15:37 -08:00
Juergen Hoeller df7b661702 Added test for placeholder in alias definition
Issue: SPR-11018
(cherry picked from commit e9a24da)
2013-11-06 00:36:56 +01:00
Juergen Hoeller fe46a01a57 JndiObjectFactoryBean converts a "defaultObject" value to the expected type if necessary
Issue: SPR-11039
(cherry picked from commit 0aedd81)
2013-11-06 00:36:48 +01:00
Rossen Stoyanchev 2f13e05b4f Return 415 on bad request body content-type
Issue: SPR-10982
2013-11-05 15:38:04 -05:00
Rossen Stoyanchev 4b38dc8972 Fix exception mock request builder
Issue: SPR-11043
2013-11-05 11:00:02 -05:00
Rossen Stoyanchev 7387cb990e Disable ext entities in SourceHttpMessageConverter
This change disables the processing of external entities in
SourceHttpMessageConverter by default and provides an option to enable
it if required.
2013-11-05 09:49:13 -05:00
Juergen Hoeller 863570abb7 Perform setParent's Environment merging for ClassPathXmlApplicationContext etc constructors with parent argument as well
Issue: SPR-11068
(cherry picked from commit c5fcf19)
2013-11-05 14:18:14 +01:00
Juergen Hoeller 70907fd326 Only retrieve the FlashMapManager if a non-empty output FlashMap has been found
Issue: SPR-10937
(cherry picked from commit 4ac6801)
2013-11-05 14:18:08 +01:00
Juergen Hoeller 494cc22bcd Polishing (along with SPR-10992) 2013-11-05 00:52:49 +01:00
Juergen Hoeller 044d68b336 @Bean method metadata is always being picked from the most concrete subclass
As a side effect, @Bean overrides and overloads work with 'allowBeanDefinitionOverriding'=false as well now.

Issue: SPR-10992
2013-11-05 00:52:28 +01:00
Juergen Hoeller a95eb1d044 Polishing (selectively backported from recent 4.0 commits) 2013-11-04 16:22:46 +01:00
Juergen Hoeller b00c31a620 Use non-lenient constructor resolution mode for @Bean methods
Since @Bean methods are never used with externally specified constructor argument values but rather just with autowiring, the non-lenient constructor resolution mode is appropriate in case of an overloaded @Bean method, not performing any type difference weight checks. This change includes a refinement of Spring's existing non-lenient constructor resolution (which needs to be explicitly turned on and is therefore not well tested), narrowing the conditions for the ambiguity check (only in case of the same number of arguments and not for overridden methods).

Issue: SPR-10988
(cherry picked from commit b093b84)
2013-11-04 16:11:04 +01:00
Juergen Hoeller 23cc44f16e Javadoc polishing 2013-11-01 23:04:07 +01:00
Juergen Hoeller e1a065906e Avoid unnecessary char[] allocation in NamedParameterUtils
Issue: SPR-11042
(cherry picked from commit 1dc7ff8)
2013-11-01 23:02:56 +01:00
Juergen Hoeller 3bfddc501d Backported further GenericTypeResolver tests
Issue: SPR-11052
2013-10-31 17:39:39 +01:00
Rossen Stoyanchev f9081bedb4 Add timeout async request handling to OSIV components
This change adds async web request timeout handling to OSIV filters
and interceptors to ensure the session or entity manager is released.

Issue: SPR-10874
2013-10-30 23:12:09 -04:00
Juergen Hoeller 1ac8e48ebf Polishing (backported from several master changes) 2013-10-30 22:47:16 +01:00
Rossen Stoyanchev d4f4225e53 Avoid filling up AntPathMatcher cache
This change avoid use of AntPathMatcher to extract URI template
variables when the lookup path is used as the best matching pattern.

Issue: SPR-10803
(cherry picked from commit a7af950)
2013-10-30 22:18:11 +01:00
Juergen Hoeller c53184cb6d Refined logging for advisors which are currently in creation
Issue: SPR-10430
(cherry picked from commit 62157fe)
2013-10-30 22:12:24 +01:00
Phillip Webb f9f106936c Relax JavaBean rules for SpEL property access
Relax the method search algorithm used by `ReflectivePropertyAccessor`
to include methods of the form `getXY()` for properties of the form
`xy`.

Although the JavaBean specification indicates that a property `xy`
should use the accessors `getxY()` and `setxY()`, in practice many
developers choose to have an uppercase first character. The
`ReflectivePropertyAccessor` will now consider these style methods if
the traditional conventions fail to find a match.

Issue: SPR-10716
(cherry picked from commit b25e91a5)
2013-10-30 13:02:07 -07:00
Phillip Webb bcf7aecf0f Skip convert to Object from TypeConverterDelegate
Update TypeConverterDelegate to bypass conversion when the target type
is Object.class. Prior to this commit converting a single element array
to an Object would result in the element being returned, rather than
the array itself.

Issue: SPR-10996
(cherry picked from commit c9aace4d)
2013-10-30 13:02:07 -07:00
Phillip Webb 5854d519a1 Add targetIsClass to SpEL property cache key
Update the `CacheKey` class used by `ReflectivePropertyAccessor` to
include if the target object is class. The prevents an incorrect cache
hit from being returned when a property with the same name is read on
both an object and its class. For example:

	#{class.name}
	#{name}

Issue: SPR-10486
(cherry picked from commit 6d882b14)
2013-10-30 13:02:07 -07:00
Phillip Webb 1ea7f741fe Multicaster support for events with null source
Update `AbstractApplicationEventMulticaster` to support `EventObjects`
with a null source (which can happen if they have been serialized).

Issue: SPR-10945
(cherry picked from commit b0ff834e)
2013-10-30 13:02:07 -07:00
Phillip Webb 8c6fe2cb42 Consistent ordering for @PropertySource locations
Ensure that property source locations are processed in the same order
regardless if the 'name' attribute is set or not.

Prior to this commit multiple locations from a `@PropertySource` with
a name were added to a `CompositePropertySource` in such a way that
the first location would take precedence. This has now been reversed
for consistence with unnamed `@PropertySource`s

Issue: SPR-10820
(cherry picked from commit e3d3d8cd)
2013-10-30 13:02:06 -07:00
Rossen Stoyanchev 7a5a6893e3 Avoid filling up AntPathMatcher cache
This change avoid use of AntPathMatcher to extract URI template
variables when the lookup path is used as the best matching pattern.

Issue: SPR-10803
2013-10-30 14:34:13 -04:00
Juergen Hoeller c8e8d6cd49 Defensive handling of exceptions during factory method type checking
Also using ClassUtils.forName in AutowireUtils now in order to accept all common class name formats.

Issue: SPR-11034
(cherry picked from commit 8c1767e)
2013-10-28 13:47:11 +01:00
Juergen Hoeller 094ff8883d Polishing 2013-10-27 22:52:36 +01:00
Juergen Hoeller 44f79f95a7 Fixed resolveReturnTypeForFactoryMethod to unwrap TypedStringValue
XML-defined arguments values are initially turned into TypedStringValue wrappers. If we encounter an unresolved argument, we need to unwrap such a TypedStringValue and then try to treat its content as a class name.

Issue: SPR-11034
2013-10-27 22:48:57 +01:00
Juergen Hoeller 3eaec64ee8 Fixed source location of setEncoding method 2013-10-27 00:57:37 +02:00
Juergen Hoeller ff9c695599 Minor optimizations in factory method handling
Optimized getTypeForFactoryMethod's implementation for non-generic factory methods, and reduced calls to getResolvedFactoryMethod in order to avoid repeated synchronization. Derived from work around SPR-11034.
2013-10-27 00:55:02 +02:00
Juergen Hoeller 6021822ce4 Polishing 2013-10-26 17:31:43 +02:00
Juergen Hoeller 045f78e6c5 Fixed detection of setter in case of getter with covariant return type narrowing
Issue: SPR-10995
2013-10-26 17:31:24 +02:00
Juergen Hoeller 42568afb37 Factory method type resolution works with indexed and named arguments as well
Issue: SPR-11019
(cherry picked from commit 109faac)
2013-10-26 15:57:54 +02:00
Juergen Hoeller ce001c23f7 Cache InjectionMetadata per bean name instead of per Class, if possible
Issue: SPR-11027
(cherry picked from commit 4675bc4)
2013-10-26 15:56:57 +02:00
Juergen Hoeller 93405fb289 Made processCommonDefinitionAnnotations(AnnotatedBeanDefinition) public
Issue: SPR-11032
(cherry picked from commit 8bd4804)
2013-10-26 15:55:48 +02:00
Juergen Hoeller db056ae0e0 ExpressionState.getConfiguration() should never return null
Issue: SPR-11031
(cherry picked from commit 4aab315)
2013-10-26 15:55:13 +02:00
Juergen Hoeller 35d53af2ca Removed accidentally added temporary files 2013-10-26 15:54:46 +02:00
Sam Brannen 63de2fab4c Assert context uniqueness against merged config
Prior to this commit, the uniqueness check for @ContextConfiguration
attributes within a @ContextHierarchy was performed at a single test
class level instead of against the merged configuration for all test
class levels in the test class hierarchy.

This commit addresses this issue by moving the uniqueness check
algorithm from resolveContextHierarchyAttributes() to
buildContextHierarchyMap() within ContextLoaderUtils.

Issue: SPR-11011
Backport-Commit: 7658d856ca
2013-10-21 20:51:36 +02:00
Phillip Webb 5d8aa635c6 Propagate EvaluationContext from LiteralExpression
Update getValue(EvaluationContext context, Object rootObject,
Class<T> desiredResultType) to propagate the EvaluationContext to
ExpressionUtils.

Issue: SPR-10953
(cherry picked from 686cd79)
2013-10-18 17:57:46 -07:00
Juergen Hoeller ad9049e68a Polishing 2013-10-17 22:19:17 +02:00
Juergen Hoeller b9135788b9 Fixed type prediction for generic factory methods
We're consistently resolving class names now, and the entire algorithm moved from GenericTypeResolver to the internal AutowireUtils helper in the bean factory package.

Issue: SPR-10411
(cherry picked from commit 8b1927f)
2013-10-17 21:46:59 +02:00
Juergen Hoeller b62652aca1 Reduced "getParameterType call not supported" log message to single line
Issue: SPR-10185
(cherry picked from commit 41f041e)
2013-10-17 21:09:11 +02:00
Juergen Hoeller fce02d94b8 Changed JSR-330 detection logging from info to debug
Issue: SPR-10974
(cherry picked from commit 7a9d583)
2013-10-17 21:07:44 +02:00
Phillip Webb 2dca5b6815 Filter source @Configuration with @ComponentScan
Exclude self @Component when parsing @ComponentScan annotations.

Issue: SPR-10531
(cherry picked from d91ffb)
2013-10-10 17:03:36 -07:00
Juergen Hoeller a302c4ac45 Polishing
(cherry picked from commit 52cca48)
2013-10-04 23:31:18 +02:00
Rossen Stoyanchev 507cf8ad14 Make method in RequestMappingHandlerMapping protected
Issue: SPR-10950
2013-10-02 17:50:16 -04:00
Phillip Webb 7500caea52 Fix ArrayStoreException reading subclassed enums
Fix ASM AnnotationAttributesReadingVisitor to correctly deal with
subclasses enums.

Issue: SPR-10914
(cherry picked from 8abe949)
2013-09-27 11:39:11 -07:00
Juergen Hoeller 7994b63c13 Polishing 2013-09-26 21:38:54 +02:00
Juergen Hoeller 26e697b60c Silently swallow IllegalStateException on commit if the JMS transaction is based on a JDBC transaction
This fine-tuned change restores the original Spring 3.0 behavior for Oracle AQ, and also allows for other ConnectionFactory types to comply with the "getDataSource()" pattern.

Issue: SPR-10829
(cherry picked from commit 11d20e3)
2013-09-26 21:25:48 +02:00
Juergen Hoeller ef66708aa6 Fixed BadSqlGrammarException usage in transaction test suite
Issue: SPR-10902
2013-09-25 13:47:15 +02:00
Juergen Hoeller 30b3e24a32 Removed S0 from BadSqlGrammarException codes
S0 doesn't seem to be universally used for SQL grammar problems: see MS SQL Server's RAISERROR. This was reported years back; not sure why the fix didn't actually appear in the codebase back then.

Issue: SPR-10902
(cherry picked from commit d9b6203)
2013-09-25 13:05:06 +02:00
Juergen Hoeller 0a31892475 Fixed handling of @Resource's shareable value
Issue: SPR-10931
(cherry picked from commit 7bc3e3b)
2013-09-25 13:04:50 +02:00
Fedor Bobin 6fb2c72a55 Allow cursor returns from SQL functions
Update CallMetaDataContext to use the metaDataProvider
createDefaultOutParameter method when creating a SqlOutParameter as
a result of a SQL function call.

This change allows Spring to support Oracle cursor types when returned
from functions.

Issue: SPR-10606
(cherry picked from c16b21)
2013-09-24 16:09:09 -07:00
Phillip Webb c82d701a4e Fix typo in MVC reference documentation
Fix ContentNeogitatingViewResolver typo in MVC reference documentation.

Issue: SPR-10927
(cherry picked from 371d25)
2013-09-23 16:05:50 -07:00
Clément Plantier d66cf0c32f Fix "Problem locating method" SpEL error message
Replace "Problem locating method {0} cannot on type {1}" with
"Problem locating method {0} on type {1}".

Issue: SPR-10928
(cherry picked from 824ac5)

Conflicts:
	spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java
2013-09-20 11:50:30 -07:00
Juergen Hoeller 562c323989 EhCacheFactoryBean calls addCache after listener registration
Issue: SPR-10904
(cherry picked from commit a3df311)
2013-09-14 15:41:01 +02:00
Juergen Hoeller 13a68c6060 AbstractBeanFactory removes alreadyCreated entry after bean creation failure
Issue: SPR-10896
(cherry picked from commit e213561)
2013-09-14 15:37:41 +02:00
Juergen Hoeller 6110919842 Polished exception message 2013-09-04 22:11:11 +02:00
Juergen Hoeller c5aa0d12b0 Polishing
Issue: SPR-9495
(cherry picked from commit baa698e)
2013-09-04 22:05:47 +02:00
Juergen Hoeller 6de67cc2df Only cache resolved method when coming from ReflectiveMethodResolver
Issue: SPR-9495
(cherry picked from commit b7ff26a)
2013-09-04 22:00:32 +02:00
Juergen Hoeller b9d726fb84 Fixed EL resolution against static method with changing target class
Issue: SPR-10452
(cherry picked from commit 5e6044c)
2013-09-04 22:00:21 +02:00
Juergen Hoeller 2b57020c18 Polishing
(cherry picked from commit b25876f)
2013-09-04 21:59:37 +02:00
Juergen Hoeller 77298a19c9 Javadoc fixes
(cherry picked from commit facf31f)
2013-09-04 21:52:41 +02:00
Juergen Hoeller 55961544a7 Fixed method count in AbstractMethodMockingControl's IllegalStateException message
Issue: SPR-10885
2013-09-02 17:09:29 +02:00
Juergen Hoeller 5639aa7064 Properly handle getMethodDescriptors() null value on IBM JVM
Also internally renaming SimpleNonIndexedPropertyDescriptor to SimplePropertyDescriptor and preferring direct field access wherever possible.

Issue: SPR-10862
2013-09-02 16:42:06 +02:00
Juergen Hoeller 0c30618ae8 Fixed getCachedExecutor race condition in MethodReference
This commit includes a full backport of the changes in SPR-10657, instead of just the initial commit which the original backport request referred to.

Issue: SPR-10884
Issue: SPR-10657
2013-09-02 15:33:15 +02:00
Juergen Hoeller 9317d8f43e Polishing
(cherry picked from commit caa1218)
2013-08-29 19:21:24 +02:00
Juergen Hoeller 692908b722 Javadoc fixes
(cherry picked from commit 465e629)
2013-08-29 19:20:54 +02:00
Grzegorz Rożniecki c890d1e69d Fix malformed code in documentation
Fixed code snippets in "Handling complex types for stored procedure
calls" paragraph.

Issue: SPR-10798
(cherry picked from commit 00c744b)
2013-08-28 14:28:21 -07:00
clemp6r 4c7cb858d2 Fix elvis operator mistake in reference docs
In the given example the expression using the Elvis operator will
return "Nikola Tesla" and not "Mike Tesla".

Issue: SPR-10850
(cherry picked from commit 84242f1)
2013-08-28 14:17:34 -07:00
Juergen Hoeller 5a49d657d8 AnnotationConfigWebApplicationContext allows for repeated register/scan calls
Restoring consistency with AnnotationConfigApplicationContext.

Issue: SPR-10852
(cherry picked from commit 01b8d93)
2013-08-28 00:24:22 +02:00
Juergen Hoeller 8a1ae53166 Consistent use of Class<?>
(cherry picked from commit 091712d)
2013-08-28 00:23:58 +02:00
Juergen Hoeller 0765a05434 Marked @Profile as @Documented
(cherry picked from commit e812b6c)
2013-08-28 00:20:52 +02:00
Rossen Stoyanchev 072e5e8471 Revise use of FilterChain in MockMvc
MockFilterChain should not be re-used across requests. This is not an
issue unless tests are executed concurrently. This change ensures the
MockFilterChain is re-created for each request in MockMvc.

Issue: SPR-10838
2013-08-27 11:45:46 -04:00
Gabriel Axel a17912d19e Fix NPE in ResourceHttpMessageConverter
ResourceHttpMessageConverter tries to use the filename to determine the
media type, but for Resource implementations such as ByteArrayResource
it is null, which causes NullPointerException. The fix checks whether
getFilename returns null before attempting to determine the media type
by it.

Issue: SPR-10848
2013-08-22 16:14:03 -04:00
Juergen Hoeller 610e7796d9 GenericTypeResolver properly handles bound parameterized type
Issue: SPR-10819
(cherry picked from commit ea6525f)
2013-08-20 19:41:00 +02:00
Arjen Poutsma 8efac21c2b Support 'empty' StreamSource in Jaxb2Marshaller
Added support for StreamSources that do not have a InputStream or
Reader, but do have a System ID.

Issue: 10828
2013-08-13 18:16:42 -04:00
Lonre Wang 40c7303702 Fix typo in reference docs
(cherry picked from 5549bd90)
2013-08-12 14:26:08 -07:00
Arjen Poutsma c00782a3e8 Added reference to CatchAllConverter
Added reference to CatchAllConverter in both javadoc and reference docs.

Issue: SPR-10821
2013-08-12 12:32:23 +02:00
Arjen Poutsma 96f5314df6 Added XStream CatchAllConverter
Added XStream CatchAllConverter that supports all classes, but throws
exceptions for (un)marshalling.

Main purpose of this class is to register this converter as a catchall
last converter with a normal or higher priority in addition to
converters that explicitly  support the domain classes that should be
supported. As a result, default XStream  converters with lower
priorities and possible security vulnerabilities do not get invoked.

Issue: SPR-10821
2013-08-09 09:38:51 -04:00
Rossen Stoyanchev 2b628a1a0d Fix bug that ignored custom json prefix
Issue: SPR-10817
2013-08-08 09:39:08 -04:00
Spring Buildmaster 349143864c Increment version to 3.2.5.BUILD-SNAPSHOT 2013-08-06 16:15:25 -07:00
Spring Buildmaster fc73f6bb2c Release version 3.2.4.RELEASE 2013-08-06 16:00:04 -07:00
Phillip Webb 119364f326 Further 3.2.4 changelog entries 2013-08-06 15:11:43 -07:00
Arjen Poutsma 434735fbf6 Fix potential security risk when using Spring OXM
Disable by default external entity resolution when using Spring OXM
with jaxb. This prevents a XML entity from being able to resolve a
local file on the host system.

See:
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing

Issue: SPR-10806
(cherry picked from commit 7576274)
2013-08-06 15:10:05 -07:00
Grzegorz Rożniecki 8f4221deb3 Fix SimpleJdbcCall and SimpleJdbcInsert Javadoc
Change "fluid" interface to "fluent" and "string" to "chain", plus fix
few typos in Javadoc.

Issue: SPR-10792
(cherry picked from commit 2344412)
2013-08-06 14:44:01 -07:00
Juergen Hoeller 2d646ca79e Polishing 2013-08-06 01:58:46 +02:00
Juergen Hoeller 1245919331 Polishing 2013-08-06 01:15:17 +02:00
Juergen Hoeller bcbd338fe2 Further 3.2.4 changelog entries 2013-08-06 00:32:59 +02:00
Juergen Hoeller 945463b826 Added javadoc note on the use of CachingConnectionFactory
Issue: SPR-10581
(cherry picked from commit 2626a35)
2013-08-06 00:31:18 +02:00
Juergen Hoeller 3ba3dd61d1 Consistent use of varargs; deprecated setAnnotatedClass method
Issue: SPR-10421
2013-08-06 00:31:06 +02:00
Juergen Hoeller cd523c7051 Restored overridable getXStream() method in Spring Framework 3.2.x
Also setting the bean class loader on the XStream instance itself now.

Issue: SPR-10421
2013-08-05 23:05:15 +02:00
Juergen Hoeller 20ddd3254b DelegatingFilterProxy avoids synchronization for pre-resolved delegate
Issue: SPR-10413
(cherry picked from commit c26272c)
2013-08-05 22:24:58 +02:00
Juergen Hoeller e30b842316 Fixed ClassFilterAwareUnionMethodMatcher equals implementation
Issue: SPR-10604
(cherry picked from commit f329140)
2013-08-05 22:23:10 +02:00
Rossen Stoyanchev b0675c031e Make date methods in HttpHeaders public
Issue: SPR-10713
2013-08-05 12:46:33 -04:00
Rossen Stoyanchev 0f71da5be6 Return -1 after parse error for Expires header
Issue: SPR-10648
2013-08-05 12:38:53 -04:00
Juergen Hoeller 9035a97e18 Refined javadoc for WebLogic/WebSphere transaction setup
Issue: SPR-10777
2013-08-01 17:24:24 +02:00
Juergen Hoeller d32a77a5f0 Optimized TomcatInstrumentableClassLoader implementation
Issue: SPR-10788
2013-08-01 15:49:58 +02:00
Juergen Hoeller d8e3ef7640 Polishing
Issue: SPR-10752
Issue: SPR-10627
2013-08-01 00:35:51 +02:00
Juergen Hoeller ccb02a2355 Updated changelog for 3.2.4 2013-07-31 23:42:36 +02:00
Juergen Hoeller d0948f1f03 Fixed misunderstanding with respect to excludeUnlistedClasses default in JPA 2.0
Issue: SPR-10767
2013-07-31 23:40:59 +02:00
Juergen Hoeller ae0f23e942 Polishing
Issue: SPR-10752
Issue: SPR-10627
2013-07-31 22:42:27 +02:00
Juergen Hoeller b40263e06b PropertySourcesPlaceholderConfigurer's "ignoreUnresolvablePlaceholders" setting reliably applies to nested placeholders as well
Issue: SPR-10549
(cherry picked from commit 127b91f)
2013-07-31 18:38:31 +02:00
Juergen Hoeller 2f8dfb3e52 Updated Quartz version range in javadoc
Issue: SPR-10775
2013-07-30 23:27:34 +02:00
Juergen Hoeller d5c78c953d Remove the JobDetail from the job data map after discovering it
Issue: SPR-10775
2013-07-30 23:27:33 +02:00
Juergen Hoeller dfac1d0510 Added "requestsRecovery" bean property to JobDetailFactoryBean
Issue: SPR-10775
2013-07-30 23:27:32 +02:00
Juergen Hoeller 14b83c3fcc Polishing
Issue: SPR-10609
2013-07-30 23:27:30 +02:00
Phillip Webb ae6e84bc7d Fix TestNG build settings 2013-07-30 14:21:28 -07:00
Phillip Webb 4213a31a7d Fix failing test due to CUSTOM_COMPILATION Group 2013-07-30 13:54:42 -07:00
Phillip Webb 22454c8edf Upgradle to gradle 1.6 2013-07-30 13:29:05 -07:00
Deline Neo 98da5a7b2b Add attributeDoesNotExist ModelResultMatcher
Issue: SPR-10509
2013-07-30 15:41:55 -04:00
Phillip Webb 0a37552beb Add CUSTOM_COMPILATION TestGroup 2013-07-30 11:54:22 -07:00
Phillip Webb 1b702fa6a2 Revert "Add test source dependency in attempt to fix CI"
This reverts commit a2e438b2be.
2013-07-30 11:53:34 -07:00
Phillip Webb a2e438b2be Add test source dependency in attempt to fix CI 2013-07-30 11:33:30 -07:00
Phillip Webb 9ff9d45283 Minor polish to gradle build 2013-07-30 10:33:52 -07:00
Phillip Webb 1fee4c0c0b Upgradle to gradle 1.6 2013-07-30 10:33:03 -07:00
Rossen Stoyanchev dc87a2211c Make HTTP scheme parsing case-insensitive
Issue: SPR-10779
2013-07-30 12:33:22 -04:00
Phillip Webb 77b7344530 Upgradle to gradle 1.6 2013-07-30 09:29:44 -07:00
Phillip Webb 7cde4f1503 Update gradle plugin versions 2013-07-30 09:22:08 -07:00
Rossen Stoyanchev 6c11fd3b5e Fix issue with parsing x-forwarded-host header
Issue: SPR-10701
2013-07-30 11:48:06 -04:00
Biju Kunjummen eec4a37d1c Fix Jaxb2TypeScanner to scan for @XmlRegistry
Update ClassPathJaxb2TypeScanner to scan for @XmlRegistry classes.

Prior to this commit explicitly configured @XmlRegistry annotated classes
were not registered with the JAXBContext when using the 'packagesToScan'
property of the Jaxb2Unmarshaller.

Issue: SPR-10714
(cherry picked from 4f871d4)
2013-07-29 11:26:52 -07:00
Phillip Webb 1e3dc4aeae Include argument types in MethodReference cache
Update the cached MethodExecutor in MethodReference to include the
method argument types. Prevents the incorrect use of the cache when the
SpEL expression refers to a class that has overloaded methods.

Issue: SPR-10657
(cherry picked from commit f9b12b8)
2013-07-25 11:28:03 +02:00
Phillip Webb d4b54d834e Skip abstract beans in getBeansWithAnnotation()
Update BeanFactory.getBeansWithAnnotation() to skip any abstract
bean definitions.

Issue: SPR-10663
(cherry picked from commit 8ed8ee2)
2013-07-25 11:27:57 +02:00
Juergen Hoeller 3562cd759b Moved executor null check to AsyncExecutionInterceptor, allowing AbstractAsyncExecutionAspect to fall back to sync execution (as in 3.2.1)
Issue: SPR-10636
(cherry picked from commit b6c54c3)
2013-07-25 10:45:59 +02:00
Juergen Hoeller c1dc4e2c75 Resource-based PlatformTransactionManager implementations defensively catch Throwable in doBegin in order to reliably close resource in case of OutOfMemoryError
Issue: SPR-10755
(cherry picked from commit 2e4eb9f)
2013-07-25 10:45:58 +02:00
Phillip Webb 8feeec4a60 Fix ResourceHttpRequestHandler empty location log
Fix ResourceHttpRequestHandler to only log warning when locations
is empty.

Issue: SPR-10780
(cherry picked from bc52469)
2013-07-24 16:52:47 -07:00
Phillip Webb 440a63a3d0 Make TypeDescriptor serializable
Issue: SPR-10631
(cherry picked from 9eb596a)
2013-07-23 14:19:15 -07:00
Phillip Webb 274ed1fe67 Remove unnecessary spring-instrument dependencies
Remove unnecessary spring-core dependency from spring-instrument.

Issue: SPR-10732
(cherry picked from 9939c48)
2013-07-23 13:37:43 -07:00
Phillip Webb 1b47f6c0b0 Add Java 7 instrumentation manifest attributes
Update META-INF/MANIFEST.MF for spring-instrument to include
necessary attributes for running under Java 7:

    Can-Redefine-Classes : true
    Can-Retransform-Classes: true
    Can-Set-Native-Method-Prefix : false

(see http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/
package-summary.html)

Prior to this commit `InstrumentationSavingAgent.getInstrumentation().
addTransformer(t, true);` would fail under Java 7.

Issue: SPR-10731
(Cherry picked from 50333ca)
2013-07-23 13:37:09 -07:00
Phillip Webb 66e4c9b2bb Fix case of rollbackForClassName in ref docs
Update @Transactional reference documentation to fix the case of the
rollbackForClassName and noRollbackForClassName attributes.

Issue: SPR-10754
(cherry picked from 1204d2a)
2013-07-22 15:48:27 -07:00
Nick Williams e608055021 Parse JPA <exclude-unlisted-classes> correctly
Fix PersistenceUnitReader to correctly read <exclude-unlisted-classes>
in both JPA 1.0 and 2.0 persistence.xml files.

Prior to this commit PersistenceUnitReader would set the value of
excludeUnlistedClasses to true when a <exclude-unlisted-classes> element
was present, regardless of its value.

The following rules are now used when parsing:

- If the <exclude-unlisted-classes> element is missing the appropriate
  default value is set (based on the JPA version).

- If an empty <exclude-unlisted-classes/> element is found the
  excludeUnlistedClasses property is set to true.

- Otherwise the value of the <exclude-unlisted-classes> element is used
  to set the excludeUnlistedClasses property.

Issue: SPR-10767
(cherry picked from 7ad540d)

Conflicts:
	spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceUnitReader.java
2013-07-22 12:38:46 -07:00
Phillip Webb 199be0ad3c Add spring-core cglib dependency 2013-07-19 14:52:54 -07:00
Phillip Webb af7753eac6 Add MemorySafeUndeclaredThrowableStrategy
Port the latest unreleased UndeclaredThrowableStrategy implementation
from cglib to fix a memory-leak present in v3.

Issue: SPR-10709
(cherry picked from 587877c)
2013-07-19 14:39:24 -07:00
Rossen Stoyanchev cce74b8ba2 Make the JSON prefix used in converters configurable
Issue: SPR-10627
2013-07-19 17:23:33 -04:00
Rossen Stoyanchev dd7508d606 Replace assert w/ warning in ResourceHttpRequestHandl.
Issue: SPR-9186
2013-07-19 17:23:33 -04:00
Rossen Stoyanchev 3bf56dda56 Fix issue in MappingJacksonJsonView
Issue: SPR-10752
2013-07-19 17:23:33 -04:00
Phillip Webb a72209aad3 Make ConfClassPostPro Ordered.HIGHEST_PRECEDENCE
Make ConfigurationClassPostProcessor Ordered.HIGHEST_PRECEDENCE in
case several BeanDefinitionRegistryPostProcessors are registered.

Issue: SPR-10645
(cherry picked from 350cb9b)
2013-07-19 14:16:39 -07:00
Phillip Webb 67f41b15eb Resolve ${} placeholders in @ImportResource
Update ConfigurationClassParser to resolve any ${} placeholders from
@ImportResource values.

Issue: SPR-10686
(cherry picked from commit 700a08e)
2013-07-19 13:14:05 -07:00
Arjen Poutsma 3515acfa3d Added 'processExternalEntities' to JAXB2Marshaller
Added 'processExternalEntities' property to the JAXB2Marshaller, which
indicates whether external XML entities are processed when
unmarshalling.

Default is false, meaning that external entities are not resolved.
Processing of external entities will only be enabled/disabled when the
Source} passed to #unmarshal(Source) is a SAXSource or StreamSource. It
has no effect for DOMSource or StAXSource instances.
2013-07-19 11:07:07 -04:00
Rossen Stoyanchev 7fdd0c22b2 Fix issue in ContentNeogitatingViewResolver
The following commit in 3.2.3 had a side effect on CNVR:
https://github.com/SpringSource/spring-framework/commit/aaded7e30b06cc70a354856a2288acd04045b673

It appears that CNVR doesn't treat a request for "*/*" differently
from a request that does not request content types. Both should be
interpreted as "any content type is acceptable". This fix ensures
that CNVR treats these two cases the same way.

Issue: SPR-10683
2013-07-18 22:03:13 -04:00
Rossen Stoyanchev a0f8a894f2 Cache constructor instance in WebAsyncUtils
Issue: SPR-10673
2013-07-18 17:48:18 -04:00
Phillip Webb 55f02db18e 'Rename' HttpHeaders.getIfNotModifiedSince()
Effectively rename HttpHeaders.getIfNotModifiedSince() to
getIfModifiedSince() by adding a new method and deprecating the
old one.

Issue: SPR-10600
2013-06-26 10:45:33 -07:00
Phillip Webb 71e88cbf30 Fix SQL syntax error in jdbcTemplate update docs
Update the reference guide jdbcTemplate update example to include the
column name.

Issue: SPR-10625
2013-06-25 22:22:36 -07:00
Phillip Webb 514a2e9568 Package RmiInvocationWrapperRTD.xml in jar
Ensure RmiInvocationWrapperRTD.xml is packaged inside spring-context.jar

Issue: SPR-10649

Conflicts:
	build.gradle
2013-06-23 23:52:05 -07:00
Rossen Stoyanchev abfb439bfe Reverse SPR-10402 change that caused 3.2.3 regression
SPR-10402 in Spring Framework 3.2.3 treated empty request parameter
values as missing values, if the empty value was turned into a null
by a PropertyEditor or Converter. This caused the regression.

Issue: SPR-10578, SPR-10402, SPR-10584
2013-06-20 16:25:30 -04:00
Phillip Webb 4ba43b4737 Support meta @Component with non-string value
Update AnnotationBeanNameGenerator to only use the value attribute of
a @Component meta-annotated annotation when it is a String.

Issue: SPR-10580
2013-06-04 10:24:14 -07:00
Spring Buildmaster 2655657a51 2013-05-20 10:18:53 -07:00
Rob Winch 404671416a Update BuildTests to verify JDK 1.6
Issue: SPR-10569
2013-05-20 10:37:33 -05:00
Phillip Webb 260eafc819 Enforce JDK version on CI server
Add a test to ensure that the CI server does not accidentally build
with the wrong JDK version.

Issue: SPR-10569
2013-05-16 17:14:03 -07:00
Juergen Hoeller ef8b5763e6 Final addition to 3.2.3 changelog 2013-05-16 19:31:57 +02:00
Juergen Hoeller 6b89af824d Consistent detection of Order annotation in superclasses and interfaces
Issue: SPR-10514
(cherry picked from commit 814d24e)
2013-05-16 18:07:00 +02:00
Juergen Hoeller 86b4b2ef23 Consistent use of Class<?> in Assert
(cherry picked from commit 16548d2)
2013-05-16 16:11:30 +02:00
Juergen Hoeller faa8430fd7 Avoid NPE in ContextLoader when dealing with an untyped ApplicationContextInitializer
Issue: SPR-10449
(cherry picked from commit a19c976)
2013-05-16 16:11:25 +02:00
Juergen Hoeller 76f870caca Final preparations for 3.2.3 release 2013-05-16 14:50:03 +02:00
Juergen Hoeller 615315728b Fixed BeanPropertyRowMapper to only prefix actual upper-case letters with underscores
Issue: SPR-10547
(cherry picked from commit c8b071c)
2013-05-16 14:34:44 +02:00
Juergen Hoeller 115442242f Replaced Map synchronization with ConcurrentHashMap to avoid session access deadlocks
Issue: SPR-10436
(cherry picked from commit cd3d0c3)
2013-05-16 14:34:38 +02:00
Juergen Hoeller 10c0e8af01 Final changelog entries for 3.2.3 2013-05-16 00:17:00 +02:00
Juergen Hoeller b6e20a4cc9 Introduced "jsonPrefix" bean property
This change involves a modification of the "writeContent" template method to include the "jsonPrefix" String instead of the "prefixJson" boolean flag. Since said template method has only been introduced in 3.2.2, this change should hopefully not be a problem.

Issue: SPR-10567
(cherry picked from commit 28164b4)
2013-05-16 00:02:31 +02:00
Juergen Hoeller a8adec7673 Avoid unnecessary creation of default StandardEnvironment instances
Issue: SPR-10568
(cherry picked from commit 7e01578)
2013-05-15 23:59:29 +02:00
Juergen Hoeller 2ae61c503e Further changelog entries for 3.2.3 2013-05-15 17:04:34 +02:00
Juergen Hoeller c2b2f30669 Polishing 2013-05-15 16:57:57 +02:00
Juergen Hoeller 239a7cd85f Fixed type detection to avoid reuse of parent bean's targetType on child definition merge
Issue: SPR-10374
(cherry picked from commit 070103b)
2013-05-15 16:42:28 +02:00
Juergen Hoeller 6e4317ebfb Properly handle knownSuperclasses in case of an overridden ConfigurationClass
Issue: SPR-10546
2013-05-15 13:47:03 +02:00
Juergen Hoeller 325d8834e3 Polishing 2013-05-15 11:34:58 +02:00
Juergen Hoeller 0c76cb7e80 Clarified that CronTrigger never schedules overlapping executions
Issue: SPR-10556
(cherry picked from commit 5dbbd8f)
2013-05-15 11:34:57 +02:00
Rob Winch 940011e233 Ensure Parent ConfigurationClass loaded on overrides
Previously ConfigurationClassParser could override a nested
@Configuration without consideration of @Bean's defined in parent
classes.

This commit ensures that if the original ConfigurationClass contains
additional bean definitions it is processed again.

Issue: SPR-10546
2013-05-15 11:34:56 +02:00
Rossen Stoyanchev 92bbd8103b Make removal of jsessionid case insensitive
Issue: SPR-10398
2013-05-14 22:07:52 -04:00
Rossen Stoyanchev 9c194699c7 Reinstate removal of semicolon content
Commit 5b1165 was an attempt to leave semicolon content in the URL path
while ignoring it for request mapping purposes. However, it becomes
quite difficult to manage and semicolon content should not always be
ignored (sometimes a semicolon is used as a separator of multiple items
in a path segment, rather than for matrix variables).

This change effectively reverts back to the original approach in 3.2
where a flag on AbstractHandlerMapping can be used to have semicolon
content removed or kept. If kept, path segments with matrix variables
must be represented with a path segment.

The main difference is that by default it is removed everywhere
including the MVC namespace and Java config.

Issue: SPR-10427, SPR-10234
2013-05-14 21:30:59 -04:00
Rossen Stoyanchev 25701ef984 Fix deadlock issue in DeferredResult
Previously DeferredResult locked around the setting of the result
including handling up to the part of submitting a dispatch. This
can cause a deadlock if a timeout occurs at the same time since
the Tomcat timeout thread has its own locking that permits only
one thread to do timeout or dispatch processing.

The fix reduces the locking to cover only the attempt to set the
DeferredResult but not the dispatching.

Issue: SPR-10485
2013-05-14 17:06:00 -04:00
Juergen Hoeller 87ef99df5e Updated changelog for 3.2.3 release 2013-05-14 18:50:39 +02:00
Juergen Hoeller 13ca2752ae Consistent use of Class<?> in core container method signatures
(cherry picked from commit 1461744)
2013-05-14 18:06:12 +02:00
Juergen Hoeller ef363b0f7a Detect a FactoryBean type match even if predictBeanType returned a non-FactoryBean type
This change should be the final piece in the puzzle to let SmartInstantiationAwareBeanPostProcessor's predictBeanType predict a FactoryBean-produced type, effectively as a semantic alternative to its postProcessBeforeInstantiation-related role.

Issue: SPR-10517
(cherry picked from commit bc3e585)
2013-05-14 18:02:49 +02:00
Juergen Hoeller f9db59e730 GenericTypeResolver defensively calls Class.getGenericSuperclass() and consistently uses Class<?>
Issue: SPR-10559
(cherry picked from commit 25e29b8)
2013-05-14 18:01:41 +02:00
Rob Winch 0dcca2304f Remove xdoclint:none for < JDK 8 2013-05-13 11:54:58 -05:00
Rossen Stoyanchev ad272a0c87 Close InputStream in ResourceHttpMessageConverter
Spring 3.2.2 introduced a change to avoid closing the response stream
in HttpMessageConverters (SPR-10095). However, the InputStream of
resources being written, for example as part of a multi-part request
should be closed. This change ensures that.

Issue: SPR-10460
2013-05-10 17:31:48 -04:00
Juergen Hoeller be224e1f30 ServletContextResourcePatternResolver uses encoded jar file location for UrlResource
Adding overloaded constructors for URI specification to UrlResource, as a convenience.

Issue: SPR-10471
(cherry picked from commit 1f0f46f)
2013-05-10 22:13:17 +02:00
Rossen Stoyanchev 4bb0916202 Delay check if pattern ends with slash
This is a minor fix with no actual impact.

Issue: SPR-10504
2013-05-10 12:51:48 -04:00
Rossen Stoyanchev d3eda09c01 Allow treating empty @RequestParam as missing value
If type conversion turns an empty request parameter value (i.e. "") to
null, we should treat it as a missing value. By default the
ConversionService doesn't change empty strings and therefore one must
explicitly convert them to null for example by registering a
StringTrimmerEditor with emptyAsNull=true.

Issue: SPR-10402
2013-05-10 12:51:31 -04:00
Rossen Stoyanchev 399f887128 Add servletRelativeAction form tag attribute
A recent change in FormTag to prepend the context and servlet paths if
not present, causes issues when used in portlet applications.
This change introduces a servletRelativeAction form tag attribute that
must be used for the context and servlet paths to be prepended.

Issue: SPR-10382
2013-05-10 12:51:20 -04:00
Rossen Stoyanchev 4d005b6987 Improve default content type selection
Previously ContentNegotiationManager continued with the next
ContentNegotiationStrategy only if the current one returned an empty
list. Now it also does that if the current ContentNegotiationStrategy
returns "*/*". Since the absence of an Accept header and "*/*" have
the same meaning, this allows a default content type to be used in
either case.

Issue: SPR-10513
2013-05-10 12:51:08 -04:00
Rossen Stoyanchev 532a7a3a02 Invoke global, then local @InitBinder/@ModelAttribute
@InitBinder and @ModelAttribute methods in @ControllerAdvice classes
are now invoked first, allowing any such methods in the @Controller
class to override them.

Issue: SPR-10419
2013-05-10 12:50:24 -04:00
Juergen Hoeller b2d416fd5f Revised ReflectiveMethodResolver to properly handle any kind of List returned from a MethodFilter
Issue: SPR-10392
(cherry picked from commit ad88650)
2013-05-07 22:07:29 +02:00
Juergen Hoeller 7298c3d669 Fixed MockMvc example code
Issue: SPR-10389
(cherry picked from commit 35847ad)
2013-05-07 22:06:51 +02:00
Juergen Hoeller 7bbd38b9e0 Fixed javadoc warnings
Issue: SPR-10373
(cherry picked from commit 1ca943c)
2013-05-07 22:06:33 +02:00
Juergen Hoeller 64d83a550e MappingJackson(2)MessageConverter needs to use bean ClassLoader 2013-05-07 18:22:48 +02:00
Juergen Hoeller 0df1630ab9 Jaxb2Marshaller doesn't need to depend on ResourceLoaderAware
Issue: SPR-10512
(cherry picked from commit 255eab5)
2013-05-03 17:48:12 +02:00
Juergen Hoeller 7cbc115da6 Added "postProcessConfiguration" template method to LocalValidatorFactoryBean; clarified limited compatibility with Hibernate Validator 5.0 2013-05-03 15:19:28 +02:00
Juergen Hoeller b962239e11 Polishing 2013-05-03 13:47:54 +02:00
Juergen Hoeller 872cf6b076 Removed unnecessary HttpUrlTemplate subclass of UriTemplate 2013-05-03 13:38:31 +02:00
Juergen Hoeller b2bd319d47 Polished UriComponents implementation
(cherry picked from commit c3b624d)
2013-05-03 13:23:48 +02:00
Juergen Hoeller e3fa49063e Added note on non-thread-safety of Jackson's DateFormat support 2013-05-02 16:06:51 +02:00
Juergen Hoeller c302efdbbf Further build file updates for alignment with 4.0 build 2013-05-01 22:38:43 +02:00
Juergen Hoeller 12699696f4 Added note on OpenJDK 8 compatibility 2013-05-01 21:45:50 +02:00
Juergen Hoeller c4f2566070 Allow for building and testing the 3.2.x line against OpenJDK 8 2013-05-01 21:39:51 +02:00
Juergen Hoeller 6458643f15 Updated 3.2.3 changelog 2013-04-30 23:57:15 +02:00
Juergen Hoeller 2145545e69 Ignore failing TopLink tests (not worth messing with since TopLink is deprecated anyway) 2013-04-30 23:29:07 +02:00
Juergen Hoeller f6545cde38 Polishing 2013-04-30 23:29:06 +02:00
Juergen Hoeller 601c64a65c Removed broken applyQueryTimeout implementation (following a fix in 4.0) 2013-04-30 23:29:06 +02:00
Juergen Hoeller 964f1a6213 Refined HibernateJpaDialect for Hibernate 4.2 support
HibernateJpaDialect's HibernateConnectionHandle does not call close() for Hibernate 4.x anymore, since on 4.2, the exposed Connection handle isn't a "borrowed connection" wrapper but rather the actual underlying Connection - with a close() call immediately returning the Connection to the pool and making the local handle invalid for further use within the transaction.

Issue: SPR-10395
2013-04-30 23:29:05 +02:00
Juergen Hoeller 886cc2cce8 Fixed general test suite problems found during OpenJDK 8 upgrade
Issue: SPR-9639
(cherry picked from commit 19f783b)
2013-04-30 23:29:04 +02:00
Juergen Hoeller 5bdd2d245c Consistent Map/Set ordering
Use LinkedHashMaps/Sets wherever exposed to users, and code tests defensively in terms of expected Map/Set ordering. Otherwise, there'll be runtime order differences between JDK 7 and JDK 8 due to internal HashMap/Set implementation differences.

Issue: SPR-9639
(cherry picked from commit 9c09a0a)
2013-04-30 23:29:03 +02:00
Juergen Hoeller d0513f7521 Revised Joda-Time support (as a side effect of JSR-310 support in Spring 4.0)
Issue: SPR-9641
(cherry picked from commit b5d44e1)
2013-04-30 23:29:02 +02:00
Juergen Hoeller 265c0c1505 Minimized ASM usage
In particular, avoid accidental usage of ASM for core JDK types - which will fail in case of a new bytecode version in the JDK, even if the application itself has been compiled with an earlier bytecode target.

Issue: SPR-10292
(cherry picked from commit d3a4068)
2013-04-30 23:29:02 +02:00
Juergen Hoeller 886cf825cb Added "getName()" accessor to MethodReference
Issue: SPR-10422
(cherry picked from commit 5ff2653)
2013-04-30 23:29:01 +02:00
Juergen Hoeller 03033f6c06 Fixed typo in code example
Issue: SPR-10394
(cherry picked from commit f374b7a)
2013-04-30 23:29:00 +02:00
Juergen Hoeller 5ff2dfbe13 Removed references to deprecated queryForInt method from documentation
Issue: SPR-10257
(cherry picked from commit 6be954e)
2013-04-30 23:28:59 +02:00
Juergen Hoeller fa44ab6336 Removed unnecessary CGLIB 2.2 dependency from spring-test-mvc module
(cherry picked from commit 657bd80)
2013-04-30 23:28:58 +02:00
Juergen Hoeller eed1a58b81 Fixed annotation attribute processing for enum arrays
Based on https://github.com/SpringSource/spring-framework/pull/263
(cherry picked from commit 06fdfb0)
2013-04-30 23:28:57 +02:00
424 changed files with 8817 additions and 5000 deletions
+131 -58
View File
@@ -3,8 +3,8 @@ buildscript {
maven { url "http://repo.springsource.org/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.3")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.6")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.4")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.7")
}
}
@@ -12,6 +12,11 @@ configure(allprojects) { project ->
group = "org.springframework"
version = qualifyVersionIfNecessary(version)
// The following is a work-around for allowing to build on JDK 8 until the
// Gradle build uses Ant 1.9.x by default. This is necessary to avoid the
// "Class not found: javac1.8" issue with Ant versions prior to 1.9.x
ant.properties["build.compiler"] = "javac1.7"
ext.aspectjVersion = "1.7.2"
ext.hsqldbVersion = "1.8.0.10"
ext.junitVersion = "4.11"
@@ -58,6 +63,9 @@ configure(allprojects) { project ->
test {
systemProperty("java.awt.headless", "true")
systemProperty("testGroups", project.properties.get("testGroups"))
scanForTestClasses = false
include '**/*Tests.*'
exclude '**/*Abstract*.*'
}
repositories {
@@ -71,25 +79,26 @@ configure(allprojects) { project ->
}
ext.javadocLinks = [
"http://docs.oracle.com/javase/6/docs/api",
"http://docs.oracle.com/javaee/6/api",
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
"http://commons.apache.org/proper/commons-lang/javadocs/api-release/",
"http://commons.apache.org/proper/commons-codec/apidocs/",
"http://docs.oracle.com/javase/6/docs/api/",
"http://docs.oracle.com/javaee/6/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"http://glassfish.java.net/nonav/docs/v3/api/",
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
"http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
"http://aopalliance.sourceforge.net/doc/",
"http://glassfish.java.net/nonav/docs/v3/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // commonj
"http://quartz-scheduler.org/api/2.1.5/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://hc.apache.org/httpclient-3.x/apidocs/",
"http://fasterxml.github.com/jackson-core/javadoc/2.0.0/",
"http://jackson.codehaus.org/1.4.2/javadoc/",
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"http://ibatis.apache.org/docs/java/dev/",
"http://tiles.apache.org/framework/apidocs/",
"http://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
"http://commons.apache.org/proper/commons-codec/apidocs/",
"http://commons.apache.org/proper/commons-dbcp/apidocs/",
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
"http://tiles.apache.org/framework/apidocs/",
"http://ibatis.apache.org/docs/java/dev/",
"http://hc.apache.org/httpclient-3.x/apidocs/",
"http://aopalliance.sourceforge.net/doc/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://ehcache.org/apidocs/",
"http://quartz-scheduler.org/api/2.1.5/",
"http://jackson.codehaus.org/1.4.2/javadoc/",
"http://fasterxml.github.com/jackson-core/javadoc/2.0.1/",
] as String[]
}
@@ -118,6 +127,9 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
options.author = true
options.header = project.name
options.links(project.ext.javadocLinks)
if(JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
// suppress warnings due to cross-module @see and @link references;
// note that global 'api' task does display all warnings.
@@ -148,7 +160,7 @@ project("spring-build-src") {
dependencies {
compile gradleApi()
groovy localGroovy()
compile localGroovy()
}
configurations.archives.artifacts.clear()
@@ -219,6 +231,7 @@ project("spring-core") {
cglib("cglib:cglib:${cglibVersion}@jar")
jarjar("com.googlecode.jarjar:jarjar:1.3")
compile(files(cglibRepackJar))
compile(files(asmRepackJar))
compile("commons-logging:commons-logging:1.1.1")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
@@ -245,6 +258,7 @@ project("spring-core") {
project("spring-beans") {
description = "Spring Beans"
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
@@ -256,6 +270,7 @@ project("spring-beans") {
project("spring-aop") {
description = "Spring AOP"
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
@@ -269,6 +284,7 @@ project("spring-aop") {
project("spring-expression") {
description = "Spring Expression Language (SpEL)"
dependencies {
compile(project(":spring-core"))
}
@@ -276,17 +292,19 @@ project("spring-expression") {
project("spring-instrument") {
description = "Spring Instrument"
dependencies {
compile(project(":spring-core"))
}
jar {
manifest.attributes["Premain-Class"] =
"org.springframework.instrument.InstrumentationSavingAgent"
manifest.attributes["Can-Redefine-Classes"] = "true"
manifest.attributes["Can-Retransform-Classes"] = "true"
manifest.attributes["Can-Set-Native-Method-Prefix"] = "false"
}
}
project("spring-instrument-tomcat") {
description = "Spring Instrument Tomcat"
dependencies {
provided("org.apache.tomcat:catalina:6.0.16")
}
@@ -294,6 +312,7 @@ project("spring-instrument-tomcat") {
project("spring-context") {
description = "Spring Context"
dependencies {
optional(project(":spring-instrument"))
compile(project(":spring-aop"))
@@ -306,12 +325,12 @@ project("spring-context") {
optional("javax.inject:javax.inject:1")
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
optional("javax.persistence:persistence-api:1.0")
optional("javax.validation:validation-api:1.0.0.GA")
optional("org.beanshell:bsh:2.0b4")
optional("org.codehaus.groovy:groovy-all:1.8.8")
optional("org.jruby:jruby:1.6.5.1")
optional("joda-time:joda-time:2.1")
optional("org.slf4j:slf4j-api:${slf4jVersion}")
optional("javax.validation:validation-api:1.0.0.GA")
optional("org.hibernate:hibernate-validator:4.3.0.Final")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
@@ -319,6 +338,9 @@ project("spring-context") {
testCompile("javax.inject:javax.inject-tck:1")
}
// pick up RmiInvocationWrapperRTD.xml in src/main
sourceSets.main.resources.srcDirs += "src/main/java"
test {
jvmArgs = ["-disableassertions:org.aspectj.weaver.UnresolvedType"] // SPR-7989
}
@@ -326,6 +348,7 @@ project("spring-context") {
project("spring-tx") {
description = "Spring Transaction"
dependencies {
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
optional(project(":spring-aop"))
@@ -355,10 +378,8 @@ project("spring-oxm") {
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional(project(":spring-context")) // for Jaxb2Marshaller
compile("commons-lang:commons-lang:2.5")
testCompile(project(":spring-context"))
optional("com.thoughtworks.xstream:xstream:1.3.1")
optional("com.sun.xml.bind:jaxb-impl:2.1.7")
optional("org.jibx:jibx-run:1.2.3")
optional("org.apache.xmlbeans:xmlbeans:2.4.0")
optional("org.codehaus.castor:castor-xml:1.3.2")
@@ -373,6 +394,7 @@ project("spring-oxm") {
project("spring-jms") {
description = "Spring JMS"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -391,6 +413,7 @@ project("spring-jms") {
project("spring-jdbc") {
description = "Spring JDBC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -407,6 +430,7 @@ project("spring-jdbc") {
project("spring-context-support") {
description = "Spring Context Support"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
@@ -443,8 +467,6 @@ project("spring-web") {
compile(project(":spring-context"))
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
compile("aopalliance:aopalliance:1.0")
optional("com.caucho:hessian:3.2.1")
optional("rome:rome:1.0")
optional("javax.el:el-api:1.0")
optional("javax.faces:jsf-api:1.2_08")
provided("javax.portlet:portlet-api:2.0")
@@ -453,6 +475,8 @@ project("spring-web") {
optional("javax.xml:jaxrpc-api:1.1")
provided("javax.xml.soap:saaj-api:1.3")
provided("javax.activation:activation:1.1")
optional("com.caucho:hessian:3.2.1")
optional("rome:rome:1.0")
optional("commons-fileupload:commons-fileupload:1.2")
optional("commons-io:commons-io:1.3")
optional("commons-httpclient:commons-httpclient:3.1")
@@ -487,16 +511,16 @@ project("spring-orm") {
dependencies {
compile("aopalliance:aopalliance:1.0")
optional("javax.persistence:persistence-api:1.0")
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
optional("org.hibernate:hibernate-core:3.3.2.GA")
optional("org.hibernate:hibernate-annotations:3.4.0.GA")
optional("org.hibernate:hibernate-entitymanager:3.4.0.GA")
optional("org.apache.openjpa:openjpa:1.1.0")
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
optional("toplink.essentials:toplink-essentials:2.0-41b")
optional("javax.jdo:jdo-api:3.0")
optional("org.apache.ibatis:ibatis-sqlmap:2.3.4.726")
optional("javax.persistence:persistence-api:1.0")
provided("javax.servlet:servlet-api:2.5")
testCompile("javax.servlet:javax.servlet-api:3.0.1")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
@@ -517,11 +541,12 @@ project("spring-orm") {
project("spring-orm-hibernate4") {
description = "Spring Object/Relational Mapping - Hibernate 4 support"
merge.into = project(":spring-orm")
dependencies {
provided(project(":spring-tx"))
provided(project(":spring-jdbc"))
optional("org.hibernate:hibernate-core:4.1.0.Final")
optional("org.hibernate:hibernate-entitymanager:4.1.0.Final")
optional("org.hibernate:hibernate-core:4.1.9.Final")
optional("org.hibernate:hibernate-entitymanager:4.1.9.Final")
optional(project(":spring-web"))
optional("javax.servlet:servlet-api:2.5")
}
@@ -529,6 +554,7 @@ project("spring-orm-hibernate4") {
project("spring-webmvc") {
description = "Spring Web MVC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-expression"))
@@ -541,7 +567,6 @@ project("spring-webmvc") {
optional("org.apache.tiles:tiles-core:2.1.2")
optional("org.apache.tiles:tiles-jsp:2.1.2")
optional("org.apache.tiles:tiles-servlet:2.1.2")
optional("velocity-tools:velocity-tools-view:1.4")
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
optional("org.apache.poi:poi:3.0.2-FINAL")
optional("com.lowagie:itext:2.1.7")
@@ -550,6 +575,7 @@ project("spring-webmvc") {
}
optional("rome:rome:1.0")
optional("velocity:velocity:1.5")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.15")
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
@@ -588,6 +614,7 @@ project("spring-webmvc") {
project("spring-webmvc-tiles3") {
description = "Spring Framework Tiles3 Integration"
merge.into = project(":spring-webmvc")
dependencies {
provided(project(":spring-context"))
provided(project(":spring-web"))
@@ -618,6 +645,7 @@ project("spring-webmvc-tiles3") {
project("spring-webmvc-portlet") {
description = "Spring Web Portlet"
dependencies {
provided("javax.servlet:servlet-api:2.5")
provided("javax.portlet:portlet-api:2.0")
@@ -636,21 +664,6 @@ project("spring-webmvc-portlet") {
project("spring-test") {
description = "Spring TestContext Framework"
task testNG(type: Test) {
useTestNG()
// "TestCase" classes are run by other test classes, not the build.
exclude "**/*TestCase.class"
// Generate TestNG reports alongside JUnit reports.
testReport true
}
test {
dependsOn testNG
useJUnit()
// "TestCase" classes are run by other test classes, not the build.
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
}
dependencies {
compile(project(":spring-core"))
optional(project(":spring-beans"))
@@ -675,6 +688,26 @@ project("spring-test") {
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
}
task testNG(type: Test) {
useTestNG()
scanForTestClasses = false
include "**/testng/*.*"
exclude "**/FailingBeforeAndAfterMethodsTests.class"
// "TestCase" classes are run by other test classes, not the build.
exclude "**/*TestCase.class"
// Generate TestNG reports alongside JUnit reports.
testReport true
}
test {
dependsOn testNG
useJUnit()
exclude "**/testng/*.*"
// "TestCase" classes are run by other test classes, not the build.
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
}
}
project("spring-test-mvc") {
@@ -695,11 +728,9 @@ project("spring-test-mvc") {
testCompile(project(":spring-context-support"))
testCompile(project(":spring-oxm"))
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
testCompile("cglib:cglib-nodep:2.2")
testCompile("rome:rome:1.0")
testCompile("javax.activation:activation:1.1")
testCompile("javax.mail:mail:1.4")
testCompile("javax.xml.bind:jaxb-api:2.2.6")
testCompile("org.apache.tiles:tiles-request-api:1.0.1")
testCompile("org.apache.tiles:tiles-api:3.0.1")
testCompile("org.apache.tiles:tiles-core:3.0.1") {
@@ -730,6 +761,7 @@ project("spring-struts") {
project("spring-aspects") {
description = "Spring Aspects"
apply from: "aspects.gradle"
dependencies {
optional(project(":spring-beans")) // for @Configurable support
optional(project(":spring-aop")) // for @Async support
@@ -747,6 +779,7 @@ project("spring-aspects") {
compile(project(":spring-beans")) // for "p" namespace visibility
testCompile(project(":spring-test"))
}
eclipse.project {
natures += "org.eclipse.ajdt.ui.ajnature"
buildCommands = [new org.gradle.plugins.ide.eclipse.model.
@@ -754,12 +787,47 @@ project("spring-aspects") {
}
}
project("spring-framework-bom") {
description = "Spring Framework (Bill of Materials)"
configurations.archives.artifacts.clear()
artifacts {
// work around GRADLE-2406 by attaching text artifact
archives(file("spring-framework-bom.txt"))
}
install {
repositories.mavenInstaller {
pom.whenConfigured {
packaging = "pom"
withXml {
asNode().children().last() + {
delegate.dependencyManagement {
delegate.dependencies {
parent.subprojects.sort { "$it.name" }.each { p ->
if (p.hasProperty("merge") && p.merge.into == null && p != project) {
delegate.dependency {
delegate.groupId(p.group)
delegate.artifactId(p.name)
delegate.version(p.version)
}
}
}
}
}
}
}
}
}
}
}
configure(rootProject) {
description = "Spring Framework"
apply plugin: "docbook-reference"
apply plugin: "groovy"
apply plugin: "detect-split-packages"
// apply plugin: "detect-split-packages"
apply from: "${gradleScriptDir}/jdiff.gradle"
reference {
@@ -767,9 +835,11 @@ configure(rootProject) {
pdfFilename = "spring-framework-reference.pdf"
}
detectSplitPackages {
projectsToScan -= project(":spring-instrument-tomcat")
}
// TODO: DetectSplitPackagesPlugin fails in line 154 due to method not found on java.io.File.
// TODO: Possibly related to user rights or OS differences on OpenJDK 8; works fine on JDK 7.
// detectSplitPackages {
// projectsToScan -= project(":spring-instrument-tomcat")
// }
// don't publish the default jar for the root project
configurations.archives.artifacts.clear()
@@ -786,7 +856,7 @@ configure(rootProject) {
testCompile(project(":spring-web"))
testCompile(project(":spring-webmvc-portlet"))
testCompile(project(":spring-orm"))
testCompile("org.hibernate:hibernate-core:4.1.0.Final")
testCompile("org.hibernate:hibernate-core:4.1.9.Final")
testCompile("javax.servlet:servlet-api:2.5")
testCompile("javax.portlet:portlet-api:2.0")
testCompile("javax.inject:javax.inject:1")
@@ -812,6 +882,9 @@ configure(rootProject) {
options.stylesheetFile = file("src/api/stylesheet.css")
options.splitIndex = true
options.links(project.ext.javadocLinks)
if(JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
source subprojects.collect { project ->
project.sourceSets.main.allJava
@@ -822,7 +895,7 @@ configure(rootProject) {
doFirst {
classpath = files(
// ensure servlet 3.x and Hibernate 4.x have precedence on the Javadoc
// ensure Servlet 3.x and Hibernate 4.x have precedence on the Javadoc
// classpath over their respective 2.5 and 3.x variants
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
@@ -959,7 +1032,7 @@ configure(rootProject) {
task wrapper(type: Wrapper) {
description = "Generates gradlew[.bat] scripts"
gradleVersion = "1.3"
gradleVersion = "1.6"
doLast() {
def gradleOpts = "-XX:MaxPermSize=1024m -Xmx1024m"
@@ -49,7 +49,7 @@ import org.gradle.api.tasks.TaskAction
public class DetectSplitPackagesPlugin implements Plugin<Project> {
public void apply(Project project) {
def tasks = project.tasks
Task detectSplitPackages = tasks.add("detectSplitPackages", DetectSplitPackagesTask.class)
Task detectSplitPackages = tasks.create("detectSplitPackages", DetectSplitPackagesTask.class)
if (tasks.asMap.containsKey("check")) {
tasks.getByName("check").dependsOn detectSplitPackages
}
@@ -67,8 +67,8 @@ class MergePlugin implements Plugin<Project> {
project.plugins.apply(IdeaPlugin)
MergeModel model = project.extensions.create("merge", MergeModel)
project.configurations.add("merging")
Configuration runtimeMerge = project.configurations.add("runtimeMerge")
project.configurations.create("merging")
Configuration runtimeMerge = project.configurations.create("runtimeMerge")
// Ensure the IDE can reference merged projects
project.eclipse.classpath.plusConfigurations += [runtimeMerge]
@@ -121,7 +121,7 @@ class MergePlugin implements Plugin<Project> {
project.configurations.each { configuration ->
Conf2ScopeMapping mapping = project.conf2ScopeMappings.getMapping([configuration])
if(mapping.scope) {
Configuration intoConfiguration = project.merge.into.configurations.add(
Configuration intoConfiguration = project.merge.into.configurations.create(
project.name + "-" + configuration.name)
configuration.excludeRules.each {
configuration.exclude([
+1 -1
View File
@@ -1 +1 @@
version=3.2.3.BUILD-SNAPSHOT
version=3.2.6.RELEASE
+1 -1
View File
@@ -43,7 +43,7 @@ def customizePom(pom, gradleProject) {
developer {
id = "jhoeller"
name = "Juergen Hoeller"
email = "jhoeller@vmware.com"
email = "jhoeller@gopivotal.com"
}
}
}
Binary file not shown.
+4 -4
View File
@@ -1,6 +1,6 @@
#Wed Nov 28 09:14:59 PST 2012
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
#Tue Jul 30 09:29:28 PDT 2013
zipStoreBase=GRADLE_USER_HOME
distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip
distributionBase=GRADLE_USER_HOME
+1
View File
@@ -22,6 +22,7 @@ include "spring-web"
include "spring-webmvc"
include "spring-webmvc-portlet"
include "spring-webmvc-tiles3"
include "spring-framework-bom"
// Exposes gradle buildSrc for IDE support
include "buildSrc"
@@ -45,43 +45,41 @@ public class AspectJWeaverMessageHandler implements IMessageHandler {
private static final String AJ_ID = "[AspectJ] ";
private static final Log LOGGER = LogFactory.getLog("AspectJ Weaver");
private static final Log logger = LogFactory.getLog("AspectJ Weaver");
public boolean handleMessage(IMessage message) throws AbortException {
Kind messageKind = message.getKind();
if (messageKind == IMessage.DEBUG) {
if (LOGGER.isDebugEnabled() || LOGGER.isTraceEnabled()) {
LOGGER.debug(makeMessageFor(message));
if (logger.isDebugEnabled()) {
logger.debug(makeMessageFor(message));
return true;
}
}
else if ((messageKind == IMessage.INFO) || (messageKind == IMessage.WEAVEINFO)) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(makeMessageFor(message));
else if (messageKind == IMessage.INFO || messageKind == IMessage.WEAVEINFO) {
if (logger.isInfoEnabled()) {
logger.info(makeMessageFor(message));
return true;
}
}
else if (messageKind == IMessage.WARNING) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(makeMessageFor(message));
if (logger.isWarnEnabled()) {
logger.warn(makeMessageFor(message));
return true;
}
}
else if (messageKind == IMessage.ERROR) {
if (LOGGER.isErrorEnabled()) {
LOGGER.error(makeMessageFor(message));
if (logger.isErrorEnabled()) {
logger.error(makeMessageFor(message));
return true;
}
}
else if (messageKind == IMessage.ABORT) {
if (LOGGER.isFatalEnabled()) {
LOGGER.fatal(makeMessageFor(message));
if (logger.isFatalEnabled()) {
logger.fatal(makeMessageFor(message));
return true;
}
}
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj.annotation;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.util.ClassUtils;
@@ -105,7 +106,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
}
Order order = type.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(type, Order.class);
if (order != null) {
return order.value();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj.annotation;
import org.springframework.aop.aspectj.SimpleAspectInstanceFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
/**
@@ -58,7 +59,7 @@ public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstan
*/
@Override
protected int getOrderForAspectClass(Class<?> aspectClass) {
Order order = aspectClass.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
if (order != null) {
return order.value();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.aop.aspectj.annotation;
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
/**
@@ -59,7 +60,7 @@ public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspect
*/
@Override
protected int getOrderForAspectClass(Class<?> aspectClass) {
Order order = aspectClass.getAnnotation(Order.class);
Order order = AnnotationUtils.findAnnotation(aspectClass, Order.class);
if (order != null) {
return order.value();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,13 +52,13 @@ public interface Advised extends TargetClassAware {
* Return the interfaces proxied by the AOP proxy. Will not
* include the target class, which may also be proxied.
*/
Class[] getProxiedInterfaces();
Class<?>[] getProxiedInterfaces();
/**
* Determine whether the given interface is proxied.
* @param intf the interface to check
*/
boolean isInterfaceProxied(Class intf);
boolean isInterfaceProxied(Class<?> intf);
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -158,7 +158,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* @see #setTargetSource
* @see #setTarget
*/
public void setTargetClass(Class targetClass) {
public void setTargetClass(Class<?> targetClass) {
this.targetSource = EmptyTargetSource.forClass(targetClass);
}
@@ -194,7 +194,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
/**
* Set the interfaces to be proxied.
*/
public void setInterfaces(Class[] interfaces) {
public void setInterfaces(Class<?>... interfaces) {
Assert.notNull(interfaces, "Interfaces must not be null");
this.interfaces.clear();
for (Class ifc : interfaces) {
@@ -206,7 +206,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* Add a new proxied interface.
* @param intf the additional interface to proxy
*/
public void addInterface(Class intf) {
public void addInterface(Class<?> intf) {
Assert.notNull(intf, "Interface must not be null");
if (!intf.isInterface()) {
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
@@ -224,15 +224,15 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
* @return {@code true} if the interface was removed; {@code false}
* if the interface was not found and hence could not be removed
*/
public boolean removeInterface(Class intf) {
public boolean removeInterface(Class<?> intf) {
return this.interfaces.remove(intf);
}
public Class[] getProxiedInterfaces() {
public Class<?>[] getProxiedInterfaces() {
return this.interfaces.toArray(new Class[this.interfaces.size()]);
}
public boolean isInterfaceProxied(Class intf) {
public boolean isInterfaceProxied(Class<?> intf) {
for (Class proxyIntf : this.interfaces) {
if (intf.isAssignableFrom(proxyIntf)) {
return true;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,17 @@ import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.AopInvocationException;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.RawTargetAccess;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
@@ -34,18 +45,7 @@ import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.AopInvocationException;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.RawTargetAccess;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.transform.impl.MemorySafeUndeclaredThrowableStrategy;
import org.springframework.core.SmartClassLoader;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -181,7 +181,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setInterceptDuringConstruction(false);
@@ -253,11 +253,14 @@ final class CglibAopProxy implements AopProxy, Serializable {
* for each one found.
*/
private void doValidateClass(Class<?> proxySuperClass) {
Method[] methods = proxySuperClass.getMethods();
for (Method method : methods) {
if (!Object.class.equals(method.getDeclaringClass()) && Modifier.isFinal(method.getModifiers())) {
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
"All calls to this method via a proxy will be routed directly to the proxy.");
if (logger.isWarnEnabled()) {
Method[] methods = proxySuperClass.getMethods();
for (Method method : methods) {
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
Modifier.isFinal(method.getModifiers())) {
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
"All calls to this method via a proxy will be routed directly to the proxy.");
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
* <p>No target, only interfaces. Must add interceptors.
* @param proxyInterfaces the interfaces that the proxy should implement
*/
public ProxyFactory(Class[] proxyInterfaces) {
public ProxyFactory(Class<?>... proxyInterfaces) {
setInterfaces(proxyInterfaces);
}
@@ -69,7 +69,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
* @param proxyInterface the interface that the proxy should implement
* @param interceptor the interceptor that the proxy should invoke
*/
public ProxyFactory(Class proxyInterface, Interceptor interceptor) {
public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
addInterface(proxyInterface);
addAdvice(interceptor);
}
@@ -80,7 +80,7 @@ public class ProxyFactory extends ProxyCreatorSupport {
* @param proxyInterface the interface that the proxy should implement
* @param targetSource the TargetSource that the proxy should invoke
*/
public ProxyFactory(Class proxyInterface, TargetSource targetSource) {
public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
addInterface(proxyInterface);
setTargetSource(targetSource);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,24 +81,32 @@ public class BeanFactoryAdvisorRetrievalHelper {
List<Advisor> advisors = new LinkedList<Advisor>();
for (String name : advisorNames) {
if (isEligibleBean(name) && !this.beanFactory.isCurrentlyInCreation(name)) {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring currently created advisor '" + name + "': " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
throw ex;
}
}
}
@@ -87,7 +87,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
/**
* Determine the specific executor to use when executing the given method.
* @return the executor to use (never {@code null})
* @return the executor to use (or {@code null}, but just if no default executor has been set)
*/
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
AsyncTaskExecutor executor = this.executors.get(method);
@@ -101,8 +101,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
this.beanFactory, Executor.class, qualifier);
}
else if (executorToUse == null) {
throw new IllegalStateException("No executor qualifier specified and no default executor set on " +
getClass().getSimpleName() + " either");
return null;
}
executor = (executorToUse instanceof AsyncTaskExecutor ?
(AsyncTaskExecutor) executorToUse : new TaskExecutorAdapter(executorToUse));
@@ -82,7 +82,13 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
Future<?> result = determineAsyncExecutor(specificMethod).submit(
AsyncTaskExecutor executor = determineAsyncExecutor(specificMethod);
if (executor == null) {
throw new IllegalStateException(
"No executor specified and no default executor set on AsyncExecutionInterceptor either");
}
Future<?> result = executor.submit(
new Callable<Object>() {
public Object call() throws Exception {
try {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ public abstract class ScopedProxyUtils {
/**
* Generates a scoped proxy for the supplied target bean, registering the target
* Generate a scoped proxy for the supplied target bean, registering the target
* bean with an internal name and setting 'targetBeanName' on the scoped proxy.
* @param definition the original bean definition
* @param registry the bean definition registry
@@ -50,20 +50,20 @@ public abstract class ScopedProxyUtils {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setOriginatingBeanDefinition(definition.getBeanDefinition());
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String targetBeanName = getTargetBeanName(originalBeanName);
proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -102,8 +102,9 @@ public abstract class MethodMatchers {
@SuppressWarnings("serial")
private static class UnionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
private MethodMatcher mm1;
private MethodMatcher mm2;
private final MethodMatcher mm1;
private final MethodMatcher mm2;
public UnionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
Assert.notNull(mm1, "First MethodMatcher must not be null");
@@ -168,6 +169,7 @@ public abstract class MethodMatchers {
private static class ClassFilterAwareUnionMethodMatcher extends UnionMethodMatcher {
private final ClassFilter cf1;
private final ClassFilter cf2;
public ClassFilterAwareUnionMethodMatcher(MethodMatcher mm1, ClassFilter cf1, MethodMatcher mm2, ClassFilter cf2) {
@@ -191,11 +193,17 @@ public abstract class MethodMatchers {
if (this == other) {
return true;
}
if (!(other instanceof ClassFilterAwareUnionMethodMatcher)) {
if (!super.equals(other)) {
return false;
}
ClassFilterAwareUnionMethodMatcher that = (ClassFilterAwareUnionMethodMatcher) other;
return (this.cf1.equals(that.cf1) && this.cf2.equals(that.cf2) && super.equals(other));
ClassFilter otherCf1 = ClassFilter.TRUE;
ClassFilter otherCf2 = ClassFilter.TRUE;
if (other instanceof ClassFilterAwareUnionMethodMatcher) {
ClassFilterAwareUnionMethodMatcher cfa = (ClassFilterAwareUnionMethodMatcher) other;
otherCf1 = cfa.cf1;
otherCf2 = cfa.cf2;
}
return (this.cf1.equals(otherCf1) && this.cf2.equals(otherCf2));
}
}
@@ -206,8 +214,9 @@ public abstract class MethodMatchers {
@SuppressWarnings("serial")
private static class IntersectionMethodMatcher implements IntroductionAwareMethodMatcher, Serializable {
private MethodMatcher mm1;
private MethodMatcher mm2;
private final MethodMatcher mm1;
private final MethodMatcher mm2;
public IntersectionMethodMatcher(MethodMatcher mm1, MethodMatcher mm2) {
Assert.notNull(mm1, "First MethodMatcher must not be null");
@@ -43,6 +43,7 @@ public final class MethodMatchersTests {
private final Method IOTHER_ABSQUATULATE;
public MethodMatchersTests() throws Exception {
EXCEPTION_GETMESSAGE = Exception.class.getMethod("getMessage", (Class[]) null);
ITESTBEAN_GETAGE = ITestBean.class.getMethod("getAge", (Class[]) null);
@@ -50,6 +51,7 @@ public final class MethodMatchersTests {
IOTHER_ABSQUATULATE = IOther.class.getMethod("absquatulate", (Class[]) null);
}
@Test
public void testDefaultMatchesAll() throws Exception {
MethodMatcher defaultMm = MethodMatcher.TRUE;
@@ -99,23 +101,33 @@ public final class MethodMatchersTests {
assertTrue("Matched setAge method", union.matches(ITESTBEAN_SETAGE, TestBean.class));
assertTrue("Matched getAge method", union.matches(ITESTBEAN_GETAGE, TestBean.class));
assertFalse("Didn't matched absquatulate method", union.matches(IOTHER_ABSQUATULATE, TestBean.class));
}
@Test
public void testUnionEquals() {
MethodMatcher first = MethodMatchers.union(MethodMatcher.TRUE, MethodMatcher.TRUE);
MethodMatcher second = new ComposablePointcut(MethodMatcher.TRUE).union(new ComposablePointcut(MethodMatcher.TRUE)).getMethodMatcher();
assertTrue(first.equals(second));
assertTrue(second.equals(first));
}
public static class StartsWithMatcher extends StaticMethodMatcher {
private String prefix;
private final String prefix;
public StartsWithMatcher(String s) {
this.prefix = s;
}
@Override
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith(prefix);
}
}
private static class TestDynamicMethodMatcherWhichMatches extends DynamicMethodMatcher {
@Override
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return true;
@@ -123,6 +135,7 @@ public final class MethodMatchersTests {
}
private static class TestDynamicMethodMatcherWhichDoesNotMatch extends DynamicMethodMatcher {
@Override
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return false;
+4 -4
View File
@@ -12,8 +12,8 @@ configurations {
tasks.getByName("idea").onlyIf { false }
tasks.getByName("ideaModule").onlyIf { false }
task compileJava(overwrite: true) {
dependsOn JavaPlugin.PROCESS_RESOURCES_TASK_NAME
compileJava {
actions = []
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileJava")
def outputDir = project.sourceSets.main.output.classesDir
@@ -44,8 +44,8 @@ task compileJava(overwrite: true) {
}
}
task compileTestJava(overwrite: true) {
dependsOn JavaPlugin.PROCESS_TEST_RESOURCES_TASK_NAME
compileTestJava {
actions = []
dependsOn configurations.ajc.getTaskDependencyFromProjectDependency(true, "compileTestJava")
dependsOn jar
@@ -97,36 +97,34 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
public void verify() {
if (verified != calls.size()) {
throw new IllegalStateException("Expected " + calls.size()
+ " calls, received " + verified);
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
}
}
/**
* Validate the call and provide the expected return value
* @param lastSig
* @param args
* @return
* Validate the call and provide the expected return value.
*/
public Object respond(String lastSig, Object[] args) {
Call call = nextCall();
CallResponse responseType = call.responseType;
if (responseType == CallResponse.return_) {
return call.returnValue(lastSig, args);
} else if(responseType == CallResponse.throw_) {
return (RuntimeException)call.throwException(lastSig, args);
} else if(responseType == CallResponse.nothing) {
}
else if (responseType == CallResponse.throw_) {
return call.throwException(lastSig, args);
}
else if (responseType == CallResponse.nothing) {
// do nothing
}
throw new IllegalStateException("Behavior of " + call + " not specified");
}
private Call nextCall() {
if (verified > calls.size() - 1) {
throw new IllegalStateException("Expected " + calls.size()
+ " calls, received " + verified);
verified++;
if (verified > calls.size()) {
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
}
return calls.get(verified++);
return calls.get(verified);
}
public void expectCall(String lastSig, Object lastArgs[]) {
@@ -171,7 +169,8 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
// Return value doesn't matter
return null;
} else {
}
else {
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ public abstract class BeanUtils {
private static final Log logger = LogFactory.getLog(BeanUtils.class);
// using WeakHashMap as a Set
// Effectively using a WeakHashMap as a Set
private static final Map<Class<?>, Boolean> unknownEditorTypes =
Collections.synchronizedMap(new WeakHashMap<Class<?>, Boolean>());
@@ -127,7 +127,7 @@ public abstract class BeanUtils {
@SuppressWarnings("unchecked")
public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo) throws BeanInstantiationException {
Assert.isAssignable(assignableTo, clazz);
return (T)instantiateClass(clazz);
return (T) instantiateClass(clazz);
}
/**
@@ -199,7 +199,7 @@ public abstract class BeanUtils {
* @return the Method object, or {@code null} if not found
* @see Class#getDeclaredMethod
*/
public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes) {
public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
try {
return clazz.getDeclaredMethod(methodName, paramTypes);
}
@@ -281,7 +281,7 @@ public abstract class BeanUtils {
}
else {
if (targetMethod.getParameterTypes().length == numParams) {
// Additional candidate with same length.
// Additional candidate with same length
numMethodsFoundWithCurrentMinimumArgs++;
}
}
@@ -317,10 +317,8 @@ public abstract class BeanUtils {
public static Method resolveSignature(String signature, Class<?> clazz) {
Assert.hasText(signature, "'signature' must not be empty");
Assert.notNull(clazz, "Class must not be null");
int firstParen = signature.indexOf("(");
int lastParen = signature.indexOf(")");
if (firstParen > -1 && lastParen == -1) {
throw new IllegalArgumentException("Invalid method signature '" + signature +
"': expected closing ')' for args list");
@@ -336,7 +334,7 @@ public abstract class BeanUtils {
String methodName = signature.substring(0, firstParen);
String[] parameterTypeNames =
StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));
Class<?>[] parameterTypes = new Class[parameterTypeNames.length];
Class<?>[] parameterTypes = new Class<?>[parameterTypeNames.length];
for (int i = 0; i < parameterTypeNames.length; i++) {
String parameterTypeName = parameterTypeNames[i].trim();
try {
@@ -455,7 +453,7 @@ public abstract class BeanUtils {
* @param beanClasses the classes to check against
* @return the property type, or {@code Object.class} as fallback
*/
public static Class<?> findPropertyType(String propertyName, Class<?>[] beanClasses) {
public static Class<?> findPropertyType(String propertyName, Class<?>... beanClasses) {
if (beanClasses != null) {
for (Class<?> beanClass : beanClasses) {
PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName);
@@ -475,8 +473,7 @@ public abstract class BeanUtils {
*/
public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) {
if (pd instanceof GenericTypeAwarePropertyDescriptor) {
return new MethodParameter(
((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter());
return new MethodParameter(((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter());
}
else {
return new MethodParameter(pd.getWriteMethod(), 0);
@@ -528,7 +525,7 @@ public abstract class BeanUtils {
* @see BeanWrapper
*/
public static void copyProperties(Object source, Object target) throws BeansException {
copyProperties(source, target, null, null);
copyProperties(source, target, null, (String[]) null);
}
/**
@@ -545,10 +542,8 @@ public abstract class BeanUtils {
* @throws BeansException if the copying failed
* @see BeanWrapper
*/
public static void copyProperties(Object source, Object target, Class<?> editable)
throws BeansException {
copyProperties(source, target, editable, null);
public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException {
copyProperties(source, target, editable, (String[]) null);
}
/**
@@ -565,9 +560,7 @@ public abstract class BeanUtils {
* @throws BeansException if the copying failed
* @see BeanWrapper
*/
public static void copyProperties(Object source, Object target, String[] ignoreProperties)
throws BeansException {
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
copyProperties(source, target, null, ignoreProperties);
}
@@ -583,7 +576,7 @@ public abstract class BeanUtils {
* @throws BeansException if the copying failed
* @see BeanWrapper
*/
private static void copyProperties(Object source, Object target, Class<?> editable, String[] ignoreProperties)
private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties)
throws BeansException {
Assert.notNull(source, "Source must not be null");
@@ -601,24 +594,27 @@ public abstract class BeanUtils {
List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;
for (PropertyDescriptor targetPd : targetPds) {
if (targetPd.getWriteMethod() != null &&
(ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null && sourcePd.getReadMethod() != null) {
try {
Method readMethod = sourcePd.getReadMethod();
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null &&
writeMethod.getParameterTypes()[0].isAssignableFrom(readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
Object value = readMethod.invoke(source);
Method writeMethod = targetPd.getWriteMethod();
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
throw new FatalBeanException("Could not copy properties from source to target", ex);
}
}
}
@@ -76,7 +76,7 @@ public class CachedIntrospectionResults {
* Needs to be a WeakHashMap with WeakReferences as values to allow
* for proper garbage collection in case of multiple class loaders.
*/
static final Map<Class, Object> classCache = new WeakHashMap<Class, Object>();
static final Map<Class<?>, Object> classCache = new WeakHashMap<Class<?>, Object>();
/**
@@ -101,15 +101,14 @@ public class CachedIntrospectionResults {
/**
* Clear the introspection cache for the given ClassLoader, removing the
* introspection results for all classes underneath that ClassLoader,
* and deregistering the ClassLoader (and any of its children) from the
* acceptance list.
* introspection results for all classes underneath that ClassLoader, and
* removing the ClassLoader (and its children) from the acceptance list.
* @param classLoader the ClassLoader to clear the cache for
*/
public static void clearClassLoader(ClassLoader classLoader) {
synchronized (classCache) {
for (Iterator<Class> it = classCache.keySet().iterator(); it.hasNext();) {
Class beanClass = it.next();
for (Iterator<Class<?>> it = classCache.keySet().iterator(); it.hasNext();) {
Class<?> beanClass = it.next();
if (isUnderneathClassLoader(beanClass.getClassLoader(), classLoader)) {
it.remove();
}
@@ -127,21 +126,20 @@ public class CachedIntrospectionResults {
/**
* Create CachedIntrospectionResults for the given bean class.
* <P>We don't want to use synchronization here. Object references are atomic,
* so we can live with doing the occasional unnecessary lookup at startup only.
* @param beanClass the bean class to analyze
* @return the corresponding CachedIntrospectionResults
* @throws BeansException in case of introspection failure
*/
static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {
@SuppressWarnings("unchecked")
static CachedIntrospectionResults forClass(Class<?> beanClass) throws BeansException {
CachedIntrospectionResults results;
Object value;
synchronized (classCache) {
value = classCache.get(beanClass);
}
if (value instanceof Reference) {
Reference ref = (Reference) value;
results = (CachedIntrospectionResults) ref.get();
Reference<CachedIntrospectionResults> ref = (Reference<CachedIntrospectionResults>) value;
results = ref.get();
}
else {
results = (CachedIntrospectionResults) value;
@@ -225,7 +223,7 @@ public class CachedIntrospectionResults {
* @param beanClass the bean class to analyze
* @throws BeansException in case of introspection failure
*/
private CachedIntrospectionResults(Class beanClass) throws BeansException {
private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
try {
if (logger.isTraceEnabled()) {
logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
@@ -248,7 +246,7 @@ public class CachedIntrospectionResults {
// garbage collection on class loader shutdown - we cache it here anyway,
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
// Introspector does not use WeakReferences as values of its WeakHashMap!
Class classToFlush = beanClass;
Class<?> classToFlush = beanClass;
do {
Introspector.flushFromCaches(classToFlush);
classToFlush = classToFlush.getSuperclass();
@@ -263,8 +261,9 @@ public class CachedIntrospectionResults {
// This call is slow so we do it once.
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (Class.class.equals(beanClass) && "classLoader".equals(pd.getName())) {
// Ignore Class.getClassLoader() method - nobody needs to bind to that
if (Class.class.equals(beanClass) &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
continue;
}
if (logger.isTraceEnabled()) {
@@ -286,7 +285,7 @@ public class CachedIntrospectionResults {
return this.beanInfo;
}
Class getBeanClass() {
Class<?> getBeanClass() {
return this.beanInfo.getBeanDescriptor().getBeanClass();
}
@@ -314,7 +313,7 @@ public class CachedIntrospectionResults {
return pds;
}
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class beanClass, PropertyDescriptor pd) {
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class<?> beanClass, PropertyDescriptor pd) {
try {
return new GenericTypeAwarePropertyDescriptor(beanClass, pd.getName(), pd.getReadMethod(),
pd.getWriteMethod(), pd.getPropertyEditorClass());
@@ -17,7 +17,6 @@
package org.springframework.beans;
import java.awt.Image;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.EventSetDescriptor;
@@ -26,10 +25,8 @@ import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -44,7 +41,7 @@ import static org.springframework.beans.PropertyDescriptorUtils.*;
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
* and/or non-void returning setter methods. For example:
* <pre>{@code
* <pre class="code">
* public class Bean {
* private Foo foo;
*
@@ -56,7 +53,7 @@ import static org.springframework.beans.PropertyDescriptorUtils.*;
* this.foo = foo;
* return this;
* }
* }}</pre>
* }</pre>
* The standard JavaBeans {@code Introspector} will discover the {@code getFoo} read
* method, but will bypass the {@code #setFoo(Foo)} write method, because its non-void
* returning signature does not comply with the JavaBeans specification.
@@ -84,8 +81,8 @@ class ExtendedBeanInfo implements BeanInfo {
/**
* Wrap the given {@link BeanInfo} instance; copy all its existing property descriptors
* locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed} or
* {@link SimpleNonIndexedPropertyDescriptor non-indexed} {@code PropertyDescriptor}
* locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed}
* or {@link SimplePropertyDescriptor non-indexed} {@code PropertyDescriptor}
* variant that bypasses default JDK weak/soft reference management; then search
* through its method descriptors to find any non-void returning write methods and
* update or create the corresponding {@link PropertyDescriptor} for each one found.
@@ -96,15 +93,16 @@ class ExtendedBeanInfo implements BeanInfo {
*/
public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException {
this.delegate = delegate;
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
new SimpleNonIndexedPropertyDescriptor(pd));
new SimplePropertyDescriptor(pd));
}
for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) {
handleCandidateWriteMethod(method);
MethodDescriptor[] methodDescriptors = delegate.getMethodDescriptors();
if (methodDescriptors != null) {
for (Method method : findCandidateWriteMethods(methodDescriptors)) {
handleCandidateWriteMethod(method);
}
}
}
@@ -132,58 +130,44 @@ class ExtendedBeanInfo implements BeanInfo {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
int nParams = parameterTypes.length;
if (methodName.length() > 3 && methodName.startsWith("set") &&
Modifier.isPublic(method.getModifiers()) &&
(
!void.class.isAssignableFrom(method.getReturnType()) ||
Modifier.isStatic(method.getModifiers())
) &&
(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)))) {
return true;
}
return false;
return methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
(!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)));
}
private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
int nParams = method.getParameterTypes().length;
String propertyName = propertyNameFor(method);
Class<?> propertyType = method.getParameterTypes()[nParams-1];
PropertyDescriptor existingPD = findExistingPropertyDescriptor(propertyName, propertyType);
PropertyDescriptor existingPd = findExistingPropertyDescriptor(propertyName, propertyType);
if (nParams == 1) {
if (existingPD == null) {
this.propertyDescriptors.add(
new SimpleNonIndexedPropertyDescriptor(propertyName, null, method));
if (existingPd == null) {
this.propertyDescriptors.add(new SimplePropertyDescriptor(propertyName, null, method));
}
else {
existingPD.setWriteMethod(method);
existingPd.setWriteMethod(method);
}
}
else if (nParams == 2) {
if (existingPD == null) {
if (existingPd == null) {
this.propertyDescriptors.add(
new SimpleIndexedPropertyDescriptor(
propertyName, null, null, null, method));
new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
}
else if (existingPD instanceof IndexedPropertyDescriptor) {
((IndexedPropertyDescriptor)existingPD).setIndexedWriteMethod(method);
else if (existingPd instanceof IndexedPropertyDescriptor) {
((IndexedPropertyDescriptor) existingPd).setIndexedWriteMethod(method);
}
else {
this.propertyDescriptors.remove(existingPD);
this.propertyDescriptors.add(
new SimpleIndexedPropertyDescriptor(
propertyName, existingPD.getReadMethod(),
existingPD.getWriteMethod(), null, method));
this.propertyDescriptors.remove(existingPd);
this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(
propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));
}
}
else {
throw new IllegalArgumentException(
"write method must have exactly 1 or 2 parameters: " + method);
throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method);
}
}
private PropertyDescriptor findExistingPropertyDescriptor(
String propertyName, Class<?> propertyType) {
private PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class<?> propertyType) {
for (PropertyDescriptor pd : this.propertyDescriptors) {
final Class<?> candidateType;
final String candidateName = pd.getName();
@@ -191,16 +175,14 @@ class ExtendedBeanInfo implements BeanInfo {
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
candidateType = ipd.getIndexedPropertyType();
if (candidateName.equals(propertyName) &&
(candidateType.equals(propertyType) ||
candidateType.equals(propertyType.getComponentType()))) {
(candidateType.equals(propertyType) || candidateType.equals(propertyType.getComponentType()))) {
return pd;
}
}
else {
candidateType = pd.getPropertyType();
if (candidateName.equals(propertyName) &&
(candidateType.equals(propertyType) ||
propertyType.equals(candidateType.getComponentType()))) {
(candidateType.equals(propertyType) || propertyType.equals(candidateType.getComponentType()))) {
return pd;
}
}
@@ -209,8 +191,7 @@ class ExtendedBeanInfo implements BeanInfo {
}
private String propertyNameFor(Method method) {
return Introspector.decapitalize(
method.getName().substring(3, method.getName().length()));
return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
}
@@ -221,65 +202,61 @@ class ExtendedBeanInfo implements BeanInfo {
* @see #ExtendedBeanInfo(BeanInfo)
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return this.propertyDescriptors.toArray(
new PropertyDescriptor[this.propertyDescriptors.size()]);
return this.propertyDescriptors.toArray(new PropertyDescriptor[this.propertyDescriptors.size()]);
}
public BeanInfo[] getAdditionalBeanInfo() {
return delegate.getAdditionalBeanInfo();
return this.delegate.getAdditionalBeanInfo();
}
public BeanDescriptor getBeanDescriptor() {
return delegate.getBeanDescriptor();
return this.delegate.getBeanDescriptor();
}
public int getDefaultEventIndex() {
return delegate.getDefaultEventIndex();
return this.delegate.getDefaultEventIndex();
}
public int getDefaultPropertyIndex() {
return delegate.getDefaultPropertyIndex();
return this.delegate.getDefaultPropertyIndex();
}
public EventSetDescriptor[] getEventSetDescriptors() {
return delegate.getEventSetDescriptors();
return this.delegate.getEventSetDescriptors();
}
public Image getIcon(int iconKind) {
return delegate.getIcon(iconKind);
return this.delegate.getIcon(iconKind);
}
public MethodDescriptor[] getMethodDescriptors() {
return delegate.getMethodDescriptors();
return this.delegate.getMethodDescriptors();
}
}
class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
class SimplePropertyDescriptor extends PropertyDescriptor {
private Method readMethod;
private Method writeMethod;
private Class<?> propertyType;
private Class<?> propertyEditorClass;
public SimpleNonIndexedPropertyDescriptor(PropertyDescriptor original)
throws IntrospectionException {
public SimplePropertyDescriptor(PropertyDescriptor original) throws IntrospectionException {
this(original.getName(), original.getReadMethod(), original.getWriteMethod());
copyNonMethodProperties(original, this);
}
public SimpleNonIndexedPropertyDescriptor(String propertyName,
Method readMethod, Method writeMethod) throws IntrospectionException {
public SimplePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException {
super(propertyName, null, null);
this.setReadMethod(readMethod);
this.setWriteMethod(writeMethod);
this.readMethod = readMethod;
this.writeMethod = writeMethod;
this.propertyType = findPropertyType(readMethod, writeMethod);
}
@Override
public Method getReadMethod() {
return this.readMethod;
@@ -305,8 +282,9 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
if (this.propertyType == null) {
try {
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
} catch (IntrospectionException ex) {
// ignore, as does PropertyDescriptor#getPropertyType
}
catch (IntrospectionException ex) {
// Ignore, as does PropertyDescriptor#getPropertyType
}
}
return this.propertyType;
@@ -322,7 +300,6 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
this.propertyEditorClass = propertyEditorClass;
}
@Override
public boolean equals(Object obj) {
return PropertyDescriptorUtils.equals(this, obj);
@@ -331,8 +308,7 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
@Override
public String toString() {
return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]",
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
this.readMethod, this.writeMethod);
getClass().getSimpleName(), getName(), getPropertyType(), this.readMethod, this.writeMethod);
}
}
@@ -340,40 +316,37 @@ class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
private Method readMethod;
private Method writeMethod;
private Class<?> propertyType;
private Class<?> propertyEditorClass;
private Method indexedReadMethod;
private Method indexedWriteMethod;
private Class<?> indexedPropertyType;
private Class<?> propertyEditorClass;
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original)
throws IntrospectionException {
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) throws IntrospectionException {
this(original.getName(), original.getReadMethod(), original.getWriteMethod(),
original.getIndexedReadMethod(), original.getIndexedWriteMethod());
copyNonMethodProperties(original, this);
}
public SimpleIndexedPropertyDescriptor(String propertyName,
Method readMethod, Method writeMethod,
Method indexedReadMethod, Method indexedWriteMethod)
throws IntrospectionException {
public SimpleIndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod,
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
super(propertyName, null, null, null, null);
this.setReadMethod(readMethod);
this.setWriteMethod(writeMethod);
this.readMethod = readMethod;
this.writeMethod = writeMethod;
this.propertyType = findPropertyType(readMethod, writeMethod);
this.setIndexedReadMethod(indexedReadMethod);
this.setIndexedWriteMethod(indexedWriteMethod);
this.indexedPropertyType = findIndexedPropertyType(
this.getName(), this.propertyType, indexedReadMethod, indexedWriteMethod);
this.indexedReadMethod = indexedReadMethod;
this.indexedWriteMethod = indexedWriteMethod;
this.indexedPropertyType = findIndexedPropertyType(propertyName, this.propertyType, indexedReadMethod, indexedWriteMethod);
}
@Override
public Method getReadMethod() {
return this.readMethod;
@@ -399,8 +372,9 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
if (this.propertyType == null) {
try {
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
} catch (IntrospectionException ex) {
// ignore, as does IndexedPropertyDescriptor#getPropertyType
}
catch (IntrospectionException ex) {
// Ignore, as does IndexedPropertyDescriptor#getPropertyType
}
}
return this.propertyType;
@@ -431,10 +405,10 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
if (this.indexedPropertyType == null) {
try {
this.indexedPropertyType = findIndexedPropertyType(
this.getName(), this.getPropertyType(),
this.indexedReadMethod, this.indexedWriteMethod);
} catch (IntrospectionException ex) {
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
}
catch (IntrospectionException ex) {
// Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
}
}
return this.indexedPropertyType;
@@ -450,26 +424,22 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
this.propertyEditorClass = propertyEditorClass;
}
/*
* @see java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
* See java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj;
if (!compareMethods(getIndexedReadMethod(), other.getIndexedReadMethod())) {
return false;
}
if (!compareMethods(getIndexedWriteMethod(), other.getIndexedWriteMethod())) {
return false;
}
if (getIndexedPropertyType() != other.getIndexedPropertyType()) {
return false;
}
@@ -482,9 +452,8 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
public String toString() {
return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " +
"readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]",
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
this.getIndexedPropertyType(), this.readMethod, this.writeMethod,
this.indexedReadMethod, this.indexedWriteMethod);
getClass().getSimpleName(), getName(), getPropertyType(), getIndexedPropertyType(),
this.readMethod, this.writeMethod, this.indexedReadMethod, this.indexedWriteMethod);
}
}
@@ -492,7 +461,7 @@ class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
class PropertyDescriptorUtils {
/*
* see java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor)
* See java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor)
*/
public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDescriptor target)
throws IntrospectionException {
@@ -504,14 +473,14 @@ class PropertyDescriptorUtils {
target.setShortDescription(source.getShortDescription());
target.setDisplayName(source.getDisplayName());
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
// Copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
Enumeration<String> keys = source.attributeNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
target.setValue(key, source.getValue(key));
}
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
// See java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
target.setPropertyEditorClass(source.getPropertyEditorClass());
target.setBound(source.isBound());
target.setConstrained(source.isConstrained());
@@ -520,32 +489,39 @@ class PropertyDescriptorUtils {
/*
* See PropertyDescriptor#findPropertyType
*/
public static Class<?> findPropertyType(Method readMethod, Method writeMethod)
throws IntrospectionException {
public static Class<?> findPropertyType(Method readMethod, Method writeMethod) throws IntrospectionException {
Class<?> propertyType = null;
if (readMethod != null) {
Class<?>[] params = readMethod.getParameterTypes();
if (params.length != 0) {
throw new IntrospectionException("bad read method arg count: " + readMethod);
throw new IntrospectionException("Bad read method arg count: " + readMethod);
}
propertyType = readMethod.getReturnType();
if (propertyType == Void.TYPE) {
throw new IntrospectionException("read method "
+ readMethod.getName() + " returns void");
throw new IntrospectionException("Read method returns void: " + readMethod);
}
}
if (writeMethod != null) {
Class<?> params[] = writeMethod.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException("bad write method arg count: " + writeMethod);
throw new IntrospectionException("Bad write method arg count: " + writeMethod);
}
if (propertyType != null
&& !params[0].isAssignableFrom(propertyType)) {
throw new IntrospectionException("type mismatch between read and write methods");
if (propertyType != null) {
if (propertyType.isAssignableFrom(params[0])) {
// Write method's property type potentially more specific
propertyType = params[0];
}
else if (params[0].isAssignableFrom(propertyType)) {
// Proceed with read method's property type
}
else {
throw new IntrospectionException(
"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
}
}
else {
propertyType = params[0];
}
propertyType = params[0];
}
return propertyType;
}
@@ -554,48 +530,51 @@ class PropertyDescriptorUtils {
* See IndexedPropertyDescriptor#findIndexedPropertyType
*/
public static Class<?> findIndexedPropertyType(String name, Class<?> propertyType,
Method indexedReadMethod, Method indexedWriteMethod)
throws IntrospectionException {
Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
Class<?> indexedPropertyType = null;
if (indexedReadMethod != null) {
Class<?> params[] = indexedReadMethod.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException(
"bad indexed read method arg count");
throw new IntrospectionException("Bad indexed read method arg count: " + indexedReadMethod);
}
if (params[0] != Integer.TYPE) {
throw new IntrospectionException(
"non int index to indexed read method");
throw new IntrospectionException("Non int index to indexed read method: " + indexedReadMethod);
}
indexedPropertyType = indexedReadMethod.getReturnType();
if (indexedPropertyType == Void.TYPE) {
throw new IntrospectionException(
"indexed read method returns void");
throw new IntrospectionException("Indexed read method returns void: " + indexedReadMethod);
}
}
if (indexedWriteMethod != null) {
Class<?> params[] = indexedWriteMethod.getParameterTypes();
if (params.length != 2) {
throw new IntrospectionException(
"bad indexed write method arg count");
throw new IntrospectionException("Bad indexed write method arg count: " + indexedWriteMethod);
}
if (params[0] != Integer.TYPE) {
throw new IntrospectionException(
"non int index to indexed write method");
throw new IntrospectionException("Non int index to indexed write method: " + indexedWriteMethod);
}
if (indexedPropertyType != null && indexedPropertyType != params[1]) {
throw new IntrospectionException(
"type mismatch between indexed read and indexed write methods: " + name);
if (indexedPropertyType != null) {
if (indexedPropertyType.isAssignableFrom(params[1])) {
// Write method's property type potentially more specific
indexedPropertyType = params[1];
}
else if (params[1].isAssignableFrom(indexedPropertyType)) {
// Proceed with read method's property type
}
else {
throw new IntrospectionException("Type mismatch between indexed read and write methods: " +
indexedReadMethod + " - " + indexedWriteMethod);
}
}
else {
indexedPropertyType = params[1];
}
indexedPropertyType = params[1];
}
if (propertyType != null
&& (!propertyType.isArray() ||
propertyType.getComponentType() != indexedPropertyType)) {
throw new IntrospectionException(
"type mismatch between indexed and non-indexed methods: " + name);
if (propertyType != null && (!propertyType.isArray() ||
propertyType.getComponentType() != indexedPropertyType)) {
throw new IntrospectionException("Type mismatch between indexed and non-indexed methods: " +
indexedReadMethod + " - " + indexedWriteMethod);
}
return indexedPropertyType;
}
@@ -605,7 +584,6 @@ class PropertyDescriptorUtils {
* return {@code true} if they are objects are equivalent, i.e. both are {@code
* PropertyDescriptor}s whose read method, write method, property types, property
* editor and flags are equivalent.
*
* @see PropertyDescriptor#equals(Object)
*/
public static boolean equals(PropertyDescriptor pd1, Object obj) {
@@ -617,15 +595,12 @@ class PropertyDescriptorUtils {
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
return false;
}
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
return false;
}
if (pd1.getPropertyType() == pd2.getPropertyType()
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass()
&& pd1.isBound() == pd2.isBound()
&& pd1.isConstrained() == pd2.isConstrained()) {
if (pd1.getPropertyType() == pd2.getPropertyType() &&
pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass() &&
pd1.isBound() == pd2.isBound() && pd1.isConstrained() == pd2.isConstrained()) {
return true;
}
}
@@ -633,14 +608,13 @@ class PropertyDescriptorUtils {
}
/*
* see PropertyDescriptor#compareMethods
* See PropertyDescriptor#compareMethods
*/
public static boolean compareMethods(Method a, Method b) {
if ((a == null) != (b == null)) {
return false;
}
if (a != null && b != null) {
if (a != null) {
if (!a.equals(b)) {
return false;
}
@@ -653,7 +627,6 @@ class PropertyDescriptorUtils {
/**
* Sorts PropertyDescriptor instances alpha-numerically to emulate the behavior of
* {@link java.beans.BeanInfo#getPropertyDescriptors()}.
*
* @see ExtendedBeanInfo#propertyDescriptors
*/
class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,32 +31,32 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Extension of the standard JavaBeans PropertyDescriptor class,
* overriding {@code getPropertyType()} such that a generically
* declared type will be resolved against the containing bean class.
* Extension of the standard JavaBeans {@link PropertyDescriptor} class,
* overriding {@code getPropertyType()} such that a generically declared
* type variable will be resolved against the containing bean class.
*
* @author Juergen Hoeller
* @since 2.5.2
*/
class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
private final Class beanClass;
private final Class<?> beanClass;
private final Method readMethod;
private final Method writeMethod;
private final Class propertyEditorClass;
private final Class<?> propertyEditorClass;
private volatile Set<Method> ambiguousWriteMethods;
private Class propertyType;
private Class<?> propertyType;
private MethodParameter writeMethodParameter;
public GenericTypeAwarePropertyDescriptor(Class beanClass, String propertyName,
Method readMethod, Method writeMethod, Class propertyEditorClass)
public GenericTypeAwarePropertyDescriptor(Class<?> beanClass, String propertyName,
Method readMethod, Method writeMethod, Class<?> propertyEditorClass)
throws IntrospectionException {
super(propertyName, null, null);
@@ -69,8 +69,11 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
// Fallback: Original JavaBeans introspection might not have found matching setter
// method due to lack of bridge method resolution, in case of the getter using a
// covariant return type whereas the setter is defined for the concrete property type.
writeMethodToUse = ClassUtils.getMethodIfAvailable(this.beanClass,
"set" + StringUtils.capitalize(getName()), readMethodToUse.getReturnType());
Method candidate = ClassUtils.getMethodIfAvailable(
this.beanClass, "set" + StringUtils.capitalize(getName()), (Class<?>[]) null);
if (candidate != null && candidate.getParameterTypes().length == 1) {
writeMethodToUse = candidate;
}
}
this.readMethod = readMethodToUse;
this.writeMethod = writeMethodToUse;
@@ -118,12 +121,12 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
}
@Override
public Class getPropertyEditorClass() {
public Class<?> getPropertyEditorClass() {
return this.propertyEditorClass;
}
@Override
public synchronized Class getPropertyType() {
public synchronized Class<?> getPropertyType() {
if (this.propertyType == null) {
if (this.readMethod != null) {
this.propertyType = GenericTypeResolver.resolveReturnType(this.readMethod, this.beanClass);
@@ -187,6 +187,9 @@ class TypeConverterDelegate {
// Try to apply some standard type conversion rules if appropriate.
if (convertedValue != null) {
if (Object.class.equals(requiredType)) {
return (T) convertedValue;
}
if (requiredType.isArray()) {
// Array required -> apply appropriate conversion of elements.
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
@@ -139,7 +139,7 @@ public abstract class BeanFactoryUtils {
* @param type the type that beans must match
* @return the array of matching bean names, or an empty array if none
*/
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class type) {
public static String[] beanNamesForTypeIncludingAncestors(ListableBeanFactory lbf, Class<?> type) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
String[] result = lbf.getBeanNamesForType(type);
if (lbf instanceof HierarchicalBeanFactory) {
@@ -181,7 +181,7 @@ public abstract class BeanFactoryUtils {
* @return the array of matching bean names, or an empty array if none
*/
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class type, boolean includeNonSingletons, boolean allowEagerInit) {
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,15 +58,19 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem
* allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that
* a bean was discovered specifically via component-scanning as opposed to other
* means.
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
* bean was discovered specifically via component-scanning as opposed to other means.
* @param metadata the annotation metadata for the bean class in question
* @since 3.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
setBeanClassName(metadata.getClassName());
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,6 +59,7 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
@@ -121,8 +122,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache =
new ConcurrentHashMap<Class<?>, Constructor<?>[]>(64);
private final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<Class<?>, InjectionMetadata>(64);
private final Map<String, InjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<String, InjectionMetadata>(64);
/**
@@ -214,7 +215,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
InjectionMetadata metadata = findAutowiringMetadata(beanType);
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType);
metadata.checkConfigMembers(beanDefinition);
}
}
@@ -280,7 +281,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass());
try {
metadata.inject(bean, beanName, pvs);
}
@@ -298,7 +299,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
*/
public void processInjection(Object bean) throws BeansException {
Class<?> clazz = bean.getClass();
InjectionMetadata metadata = findAutowiringMetadata(clazz);
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz);
try {
metadata.inject(bean, null, null);
}
@@ -308,15 +309,17 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
private InjectionMetadata findAutowiringMetadata(Class<?> clazz) {
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz) {
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(clazz, metadata);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,14 +48,14 @@ public class InjectionMetadata {
private final Log logger = LogFactory.getLog(InjectionMetadata.class);
private final Class targetClass;
private final Class<?> targetClass;
private final Collection<InjectedElement> injectedElements;
private volatile Set<InjectedElement> checkedElements;
public InjectionMetadata(Class targetClass, Collection<InjectedElement> elements) {
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
this.targetClass = targetClass;
this.injectedElements = elements;
}
@@ -110,7 +110,7 @@ public class InjectionMetadata {
return this.member;
}
protected final Class getResourceType() {
protected final Class<?> getResourceType() {
if (this.isField) {
return ((Field) this.member).getType();
}
@@ -122,16 +122,16 @@ public class InjectionMetadata {
}
}
protected final void checkResourceType(Class resourceType) {
protected final void checkResourceType(Class<?> resourceType) {
if (this.isField) {
Class fieldType = ((Field) this.member).getType();
Class<?> fieldType = ((Field) this.member).getType();
if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) {
throw new IllegalStateException("Specified field type [" + fieldType +
"] is incompatible with resource type [" + resourceType.getName() + "]");
}
}
else {
Class paramType =
Class<?> paramType =
(this.pd != null ? this.pd.getPropertyType() : ((Method) this.member).getParameterTypes()[0]);
if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) {
throw new IllegalStateException("Specified parameter type [" + paramType +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,9 @@ import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.AutowireCandidateResolver;
@@ -227,17 +229,22 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
Class<? extends Annotation> type = annotation.annotationType();
RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
if (qualifier == null) {
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
}
if (qualifier == null) {
Annotation targetAnnotation = null;
if (bd.getResolvedFactoryMethod() != null) {
targetAnnotation = AnnotationUtils.getAnnotation(bd.getResolvedFactoryMethod(), type);
// First, check annotation on factory method, if applicable
Annotation targetAnnotation = getFactoryMethodAnnotation(bd, type);
if (targetAnnotation == null) {
RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
if (dbd != null) {
targetAnnotation = getFactoryMethodAnnotation(dbd, type);
}
}
if (targetAnnotation == null) {
// look for matching annotation on the target class
// Look for matching annotation on the target class
if (this.beanFactory != null) {
Class<?> beanType = this.beanFactory.getType(bdHolder.getBeanName());
if (beanType != null) {
@@ -252,30 +259,31 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
return true;
}
}
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
if (attributes.isEmpty() && qualifier == null) {
// if no attributes, the qualifier must be present
// If no attributes, the qualifier must be present
return false;
}
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String attributeName = entry.getKey();
Object expectedValue = entry.getValue();
Object actualValue = null;
// check qualifier first
// Check qualifier first
if (qualifier != null) {
actualValue = qualifier.getAttribute(attributeName);
}
if (actualValue == null) {
// fall back on bean definition attribute
// Fall back on bean definition attribute
actualValue = bd.getAttribute(attributeName);
}
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) {
// fall back on bean name (or alias) match
// Fall back on bean name (or alias) match
continue;
}
if (actualValue == null && qualifier != null) {
// fall back on default, but only if the qualifier is present
// Fall back on default, but only if the qualifier is present
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
}
if (actualValue != null) {
@@ -288,6 +296,25 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
return true;
}
protected RootBeanDefinition getResolvedDecoratedDefinition(RootBeanDefinition rbd) {
BeanDefinitionHolder decDef = rbd.getDecoratedDefinition();
if (decDef != null && this.beanFactory instanceof ConfigurableListableBeanFactory) {
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory;
if (clbf.containsBeanDefinition(decDef.getBeanName())) {
BeanDefinition dbd = clbf.getMergedBeanDefinition(decDef.getBeanName());
if (dbd instanceof RootBeanDefinition) {
return (RootBeanDefinition) dbd;
}
}
}
return null;
}
protected Annotation getFactoryMethodAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
return (resolvedFactoryMethod != null ? AnnotationUtils.getAnnotation(resolvedFactoryMethod, type) : null);
}
/**
* Determine whether the given dependency carries a value annotation.
@@ -185,7 +185,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @see #AUTOWIRE_BY_TYPE
* @see #AUTOWIRE_CONSTRUCTOR
*/
Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
/**
* Instantiate a new bean instance of the given class with the specified autowire
@@ -213,7 +213,7 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #applyBeanPostProcessorsAfterInitialization
*/
Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
/**
* Autowire the bean properties of the given bean instance by name or type.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -146,7 +146,7 @@ public class ConstructorArgumentValues {
* untyped values only)
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getIndexedArgumentValue(int index, Class requiredType) {
public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType) {
return getIndexedArgumentValue(index, requiredType, null);
}
@@ -159,7 +159,7 @@ public class ConstructorArgumentValues {
* unnamed values only)
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getIndexedArgumentValue(int index, Class requiredType, String requiredName) {
public ValueHolder getIndexedArgumentValue(int index, Class<?> requiredType, String requiredName) {
Assert.isTrue(index >= 0, "Index must not be negative");
ValueHolder valueHolder = this.indexedArgumentValues.get(index);
if (valueHolder != null &&
@@ -247,7 +247,7 @@ public class ConstructorArgumentValues {
* @param requiredType the type to match
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getGenericArgumentValue(Class requiredType) {
public ValueHolder getGenericArgumentValue(Class<?> requiredType) {
return getGenericArgumentValue(requiredType, null, null);
}
@@ -257,7 +257,7 @@ public class ConstructorArgumentValues {
* @param requiredName the name to match
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getGenericArgumentValue(Class requiredType, String requiredName) {
public ValueHolder getGenericArgumentValue(Class<?> requiredType, String requiredName) {
return getGenericArgumentValue(requiredType, requiredName, null);
}
@@ -273,7 +273,7 @@ public class ConstructorArgumentValues {
* in the current resolution process and should therefore not be returned again
* @return the ValueHolder for the argument, or {@code null} if none found
*/
public ValueHolder getGenericArgumentValue(Class requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
public ValueHolder getGenericArgumentValue(Class<?> requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
for (ValueHolder valueHolder : this.genericArgumentValues) {
if (usedValueHolders != null && usedValueHolders.contains(valueHolder)) {
continue;
@@ -309,10 +309,10 @@ public class ConstructorArgumentValues {
* Look for an argument value that either corresponds to the given index
* in the constructor argument list or generically matches by type.
* @param index the index in the constructor argument list
* @param requiredType the type to match
* @param requiredType the parameter type to match
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getArgumentValue(int index, Class requiredType) {
public ValueHolder getArgumentValue(int index, Class<?> requiredType) {
return getArgumentValue(index, requiredType, null, null);
}
@@ -320,11 +320,11 @@ public class ConstructorArgumentValues {
* Look for an argument value that either corresponds to the given index
* in the constructor argument list or generically matches by type.
* @param index the index in the constructor argument list
* @param requiredType the type to match
* @param requiredName the name to match
* @param requiredType the parameter type to match
* @param requiredName the parameter name to match
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getArgumentValue(int index, Class requiredType, String requiredName) {
public ValueHolder getArgumentValue(int index, Class<?> requiredType, String requiredName) {
return getArgumentValue(index, requiredType, requiredName, null);
}
@@ -332,15 +332,17 @@ public class ConstructorArgumentValues {
* Look for an argument value that either corresponds to the given index
* in the constructor argument list or generically matches by type.
* @param index the index in the constructor argument list
* @param requiredType the type to match (can be {@code null} to find
* an untyped argument value)
* @param requiredType the parameter type to match (can be {@code null}
* to find an untyped argument value)
* @param requiredName the parameter name to match (can be {@code null}
* to find an unnamed argument value)
* @param usedValueHolders a Set of ValueHolder objects that have already
* been used in the current resolution process and should therefore not
* be returned again (allowing to return the next generic argument match
* in case of multiple generic argument values of the same type)
* @return the ValueHolder for the argument, or {@code null} if none set
*/
public ValueHolder getArgumentValue(int index, Class requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
public ValueHolder getArgumentValue(int index, Class<?> requiredType, String requiredName, Set<ValueHolder> usedValueHolders) {
Assert.isTrue(index >= 0, "Index must not be negative");
ValueHolder valueHolder = getIndexedArgumentValue(index, requiredType, requiredName);
if (valueHolder == null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ public class DependencyDescriptor implements Serializable {
private transient Field field;
private Class declaringClass;
private Class<?> declaringClass;
private String methodName;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,7 +61,7 @@ public class TypedStringValue implements BeanMetadataElement {
* @param value the String value
* @param targetType the type to convert to
*/
public TypedStringValue(String value, Class targetType) {
public TypedStringValue(String value, Class<?> targetType) {
setValue(value);
setTargetType(targetType);
}
@@ -101,7 +101,7 @@ public class TypedStringValue implements BeanMetadataElement {
* for example in BeanFactoryPostProcessors.
* @see PropertyPlaceholderConfigurer
*/
public void setTargetType(Class targetType) {
public void setTargetType(Class<?> targetType) {
Assert.notNull(targetType, "'targetType' must not be null");
this.targetType = targetType;
}
@@ -109,7 +109,7 @@ public class TypedStringValue implements BeanMetadataElement {
/**
* Return the type to convert to.
*/
public Class getTargetType() {
public Class<?> getTargetType() {
Object targetTypeValue = this.targetType;
if (!(targetTypeValue instanceof Class)) {
throw new IllegalStateException("Typed String value does not carry a resolved target type");
@@ -153,11 +153,11 @@ public class TypedStringValue implements BeanMetadataElement {
* @return the resolved type to convert to
* @throws ClassNotFoundException if the type cannot be resolved
*/
public Class resolveTargetType(ClassLoader classLoader) throws ClassNotFoundException {
public Class<?> resolveTargetType(ClassLoader classLoader) throws ClassNotFoundException {
if (this.targetType == null) {
return null;
}
Class resolvedClass = ClassUtils.forName(getTargetTypeName(), classLoader);
Class<?> resolvedClass = ClassUtils.forName(getTargetTypeName(), classLoader);
this.targetType = resolvedClass;
return resolvedClass;
}
@@ -63,7 +63,7 @@ import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
@@ -135,21 +135,21 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* Dependency types to ignore on dependency check and autowire, as Set of
* Class objects: for example, String. Default is none.
*/
private final Set<Class> ignoredDependencyTypes = new HashSet<Class>();
private final Set<Class<?>> ignoredDependencyTypes = new HashSet<Class<?>>();
/**
* Dependency interfaces to ignore on dependency check and autowire, as Set of
* Class objects. By default, only the BeanFactory interface is ignored.
*/
private final Set<Class> ignoredDependencyInterfaces = new HashSet<Class>();
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();
/** Cache of unfinished FactoryBean instances: FactoryBean name --> BeanWrapper */
private final Map<String, BeanWrapper> factoryBeanInstanceCache =
new ConcurrentHashMap<String, BeanWrapper>(16);
/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
private final Map<Class, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
new ConcurrentHashMap<Class, PropertyDescriptor[]>(64);
private final Map<Class<?>, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
new ConcurrentHashMap<Class<?>, PropertyDescriptor[]>(64);
/**
@@ -171,6 +171,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
setParentBeanFactory(parentBeanFactory);
}
/**
* Set the instantiation strategy to use for creating bean instances.
* Default is CglibSubclassingInstantiationStrategy.
@@ -243,7 +244,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* Ignore the given dependency type for autowiring:
* for example, String. Default is none.
*/
public void ignoreDependencyType(Class type) {
public void ignoreDependencyType(Class<?> type) {
this.ignoredDependencyTypes.add(type);
}
@@ -257,11 +258,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.context.ApplicationContextAware
*/
public void ignoreDependencyInterface(Class ifc) {
public void ignoreDependencyInterface(Class<?> ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}
@Override
public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
super.copyConfigurationFrom(otherFactory);
@@ -305,12 +305,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
RootBeanDefinition bd = null;
if (mbd instanceof RootBeanDefinition) {
RootBeanDefinition rbd = (RootBeanDefinition) mbd;
if (rbd.isPrototype()) {
bd = rbd;
}
bd = (rbd.isPrototype() ? rbd : rbd.cloneBeanDefinition());
}
if (bd == null) {
bd = new RootBeanDefinition(mbd);
if (!mbd.isPrototype()) {
if (bd == null) {
bd = new RootBeanDefinition(mbd);
}
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = false;
}
@@ -329,14 +329,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Specialized methods for fine-grained control over the bean lifecycle
//-------------------------------------------------------------------------
public Object createBean(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
return createBean(beanClass.getName(), bd, null);
}
public Object autowire(Class beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
public Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
final RootBeanDefinition bd = new RootBeanDefinition(beanClass, autowireMode, dependencyCheck);
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
@@ -346,10 +346,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
else {
Object bean;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
bean = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return getInstantiationStrategy().instantiate(bd, null, parent);
}
@@ -358,7 +356,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
else {
bean = getInstantiationStrategy().instantiate(bd, null, parent);
}
populateBean(beanClass.getName(), bd, new BeanWrapperImpl(bean));
return bean;
}
@@ -490,7 +487,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
@@ -509,7 +506,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory() {
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
@@ -572,7 +569,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
@Override
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
Class<?> targetType = mbd.getTargetType();
if (targetType == null) {
targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
@@ -587,7 +584,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Class predicted = ibp.predictBeanType(targetType, beanName);
Class<?> predicted = ibp.predictBeanType(targetType, beanName);
if (predicted != null && (typesToMatch.length != 1 || !FactoryBean.class.equals(typesToMatch[0]) ||
FactoryBean.class.isAssignableFrom(predicted))) {
return predicted;
@@ -635,31 +632,61 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
return null;
}
List<ValueHolder> argumentValues = mbd.getConstructorArgumentValues().getGenericArgumentValues();
Object[] args = new Object[argumentValues.size()];
for (int i = 0; i < args.length; i++) {
args[i] = argumentValues.get(i).getValue();
}
// If all factory methods have the same return type, return that type.
// Can't clearly figure out exact method due to type converting / autowiring!
Class<?> commonType = null;
int minNrOfArgs = mbd.getConstructorArgumentValues().getArgumentCount();
Method[] candidates = ReflectionUtils.getUniqueDeclaredMethods(factoryClass);
Set<Class<?>> returnTypes = new HashSet<Class<?>>(1);
for (Method factoryMethod : candidates) {
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
Class<?> returnType = GenericTypeResolver.resolveReturnTypeForGenericMethod(factoryMethod, args);
if (returnType != null) {
returnTypes.add(returnType);
// No declared type variables to inspect, so just process the standard return type.
if (factoryMethod.getTypeParameters().length > 0) {
try {
// Fully resolve parameter names and argument values.
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
String[] paramNames = null;
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(factoryMethod);
}
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
if (valueHolder == null) {
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
args[i] = valueHolder.getValue();
usedValueHolders.add(valueHolder);
}
}
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
factoryMethod, args, getBeanClassLoader());
if (returnType != null) {
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
}
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to resolve generic return type for factory method: " + ex);
}
}
}
else {
commonType = ClassUtils.determineCommonAncestor(factoryMethod.getReturnType(), commonType);
}
}
}
if (returnTypes.size() == 1) {
if (commonType != null) {
// Clear return type found: all factory methods return same type.
return returnTypes.iterator().next();
return commonType;
}
else {
// Ambiguous return types found: return null to indicate "not determinable".
@@ -688,22 +715,19 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Try to obtain the FactoryBean's object type without instantiating it at all.
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
if (fbDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) fbDef).hasBeanClass()) {
Class<?> fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass();
if (ClassUtils.isCglibProxyClass(fbClass)) {
// CGLIB subclass methods hide generic parameters. look at the superclass.
fbClass = fbClass.getSuperclass();
}
// CGLIB subclass methods hide generic parameters; look at the original user class.
Class<?> fbClass = ClassUtils.getUserClass(((AbstractBeanDefinition) fbDef).getBeanClass());
// Find the given factory method, taking into account that in the case of
// @Bean methods, there may be parameters present.
ReflectionUtils.doWithMethods(fbClass,
new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (method.getName().equals(factoryMethodName) &&
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
new ReflectionUtils.MethodCallback() {
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
if (method.getName().equals(factoryMethodName) &&
FactoryBean.class.isAssignableFrom(method.getReturnType())) {
objectType.value = GenericTypeResolver.resolveReturnTypeArgument(method, FactoryBean.class);
}
}
}
});
});
if (objectType.value != null) {
return objectType.value;
}
@@ -764,11 +788,11 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @return the FactoryBean instance, or {@code null} to indicate
* that we couldn't obtain a shortcut FactoryBean instance
*/
private FactoryBean getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
synchronized (getSingletonMutex()) {
BeanWrapper bw = this.factoryBeanInstanceCache.get(beanName);
if (bw != null) {
return (FactoryBean) bw.getWrappedInstance();
return (FactoryBean<?>) bw.getWrappedInstance();
}
if (isSingletonCurrentlyInCreation(beanName)) {
return null;
@@ -788,7 +812,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Finished partial creation of this bean.
afterSingletonCreation(beanName);
}
FactoryBean fb = getFactoryBean(beanName, instance);
FactoryBean<?> fb = getFactoryBean(beanName, instance);
if (bw != null) {
this.factoryBeanInstanceCache.put(beanName, bw);
}
@@ -805,7 +829,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @return the FactoryBean instance, or {@code null} to indicate
* that we couldn't obtain a shortcut FactoryBean instance
*/
private FactoryBean getNonSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
private FactoryBean<?> getNonSingletonFactoryBeanForTypeCheck(String beanName, RootBeanDefinition mbd) {
if (isPrototypeCurrentlyInCreation(beanName)) {
return null;
}
@@ -836,7 +860,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws BeansException if any post-processing failed
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
*/
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName)
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName)
throws BeansException {
try {
@@ -887,7 +911,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws BeansException if any post-processing failed
* @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
*/
protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
@@ -916,7 +940,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class beanClass = resolveBeanClass(mbd, beanName);
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
@@ -948,7 +972,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
// Need to determine the constructor...
Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
@@ -968,14 +992,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
*/
protected Constructor[] determineConstructorsFromBeanPostProcessors(Class beanClass, String beanName)
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(Class<?> beanClass, String beanName)
throws BeansException {
if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {
return ctors;
}
@@ -1046,7 +1070,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @return BeanWrapper for the new instance
*/
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, Constructor[] ctors, Object[] explicitArgs) {
String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,7 +54,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
private ClassLoader beanClassLoader;
private Environment environment = new StandardEnvironment();
private Environment environment;
private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
@@ -90,7 +90,7 @@ public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable)this.registry).getEnvironment();
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
@@ -275,76 +275,82 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
markBeanAsCreated(beanName);
}
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
@@ -511,26 +517,32 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
}
Class<?> beanClass = predictBeanType(beanName, mbd, typesToMatch);
if (beanClass == null) {
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
if (beanType == null) {
return false;
}
// Check bean class whether we're dealing with a FactoryBean.
if (FactoryBean.class.isAssignableFrom(beanClass)) {
if (FactoryBean.class.isAssignableFrom(beanType)) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
Class<?> type = getTypeForFactoryBean(beanName, mbd);
return (type != null && typeToMatch.isAssignableFrom(type));
}
else {
return typeToMatch.isAssignableFrom(beanClass);
beanType = getTypeForFactoryBean(beanName, mbd);
if (beanType == null) {
return false;
}
}
}
else {
return !BeanFactoryUtils.isFactoryDereference(name) &&
typeToMatch.isAssignableFrom(beanClass);
else if (BeanFactoryUtils.isFactoryDereference(name)) {
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
// type but we nevertheless are being asked to dereference a FactoryBean...
// Let's check the original bean class and proceed with it if it is a FactoryBean.
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
return false;
}
}
return typeToMatch.isAssignableFrom(beanType);
}
}
@@ -1335,8 +1347,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @param mbd the corresponding bean definition
*/
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class);
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
return (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
}
/**
@@ -1382,6 +1394,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
this.alreadyCreated.put(beanName, Boolean.TRUE);
}
/**
* Perform appropriate cleanup of cached metadata after bean creation failed.
* @param beanName the name of the bean
*/
protected void cleanupAfterBeanCreationFailure(String beanName) {
this.alreadyCreated.remove(beanName);
}
/**
* Determine whether the specified bean is eligible for having
* its bean definition metadata cached.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,20 +23,27 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Set;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Utility class that contains various methods useful for
* the implementation of autowire-capable bean factories.
* Utility class that contains various methods useful for the implementation of
* autowire-capable bean factories.
*
* @author Juergen Hoeller
* @author Mark Fisher
* @author Sam Brannen
* @since 1.1.2
* @see AbstractAutowireCapableBeanFactory
*/
@@ -49,9 +56,9 @@ abstract class AutowireUtils {
* decreasing number of arguments.
* @param constructors the constructor array to sort
*/
public static void sortConstructors(Constructor[] constructors) {
Arrays.sort(constructors, new Comparator<Constructor>() {
public int compare(Constructor c1, Constructor c2) {
public static void sortConstructors(Constructor<?>[] constructors) {
Arrays.sort(constructors, new Comparator<Constructor<?>>() {
public int compare(Constructor<?> c1, Constructor<?> c2) {
boolean p1 = Modifier.isPublic(c1.getModifiers());
boolean p2 = Modifier.isPublic(c2.getModifiers());
if (p1 != p2) {
@@ -103,7 +110,7 @@ abstract class AutowireUtils {
}
// It was declared by CGLIB, but we might still want to autowire it
// if it was actually declared by the superclass.
Class superclass = wm.getDeclaringClass().getSuperclass();
Class<?> superclass = wm.getDeclaringClass().getSuperclass();
return !ClassUtils.hasMethod(superclass, wm.getName(), wm.getParameterTypes());
}
@@ -114,11 +121,11 @@ abstract class AutowireUtils {
* @param interfaces the Set of interfaces (Class objects)
* @return whether the setter method is defined by an interface
*/
public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class> interfaces) {
public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Class<?>> interfaces) {
Method setter = pd.getWriteMethod();
if (setter != null) {
Class targetClass = setter.getDeclaringClass();
for (Class ifc : interfaces) {
Class<?> targetClass = setter.getDeclaringClass();
for (Class<?> ifc : interfaces) {
if (ifc.isAssignableFrom(targetClass) &&
ClassUtils.hasMethod(ifc, setter.getName(), setter.getParameterTypes())) {
return true;
@@ -135,12 +142,12 @@ abstract class AutowireUtils {
* @param requiredType the type to assign the result to
* @return the resolved value
*/
public static Object resolveAutowiringValue(Object autowiringValue, Class requiredType) {
public static Object resolveAutowiringValue(Object autowiringValue, Class<?> requiredType) {
if (autowiringValue instanceof ObjectFactory && !requiredType.isInstance(autowiringValue)) {
ObjectFactory factory = (ObjectFactory) autowiringValue;
ObjectFactory<?> factory = (ObjectFactory<?>) autowiringValue;
if (autowiringValue instanceof Serializable && requiredType.isInterface()) {
autowiringValue = Proxy.newProxyInstance(requiredType.getClassLoader(),
new Class[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
new Class<?>[] {requiredType}, new ObjectFactoryDelegatingInvocationHandler(factory));
}
else {
return factory.getObject();
@@ -149,6 +156,124 @@ abstract class AutowireUtils {
return autowiringValue;
}
/**
* Determine the target type for the generic return type of the given
* <em>generic factory method</em>, where formal type variables are declared
* on the given method itself.
* <p>For example, given a factory method with the following signature,
* if {@code resolveReturnTypeForFactoryMethod()} is invoked with the reflected
* method for {@code creatProxy()} and an {@code Object[]} array containing
* {@code MyService.class}, {@code resolveReturnTypeForFactoryMethod()} will
* infer that the target return type is {@code MyService}.
* <pre class="code">{@code public static <T> T createProxy(Class<T> clazz)}</pre>
* <h4>Possible Return Values</h4>
* <ul>
* <li>the target return type, if it can be inferred</li>
* <li>the {@linkplain Method#getReturnType() standard return type}, if
* the given {@code method} does not declare any {@linkplain
* Method#getTypeParameters() formal type variables}</li>
* <li>the {@linkplain Method#getReturnType() standard return type}, if the
* target return type cannot be inferred (e.g., due to type erasure)</li>
* <li>{@code null}, if the length of the given arguments array is shorter
* than the length of the {@linkplain
* Method#getGenericParameterTypes() formal argument list} for the given
* method</li>
* </ul>
* @param method the method to introspect (never {@code null})
* @param args the arguments that will be supplied to the method when it is
* invoked (never {@code null})
* @param classLoader the ClassLoader to resolve class names against, if necessary
* (never {@code null})
* @return the resolved target return type, the standard return type, or {@code null}
* @since 3.2.5
*/
public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[] args, ClassLoader classLoader) {
Assert.notNull(method, "Method must not be null");
Assert.notNull(args, "Argument array must not be null");
Assert.notNull(classLoader, "ClassLoader must not be null");
TypeVariable<Method>[] declaredTypeVariables = method.getTypeParameters();
Type genericReturnType = method.getGenericReturnType();
Type[] methodParameterTypes = method.getGenericParameterTypes();
Assert.isTrue(args.length == methodParameterTypes.length, "Argument array does not match parameter count");
// Ensure that the type variable (e.g., T) is declared directly on the method
// itself (e.g., via <T>), not on the enclosing class or interface.
boolean locallyDeclaredTypeVariableMatchesReturnType = false;
for (TypeVariable<Method> currentTypeVariable : declaredTypeVariables) {
if (currentTypeVariable.equals(genericReturnType)) {
locallyDeclaredTypeVariableMatchesReturnType = true;
break;
}
}
if (locallyDeclaredTypeVariableMatchesReturnType) {
for (int i = 0; i < methodParameterTypes.length; i++) {
Type methodParameterType = methodParameterTypes[i];
Object arg = args[i];
if (methodParameterType.equals(genericReturnType)) {
if (arg instanceof TypedStringValue) {
TypedStringValue typedValue = ((TypedStringValue) arg);
if (typedValue.hasTargetType()) {
return typedValue.getTargetType();
}
try {
return typedValue.resolveTargetType(classLoader);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Failed to resolve value type [" +
typedValue.getTargetTypeName() + "] for factory method argument", ex);
}
}
// Only consider argument type if it is a simple value...
if (arg != null && !(arg instanceof BeanMetadataElement)) {
return arg.getClass();
}
return method.getReturnType();
}
else if (methodParameterType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) methodParameterType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type typeArg : actualTypeArguments) {
if (typeArg.equals(genericReturnType)) {
if (arg instanceof Class) {
return (Class<?>) arg;
}
else {
String className = null;
if (arg instanceof String) {
className = (String) arg;
}
else if (arg instanceof TypedStringValue) {
TypedStringValue typedValue = ((TypedStringValue) arg);
String targetTypeName = typedValue.getTargetTypeName();
if (targetTypeName == null || Class.class.getName().equals(targetTypeName)) {
className = typedValue.getValue();
}
}
if (className != null) {
try {
return ClassUtils.forName(className, classLoader);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Could not resolve class name [" + arg +
"] for factory method argument", ex);
}
}
// Consider adding logic to determine the class of the typeArg, if possible.
// For now, just fall back...
return method.getReturnType();
}
}
}
}
}
}
// Fall back...
return method.getReturnType();
}
/**
* Reflective InvocationHandler for lazy access to the current target object.
@@ -156,9 +281,9 @@ abstract class AutowireUtils {
@SuppressWarnings("serial")
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable {
private final ObjectFactory objectFactory;
private final ObjectFactory<?> objectFactory;
public ObjectFactoryDelegatingInvocationHandler(ObjectFactory objectFactory) {
public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) {
this.objectFactory = objectFactory;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.springframework.core.io.ResourceLoader;
/**
* Simple interface for bean definition readers.
* Specifies load methods with Resource parameters.
* Specifies load methods with Resource and String location parameters.
*
* <p>Concrete bean definition readers can of course add additional
* load and register methods for bean definitions, specific to
@@ -45,23 +45,23 @@ public interface BeanDefinitionReader {
*/
BeanDefinitionRegistry getRegistry();
/**
* Return the resource loader to use for resource locations.
* Can be checked for the <b>ResourcePatternResolver</b> interface and cast
* accordingly, for loading multiple resources for a given resource pattern.
* <p>Null suggests that absolute resource loading is not available
* for this bean definition reader.
* <p>This is mainly meant to be used for importing further resources
* from within a bean definition resource, for example via the "import"
* tag in XML bean definitions. It is recommended, however, to apply
* such imports relative to the defining resource; only explicit full
* resource locations will trigger absolute resource loading.
* <p>There is also a {@code loadBeanDefinitions(String)} method available,
* for loading bean definitions from a resource location (or location pattern).
* This is a convenience to avoid explicit ResourceLoader handling.
* @see #loadBeanDefinitions(String)
* @see org.springframework.core.io.support.ResourcePatternResolver
*/
/**
* Return the resource loader to use for resource locations.
* Can be checked for the <b>ResourcePatternResolver</b> interface and cast
* accordingly, for loading multiple resources for a given resource pattern.
* <p>Null suggests that absolute resource loading is not available
* for this bean definition reader.
* <p>This is mainly meant to be used for importing further resources
* from within a bean definition resource, for example via the "import"
* tag in XML bean definitions. It is recommended, however, to apply
* such imports relative to the defining resource; only explicit full
* resource locations will trigger absolute resource loading.
* <p>There is also a {@code loadBeanDefinitions(String)} method available,
* for loading bean definitions from a resource location (or location pattern).
* This is a convenience to avoid explicit ResourceLoader handling.
* @see #loadBeanDefinitions(String)
* @see org.springframework.core.io.support.ResourcePatternResolver
*/
ResourceLoader getResourceLoader();
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -128,7 +128,7 @@ class BeanDefinitionValueResolver {
else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
ManagedArray array = (ManagedArray) value;
Class elementType = array.resolvedElementType;
Class<?> elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
@@ -256,10 +256,8 @@ class BeanDefinitionValueResolver {
mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
// Check given bean name whether it is unique. If not already unique,
// add counter - increasing the counter until the name is unique.
String actualInnerBeanName = innerBeanName;
if (mbd.isSingleton()) {
actualInnerBeanName = adaptInnerBeanName(innerBeanName);
}
String actualInnerBeanName = adaptInnerBeanName(innerBeanName);
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
// Guarantee initialization of beans that the inner bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
@@ -269,9 +267,8 @@ class BeanDefinitionValueResolver {
}
}
Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
if (innerBean instanceof FactoryBean) {
boolean synthetic = (mbd != null && mbd.isSynthetic());
boolean synthetic = mbd.isSynthetic();
return this.beanFactory.getObjectFromFactoryBean((FactoryBean) innerBean, actualInnerBeanName, !synthetic);
}
else {
@@ -335,7 +332,7 @@ class BeanDefinitionValueResolver {
/**
* For each element in the managed array, resolve reference if necessary.
*/
private Object resolveManagedArray(Object argName, List<?> ml, Class elementType) {
private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) {
Object resolved = Array.newInstance(elementType, ml.size());
for (int i = 0; i < ml.size(); i++) {
Array.set(resolved, i,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
package org.springframework.beans.factory.support;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.ObjectUtils;
@@ -98,7 +97,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
* @param pvs the property values to apply
*/
public ChildBeanDefinition(
String parentName, Class beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
@@ -128,7 +127,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public ChildBeanDefinition(ChildBeanDefinition original) {
super((BeanDefinition) original);
super(original);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -151,7 +151,7 @@ class ConstructorResolver {
// Take specified constructors, if any.
Constructor[] candidates = chosenCtors;
if (candidates == null) {
Class beanClass = mbd.getBeanClass();
Class<?> beanClass = mbd.getBeanClass();
try {
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
@@ -169,7 +169,7 @@ class ConstructorResolver {
for (int i = 0; i < candidates.length; i++) {
Constructor<?> candidate = candidates[i];
Class[] paramTypes = candidate.getParameterTypes();
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
@@ -341,7 +341,7 @@ class ConstructorResolver {
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;
Class factoryClass;
Class<?> factoryClass;
boolean isStatic;
String factoryBeanName = mbd.getFactoryBeanName();
@@ -399,7 +399,7 @@ class ConstructorResolver {
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] rawCandidates;
final Class factoryClazz = factoryClass;
final Class<?> factoryClazz = factoryClass;
if (System.getSecurityManager() != null) {
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
public Method[] run() {
@@ -445,7 +445,7 @@ class ConstructorResolver {
for (int i = 0; i < candidates.length; i++) {
Method candidate = candidates[i];
Class[] paramTypes = candidate.getParameterTypes();
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
ArgumentsHolder argsHolder;
@@ -503,7 +503,15 @@ class ConstructorResolver {
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight) {
// Find out about ambiguity: In case of the same type difference weight
// for methods with the same number of parameters, collect such candidates
// and eventually raise an ambiguity exception.
// However, only perform that check in non-lenient constructor resolution mode,
// and explicitly ignore overridden methods (with the same parameter signature).
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterTypes().length &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<Method>();
ambiguousFactoryMethods.add(factoryMethodToUse);
@@ -540,7 +548,7 @@ class ConstructorResolver {
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null && !mbd.isLenientConstructorResolution()) {
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
@@ -644,7 +652,7 @@ class ConstructorResolver {
*/
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class[] paramTypes, String[] paramNames, Object methodOrCtor,
BeanWrapper bw, Class<?>[] paramTypes, String[] paramNames, Object methodOrCtor,
boolean autowiring) throws UnsatisfiedDependencyException {
String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
@@ -750,7 +758,7 @@ class ConstructorResolver {
private Object[] resolvePreparedArguments(
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
Class[] paramTypes = (methodOrCtor instanceof Method ?
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
this.beanFactory.getCustomTypeConverter() : bw);
@@ -822,7 +830,7 @@ class ConstructorResolver {
this.preparedArguments = args;
}
public int getTypeDifferenceWeight(Class[] paramTypes) {
public int getTypeDifferenceWeight(Class<?>[] paramTypes) {
// If valid arguments found, determine type difference weight.
// Try type difference weight on both the converted arguments and
// the raw arguments. If the raw weight is better, use it.
@@ -832,7 +840,7 @@ class ConstructorResolver {
return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight);
}
public int getAssignabilityWeight(Class[] paramTypes) {
public int getAssignabilityWeight(Class<?>[] paramTypes) {
for (int i = 0; i < paramTypes.length; i++) {
if (!ClassUtils.isAssignableValue(paramTypes[i], this.arguments[i])) {
return Integer.MAX_VALUE;
@@ -31,7 +31,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -460,12 +459,15 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
Set<String> beanNames = new LinkedHashSet<String>(getBeanDefinitionCount());
beanNames.addAll(Arrays.asList(getBeanDefinitionNames()));
beanNames.addAll(Arrays.asList(getSingletonNames()));
Map<String, Object> results = new LinkedHashMap<String, Object>();
for (String beanName : beanNames) {
if (findAnnotationOnBean(beanName, annotationType) != null) {
for (String beanName : getBeanDefinitionNames()) {
BeanDefinition beanDefinition = getBeanDefinition(beanName);
if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
}
for (String beanName : getSingletonNames()) {
if (!results.containsKey(beanName) && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory> singletonFactories = new HashMap<String, ObjectFactory>(16);
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
@@ -181,7 +181,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
@@ -201,7 +201,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,11 +52,11 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @return the FactoryBean's object type,
* or {@code null} if the type cannot be determined yet
*/
protected Class getTypeForFactoryBean(final FactoryBean factoryBean) {
protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
try {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Class>() {
public Class run() {
return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
public Class<?> run() {
return factoryBean.getObjectType();
}
}, getAccessControlContext());
@@ -94,7 +94,7 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
@@ -120,7 +120,7 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
private Object doGetObjectFromFactoryBean(
final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
final FactoryBean<?> factory, final String beanName, final boolean shouldPostProcess)
throws BeanCreationException {
Object object;
@@ -190,12 +190,12 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @return the bean instance as FactoryBean
* @throws BeansException if the given bean cannot be exposed as a FactoryBean
*/
protected FactoryBean getFactoryBean(String beanName, Object beanInstance) throws BeansException {
protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) throws BeansException {
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanCreationException(beanName,
"Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
}
return (FactoryBean) beanInstance;
return (FactoryBean<?>) beanInstance;
}
/**
@@ -107,7 +107,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* Create a new RootBeanDefinition for a singleton.
* @param beanClass the class of the bean to instantiate
*/
public RootBeanDefinition(Class beanClass) {
public RootBeanDefinition(Class<?> beanClass) {
super();
setBeanClass(beanClass);
}
@@ -147,7 +147,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param dependencyCheck whether to perform a dependency check for objects
* (not applicable to autowiring a constructor, thus ignored there)
*/
public RootBeanDefinition(Class beanClass, int autowireMode, boolean dependencyCheck) {
public RootBeanDefinition(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
super();
setBeanClass(beanClass);
setAutowireMode(autowireMode);
@@ -191,7 +191,7 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
*/
public RootBeanDefinition(Class beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
public RootBeanDefinition(Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
setBeanClass(beanClass);
}
@@ -225,7 +225,11 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public RootBeanDefinition(RootBeanDefinition original) {
this((BeanDefinition) original);
super(original);
this.decoratedDefinition = original.decoratedDefinition;
this.allowCaching = original.allowCaching;
this.targetType = original.targetType;
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
}
/**
@@ -235,13 +239,6 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
*/
RootBeanDefinition(BeanDefinition original) {
super(original);
if (original instanceof RootBeanDefinition) {
RootBeanDefinition originalRbd = (RootBeanDefinition) original;
this.decoratedDefinition = originalRbd.decoratedDefinition;
this.allowCaching = originalRbd.allowCaching;
this.targetType = originalRbd.targetType;
this.isFactoryMethodUnique = originalRbd.isFactoryMethodUnique;
}
}
@@ -93,7 +93,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
try {
return ((FactoryBean) bean).getObject();
return ((FactoryBean<?>) bean).getObject();
}
catch (Exception ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
@@ -141,18 +141,18 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
// In case of FactoryBean, return singleton status of created object.
return (bean instanceof FactoryBean && ((FactoryBean) bean).isSingleton());
return (bean instanceof FactoryBean && ((FactoryBean<?>) bean).isSingleton());
}
public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
Object bean = getBean(name);
// In case of FactoryBean, return prototype status of created object.
return ((bean instanceof SmartFactoryBean && ((SmartFactoryBean) bean).isPrototype()) ||
(bean instanceof FactoryBean && !((FactoryBean) bean).isSingleton()));
return ((bean instanceof SmartFactoryBean && ((SmartFactoryBean<?>) bean).isPrototype()) ||
(bean instanceof FactoryBean && !((FactoryBean<?>) bean).isSingleton()));
}
public boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException {
Class type = getType(name);
public boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException {
Class<?> type = getType(name);
return (targetType == null || (type != null && targetType.isAssignableFrom(type)));
}
@@ -167,7 +167,7 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
if (bean instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
return ((FactoryBean) bean).getObjectType();
return ((FactoryBean<?>) bean).getObjectType();
}
return bean.getClass();
}
@@ -193,18 +193,18 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
return StringUtils.toStringArray(this.beans.keySet());
}
public String[] getBeanNamesForType(Class type) {
public String[] getBeanNamesForType(Class<?> type) {
return getBeanNamesForType(type, true, true);
}
public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean includeFactoryBeans) {
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean includeFactoryBeans) {
boolean isFactoryType = (type != null && FactoryBean.class.isAssignableFrom(type));
List<String> matches = new ArrayList<String>();
for (String name : this.beans.keySet()) {
Object beanInstance = this.beans.get(name);
if (beanInstance instanceof FactoryBean && !isFactoryType) {
if (includeFactoryBeans) {
Class objectType = ((FactoryBean) beanInstance).getObjectType();
Class<?> objectType = ((FactoryBean<?>) beanInstance).getObjectType();
if (objectType != null && (type == null || type.isAssignableFrom(objectType))) {
matches.add(name);
}
@@ -237,8 +237,8 @@ public class StaticListableBeanFactory implements ListableBeanFactory {
if (beanInstance instanceof FactoryBean && !isFactoryType) {
if (includeFactoryBeans) {
// Match object created by FactoryBean.
FactoryBean factory = (FactoryBean) beanInstance;
Class objectType = factory.getObjectType();
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
Class<?> objectType = factory.getObjectType();
if ((includeNonSingletons || factory.isSingleton()) &&
objectType != null && (type == null || type.isAssignableFrom(objectType))) {
matches.put(beanName, getBean(beanName, type));
@@ -133,7 +133,7 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createHelper(this.readerContext, root, parent);
this.delegate = createDelegate(this.readerContext, root, parent);
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
@@ -142,12 +142,22 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root, parentDelegate);
if (delegate == null) {
delegate = new BeanDefinitionParserDelegate(readerContext, this.environment);
delegate.initDefaults(root, parentDelegate);
}
return delegate;
}
@Deprecated
protected BeanDefinitionParserDelegate createHelper(
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
delegate.initDefaults(root, parentDelegate);
return delegate;
return null;
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,9 +78,12 @@ public class ResourceEditorRegistrar implements PropertyEditorRegistrar {
}
/**
* Create a new ResourceEditorRegistrar for the given ResourceLoader
* Create a new ResourceEditorRegistrar for the given {@link ResourceLoader}
* and {@link PropertyResolver}.
* @param resourceLoader the ResourceLoader (or ResourcePatternResolver)
* to create editors for (usually an ApplicationContext)
* @param propertyResolver the PropertyResolver (usually an Environment)
* @see org.springframework.core.env.Environment
* @see org.springframework.core.io.support.ResourcePatternResolver
* @see org.springframework.context.ApplicationContext
*/
@@ -16,8 +16,6 @@
package org.springframework.beans;
import static org.junit.Assert.*;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
@@ -25,6 +23,7 @@ import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.core.io.Resource;
@@ -33,6 +32,7 @@ import org.springframework.tests.sample.beans.DerivedTestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* Unit tests for {@link BeanUtils}.
@@ -79,8 +79,7 @@ public final class BeanUtilsTests {
@Test
public void testBeanPropertyIsArray() {
PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(ContainerBean.class);
for (int i = 0; i < descriptors.length; i++) {
PropertyDescriptor descriptor = descriptors[i];
for (PropertyDescriptor descriptor : descriptors) {
if ("containedBeans".equals(descriptor.getName())) {
assertTrue("Property should be an array", descriptor.getPropertyType().isArray());
assertEquals(descriptor.getPropertyType().getComponentType(), ContainedBean.class);
@@ -171,7 +170,7 @@ public final class BeanUtilsTests {
assertTrue("Touchy empty", tb2.getTouchy() == null);
// "spouse", "touchy", "age" should not be copied
BeanUtils.copyProperties(tb, tb2, new String[]{"spouse", "touchy", "age"});
BeanUtils.copyProperties(tb, tb2, "spouse", "touchy", "age");
assertTrue("Name copied", tb2.getName() == null);
assertTrue("Age still empty", tb2.getAge() == 0);
assertTrue("Touchy still empty", tb2.getTouchy() == null);
@@ -182,7 +181,16 @@ public final class BeanUtilsTests {
NameAndSpecialProperty source = new NameAndSpecialProperty();
source.setName("name");
TestBean target = new TestBean();
BeanUtils.copyProperties(source, target, new String[]{"specialProperty"});
BeanUtils.copyProperties(source, target, "specialProperty");
assertEquals(target.getName(), "name");
}
@Test
public void testCopyPropertiesWithInvalidProperty() {
InvalidProperty source = new InvalidProperty();
source.setName("name");
InvalidProperty target = new InvalidProperty();
BeanUtils.copyProperties(source, target);
assertEquals(target.getName(), "name");
}
@@ -257,7 +265,8 @@ public final class BeanUtilsTests {
assertEquals(String.class, keyDescr.getPropertyType());
for (PropertyDescriptor propertyDescriptor : descrs) {
if (propertyDescriptor.getName().equals(keyDescr.getName())) {
assertEquals(propertyDescriptor.getName() + " has unexpected type", keyDescr.getPropertyType(), propertyDescriptor.getPropertyType());
assertEquals(propertyDescriptor.getName() + " has unexpected type",
keyDescr.getPropertyType(), propertyDescriptor.getPropertyType());
}
}
}
@@ -292,6 +301,31 @@ public final class BeanUtilsTests {
}
@SuppressWarnings("unused")
private static class InvalidProperty {
private String name;
private String value;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setValue(int value) {
this.value = Integer.toString(value);
}
public String getValue() {
return this.value;
}
}
@SuppressWarnings("unused")
private static class ContainerBean {
@@ -347,6 +381,7 @@ public final class BeanUtilsTests {
}
}
private interface MapEntry<K, V> {
K getKey();
@@ -358,6 +393,7 @@ public final class BeanUtilsTests {
void setValue(V value);
}
private static class Bean implements MapEntry<String, String> {
private String key;
@@ -63,6 +63,10 @@ import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* @author Rod Johnson
@@ -1559,6 +1563,20 @@ public final class BeanWrapperTests {
assertEquals("val1", Spr10115Bean.prop1);
}
@Test
public void testArrayToObject() throws Exception {
ArrayToObject foo = new ArrayToObject();
BeanWrapperImpl bwi = new BeanWrapperImpl();
bwi.setWrappedInstance(foo);
Object[] array = new Object[] {"1","2"};
bwi.setPropertyValue("object", array );
assertThat(foo.getObject(), equalTo((Object) array));
array = new Object[] {"1"};
bwi.setPropertyValue("object", array );
assertThat(foo.getObject(), equalTo((Object) array));
}
static class Spr10115Bean {
private static String prop1;
@@ -1944,4 +1962,19 @@ public final class BeanWrapperTests {
TEST_VALUE
}
static class ArrayToObject {
private Object object;
public void setObject(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
}
}
@@ -21,29 +21,19 @@ import java.beans.IndexedPropertyDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import org.junit.Test;
import org.springframework.core.JdkVersion;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.ClassUtils;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Unit tests for {@link ExtendedBeanInfo}.
*
* @author Chris Beams
* @since 3.1
*/
@@ -207,10 +197,6 @@ public class ExtendedBeanInfoTests {
}
}
interface Spr9453<T> {
T getProp();
}
@Test
public void cornerSpr9453() throws IntrospectionException {
final class Bean implements Spr9453<Class<?>> {
@@ -335,10 +321,8 @@ public class ExtendedBeanInfoTests {
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
assertEquals(hasWriteMethodForProperty(bi, "foo"), hasWriteMethodForProperty(ebi, "foo"));
}
@Test
@@ -352,10 +336,8 @@ public class ExtendedBeanInfoTests {
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(false));
assertEquals(hasIndexedWriteMethodForProperty(bi, "foos"), hasIndexedWriteMethodForProperty(ebi, "foos"));
}
/**
@@ -595,7 +577,6 @@ public class ExtendedBeanInfoTests {
new ExtendedBeanInfo(Introspector.getBeanInfo(BigDecimal.class));
}
@Test
public void subclassWriteMethodWithCovariantReturnType() throws IntrospectionException {
@SuppressWarnings("unused") class B {
@@ -792,6 +773,7 @@ public class ExtendedBeanInfoTests {
@Test
public void propertyDescriptorComparator() throws IntrospectionException {
PropertyDescriptorComparator c = new PropertyDescriptorComparator();
assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("a", null, null)), equalTo(0));
assertThat(c.compare(new PropertyDescriptor("abc", null, null), new PropertyDescriptor("abc", null, null)), equalTo(0));
assertThat(c.compare(new PropertyDescriptor("a", null, null), new PropertyDescriptor("b", null, null)), lessThan(0));
@@ -863,31 +845,6 @@ public class ExtendedBeanInfoTests {
new ExtendedBeanInfo(Introspector.getBeanInfo(LawLibrary.class));
}
interface Book { }
interface TextBook extends Book { }
interface LawBook extends TextBook { }
interface BookOperations {
Book getBook();
void setBook(Book book);
}
interface TextBookOperations extends BookOperations {
TextBook getBook();
}
abstract class Library {
public Book getBook() { return null; }
public void setBook(Book book) { }
}
class LawLibrary extends Library implements TextBookOperations {
public LawBook getBook() { return null; }
}
@Test
public void cornerSpr8949() throws IntrospectionException {
class A {
@@ -905,23 +862,10 @@ public class ExtendedBeanInfoTests {
BeanInfo bi = Introspector.getBeanInfo(B.class);
/* first, demonstrate the 'problem':
* java.beans.Introspector returns the "wrong" declaring class for overridden read
* methods, which in turn violates expectations in {@link ExtendedBeanInfo} regarding
* method equality. Spring's {@link ClassUtils#getMostSpecificMethod(Method, Class)}
* helps out here, and is now put into use in ExtendedBeanInfo as well
*/
for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
if ("targetMethod".equals(pd.getName())) {
Method readMethod = pd.getReadMethod();
assertTrue(readMethod.getDeclaringClass().equals(A.class)); // we expected B!
Method msReadMethod = ClassUtils.getMostSpecificMethod(readMethod, B.class);
assertTrue(msReadMethod.getDeclaringClass().equals(B.class)); // and now we get it.
}
}
// and now demonstrate that we've indeed fixed the problem
// java.beans.Introspector returns the "wrong" declaring class for overridden read
// methods, which in turn violates expectations in {@link ExtendedBeanInfo} regarding
// method equality. Spring's {@link ClassUtils#getMostSpecificMethod(Method, Class)}
// helps out here, and is now put into use in ExtendedBeanInfo as well.
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "targetMethod"), is(true));
@@ -973,8 +917,56 @@ public class ExtendedBeanInfoTests {
}
}
interface Spr9453<T> {
T getProp();
}
interface Book {
}
interface TextBook extends Book {
}
interface LawBook extends TextBook {
}
interface BookOperations {
Book getBook();
void setBook(Book book);
}
interface TextBookOperations extends BookOperations {
@Override
TextBook getBook();
}
abstract class Library {
public Book getBook() {
return null;
}
public void setBook(Book book) {
}
}
class LawLibrary extends Library implements TextBookOperations {
@Override
public LawBook getBook() {
return null;
}
}
static class WithStaticWriteMethod {
public static void setProp1(String prop1) {
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Unit tests for {@link SimpleNonIndexedPropertyDescriptor} and
* Unit tests for {@link SimplePropertyDescriptor} and
* {@link SimpleIndexedPropertyDescriptor}.
*
* @author Chris Beams
@@ -39,7 +39,7 @@ public class SimplePropertyDescriptorTests {
@Test
public void toStringOutput() throws IntrospectionException, SecurityException, NoSuchMethodException {
{
Object pd = new SimpleNonIndexedPropertyDescriptor("foo", null, null);
Object pd = new SimplePropertyDescriptor("foo", null, null);
assertThat(pd.toString(), containsString(
"PropertyDescriptor[name=foo, propertyType=null, readMethod=null"));
}
@@ -49,7 +49,7 @@ public class SimplePropertyDescriptorTests {
public Object setFoo(String foo) { return null; }
}
Method m = C.class.getMethod("setFoo", String.class);
Object pd = new SimpleNonIndexedPropertyDescriptor("foo", null, m);
Object pd = new SimplePropertyDescriptor("foo", null, m);
assertThat(pd.toString(), allOf(
containsString("PropertyDescriptor[name=foo"),
containsString("propertyType=class java.lang.String"),
@@ -76,10 +76,10 @@ public class SimplePropertyDescriptorTests {
@Test
public void nonIndexedEquality() throws IntrospectionException, SecurityException, NoSuchMethodException {
Object pd1 = new SimpleNonIndexedPropertyDescriptor("foo", null, null);
Object pd1 = new SimplePropertyDescriptor("foo", null, null);
assertThat(pd1, equalTo(pd1));
Object pd2 = new SimpleNonIndexedPropertyDescriptor("foo", null, null);
Object pd2 = new SimplePropertyDescriptor("foo", null, null);
assertThat(pd1, equalTo(pd2));
assertThat(pd2, equalTo(pd1));
@@ -89,12 +89,12 @@ public class SimplePropertyDescriptorTests {
public String getFoo() { return null; }
}
Method wm1 = C.class.getMethod("setFoo", String.class);
Object pd3 = new SimpleNonIndexedPropertyDescriptor("foo", null, wm1);
Object pd3 = new SimplePropertyDescriptor("foo", null, wm1);
assertThat(pd1, not(equalTo(pd3)));
assertThat(pd3, not(equalTo(pd1)));
Method rm1 = C.class.getMethod("getFoo");
Object pd4 = new SimpleNonIndexedPropertyDescriptor("foo", rm1, null);
Object pd4 = new SimplePropertyDescriptor("foo", rm1, null);
assertThat(pd1, not(equalTo(pd4)));
assertThat(pd4, not(equalTo(pd1)));
@@ -147,4 +147,5 @@ public class SimplePropertyDescriptorTests {
assertThat(pd1, not(equalTo(pd7)));
assertThat(pd7, not(equalTo(pd1)));
}
}
@@ -712,6 +712,20 @@ public class DefaultListableBeanFactoryTests {
factory.getMergedBeanDefinition("child"), factory.getMergedBeanDefinition("child"));
}
@Test
public void testGetTypeWorksAfterParentChildMerging() {
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);
ChildBeanDefinition childDefinition = new ChildBeanDefinition("parent", DerivedTestBean.class, null, null);
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("parent", parentDefinition);
factory.registerBeanDefinition("child", childDefinition);
factory.freezeConfiguration();
assertEquals(TestBean.class, factory.getType("parent"));
assertEquals(DerivedTestBean.class, factory.getType("child"));
}
@Test
public void testNameAlreadyBound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="abstractFactoryBean" class="org.springframework.beans.factory.FactoryBeanTests$AbstractFactoryBean" abstract="true"/>
</beans>
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
/**
@@ -38,6 +39,7 @@ public final class FactoryBeanTests {
private static final Class<?> CLASS = FactoryBeanTests.class;
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
private static final Resource WITH_AUTOWIRING_CONTEXT = qualifiedResource(CLASS, "withAutowiring.xml");
private static final Resource ABSTRACT_CONTEXT = qualifiedResource(CLASS, "abstract.xml");
@Test
public void testFactoryBeanReturnsNull() throws Exception {
@@ -80,6 +82,20 @@ public final class FactoryBeanTests {
assertSame(gamma, beta.getGamma());
}
@Test
public void testAbstractFactoryBeanViaAnnotation() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansWithAnnotation(Component.class);
}
@Test
public void testAbstractFactoryBeanViaType() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(ABSTRACT_CONTEXT);
factory.getBeansOfType(AbstractFactoryBean.class);
}
public static class NullReturningFactoryBean implements FactoryBean<Object> {
@@ -152,6 +168,7 @@ public final class FactoryBeanTests {
}
@Component
public static class BetaFactoryBean implements FactoryBean<Object> {
private Beta beta;
@@ -176,4 +193,7 @@ public final class FactoryBeanTests {
}
}
public abstract static class AbstractFactoryBean implements FactoryBean<Object> {
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.beans.annotation;
package org.springframework.beans.factory.annotation;
import static org.junit.Assert.*;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.beans.annotation;
package org.springframework.beans.factory.annotation;
import static org.junit.Assert.*;
@@ -28,8 +28,6 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -0,0 +1,192 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class AutowireUtilsTests {
@Test
public void genericMethodReturnTypes() {
Method notParameterized = ReflectionUtils.findMethod(MyTypeWithMethods.class, "notParameterized", new Class[]{});
assertEquals(String.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(notParameterized, new Object[]{}, getClass().getClassLoader()));
Method notParameterizedWithArguments = ReflectionUtils.findMethod(MyTypeWithMethods.class, "notParameterizedWithArguments",
new Class[] { Integer.class, Boolean.class });
assertEquals(String.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(notParameterizedWithArguments, new Object[] { 99, true }, getClass().getClassLoader()));
Method createProxy = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createProxy", new Class[] { Object.class });
assertEquals(String.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createProxy, new Object[] { "foo" }, getClass().getClassLoader()));
Method createNamedProxyWithDifferentTypes = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedProxy",
new Class[] { String.class, Object.class });
assertEquals(Long.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDifferentTypes, new Object[] { "enigma", 99L }, getClass().getClassLoader()));
Method createNamedProxyWithDuplicateTypes = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedProxy",
new Class[] { String.class, Object.class });
assertEquals(String.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDuplicateTypes, new Object[] { "enigma", "foo" }, getClass().getClassLoader()));
Method createMock = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createMock", new Class[] { Class.class });
assertEquals(Runnable.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createMock, new Object[] { Runnable.class }, getClass().getClassLoader()));
assertEquals(Runnable.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createMock, new Object[] { Runnable.class.getName() }, getClass().getClassLoader()));
Method createNamedMock = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedMock", new Class[] { String.class,
Class.class });
assertEquals(Runnable.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedMock, new Object[] { "foo", Runnable.class }, getClass().getClassLoader()));
Method createVMock = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createVMock",
new Class[] { Object.class, Class.class });
assertEquals(Runnable.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(createVMock, new Object[] { "foo", Runnable.class }, getClass().getClassLoader()));
// Ideally we would expect String.class instead of Object.class, but
// resolveReturnTypeForFactoryMethod() does not currently support this form of
// look-up.
Method extractValueFrom = ReflectionUtils.findMethod(MyTypeWithMethods.class, "extractValueFrom",
new Class[] { MyInterfaceType.class });
assertEquals(Object.class,
AutowireUtils.resolveReturnTypeForFactoryMethod(extractValueFrom, new Object[] { new MySimpleInterfaceType() }, getClass().getClassLoader()));
// Ideally we would expect Boolean.class instead of Object.class, but this
// information is not available at run-time due to type erasure.
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
map.put(0, false);
map.put(1, true);
Method extractMagicValue = ReflectionUtils.findMethod(MyTypeWithMethods.class, "extractMagicValue", new Class[] { Map.class });
assertEquals(Object.class, AutowireUtils.resolveReturnTypeForFactoryMethod(extractMagicValue, new Object[] { map }, getClass().getClassLoader()));
}
public interface MyInterfaceType<T> {
}
public class MySimpleInterfaceType implements MyInterfaceType<String> {
}
public static class MyTypeWithMethods<T> {
public MyInterfaceType<Integer> integer() {
return null;
}
public MySimpleInterfaceType string() {
return null;
}
public Object object() {
return null;
}
@SuppressWarnings("rawtypes")
public MyInterfaceType raw() {
return null;
}
public String notParameterized() {
return null;
}
public String notParameterizedWithArguments(Integer x, Boolean b) {
return null;
}
/**
* Simulates a factory method that wraps the supplied object in a proxy of the
* same type.
*/
public static <T> T createProxy(T object) {
return null;
}
/**
* Similar to {@link #createProxy(Object)} but adds an additional argument before
* the argument of type {@code T}. Note that they may potentially be of the same
* time when invoked!
*/
public static <T> T createNamedProxy(String name, T object) {
return null;
}
/**
* Simulates factory methods found in libraries such as Mockito and EasyMock.
*/
public static <MOCK> MOCK createMock(Class<MOCK> toMock) {
return null;
}
/**
* Similar to {@link #createMock(Class)} but adds an additional method argument
* before the parameterized argument.
*/
public static <T> T createNamedMock(String name, Class<T> toMock) {
return null;
}
/**
* Similar to {@link #createNamedMock(String, Class)} but adds an additional
* parameterized type.
*/
public static <V extends Object, T> T createVMock(V name, Class<T> toMock) {
return null;
}
/**
* Extract some value of the type supported by the interface (i.e., by a concrete,
* non-generic implementation of the interface).
*/
public static <T> T extractValueFrom(MyInterfaceType<T> myInterfaceType) {
return null;
}
/**
* Extract some magic value from the supplied map.
*/
public static <K, V> V extractMagicValue(Map<K, V> map) {
return null;
}
public void readIntegerInputMessage(MyInterfaceType<Integer> message) {
}
public void readIntegerArrayInputMessage(MyInterfaceType<Integer>[] message) {
}
public void readGenericArrayInputMessage(T[] message) {
}
}
}
@@ -16,13 +16,9 @@
package org.springframework.beans.factory.support;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
@@ -37,21 +33,23 @@ import java.util.Set;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.UrlResource;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import org.springframework.tests.sample.beans.GenericBean;
import org.springframework.tests.sample.beans.GenericIntegerBean;
import org.springframework.tests.sample.beans.GenericSetOfIntegerBean;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
@@ -115,7 +113,7 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(GenericIntegerBean.class);
List input = new ArrayList();
List<Integer> input = new ArrayList<Integer>();
input.add(1);
rbd.getPropertyValues().add("testBeanList", input);
@@ -655,18 +653,17 @@ public class BeanFactoryGenericsTests {
}
/**
* Tests support for parameterized {@code factory-method} declarations such
* as Mockito {@code mock()} method which has the following signature.
*
* <pre>{@code
* Tests support for parameterized static {@code factory-method} declarations such as
* Mockito's {@code mock()} method which has the following signature.
* <pre>
* {@code
* public static <T> T mock(Class<T> classToMock)
* }</pre>
*
* See SPR-9493
* @since 3.2
* }
* </pre>
* <p>See SPR-9493
*/
@Test
public void parameterizedFactoryMethod() {
public void parameterizedStaticFactoryMethod() {
RootBeanDefinition rbd = new RootBeanDefinition(Mockito.class);
rbd.setFactoryMethodName("mock");
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
@@ -678,6 +675,100 @@ public class BeanFactoryGenericsTests {
assertEquals(1, beans.size());
}
/**
* Tests support for parameterized instance {@code factory-method} declarations such
* as EasyMock's {@code IMocksControl.createMock()} method which has the following
* signature.
* <pre>
* {@code
* public <T> T createMock(Class<T> toMock)
* }
* </pre>
* <p>See SPR-10411
*/
@Test
public void parameterizedInstanceFactoryMethod() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
bf.registerBeanDefinition("mock", rbd);
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@Test
public void parameterizedInstanceFactoryMethodWithNonResolvedClassName() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
bf.registerBeanDefinition("mock", rbd);
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@Test
public void parameterizedInstanceFactoryMethodWithWrappedClassName() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClassName(Mockito.class.getName());
rbd.setFactoryMethodName("mock");
// TypedStringValue used to be equivalent to an XML-defined argument String
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName()));
bf.registerBeanDefinition("mock", rbd);
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@Test
public void parameterizedInstanceFactoryMethodWithInvalidClassName() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
bf.registerBeanDefinition("mock", rbd);
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(0, beans.size());
}
@Test
public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
bf.registerBeanDefinition("mock", rbd);
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@SuppressWarnings("serial")
public static class NamedUrlList extends LinkedList<URL> {
@@ -722,4 +813,22 @@ public class BeanFactoryGenericsTests {
}
}
/**
* Pseudo-implementation of EasyMock's {@code MocksControl} class.
*/
public static class MocksControl {
@SuppressWarnings("unchecked")
public <T> T createMock(Class<T> toMock) {
return (T) Proxy.newProxyInstance(BeanFactoryGenericsTests.class.getClassLoader(), new Class<?>[] {toMock},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw new UnsupportedOperationException("mocked!");
}
});
}
}
}
@@ -16,59 +16,59 @@
package org.springframework.beans.factory.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/**
* Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor}
* forces the predicted type of a FactoryBean, effectively preventing retrieval of the
* bean from calls to #getBeansOfType(FactoryBean.class). The implementation of
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures
* that not only the predicted bean type is considered, but also the original bean
* definition's beanClass.
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures that
* not only the predicted bean type is considered, but also the original bean definition's
* beanClass.
*
* @author Chris Beams
* @author Oliver Gierke
*/
public class Spr8954Tests {
@Test
public void repro() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
private DefaultListableBeanFactory bf;
@Before
public void setUp() {
bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
bf.addBeanPostProcessor(new PredictingBPP());
}
@Test
public void repro() {
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
@SuppressWarnings("rawtypes")
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
assertThat(1, equalTo(fbBeans.size()));
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
assertThat(fbBeans.size(), is(1));
assertThat(fbBeans.keySet(), hasItem("&foo"));
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
assertThat(1, equalTo(aiBeans.size()));
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
assertThat(aiBeans.size(), is(1));
assertThat(aiBeans.keySet(), hasItem("&foo"));
}
@Test
public void findsBeansByTypeIfNotInstantiated() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
bf.addBeanPostProcessor(new PredictingBPP());
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
@SuppressWarnings("rawtypes")
@@ -77,8 +77,21 @@ public class Spr8954Tests {
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
assertThat(1, equalTo(aiBeans.size()));
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
assertThat(aiBeans.size(), is(1));
assertThat(aiBeans.keySet(), hasItem("&foo"));
}
/**
* SPR-10517
*/
@Test
public void findsFactoryBeanNameByTypeWithoutInstantiation() {
String[] names = bf.getBeanNamesForType(AnInterface.class, false, false);
assertThat(Arrays.asList(names), hasItem("&foo"));
Map<String, AnInterface> beans = bf.getBeansOfType(AnInterface.class, false, false);
assertThat(beans.size(), is(1));
assertThat(beans.keySet(), hasItem("&foo"));
}
@@ -116,8 +129,7 @@ public class Spr8954Tests {
@Override
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
return FactoryBean.class.isAssignableFrom(beanClass) ?
PredictedType.class : null;
return FactoryBean.class.isAssignableFrom(beanClass) ? PredictedType.class : null;
}
}
@@ -55,11 +55,11 @@ public class FactoryMethods {
return new FactoryMethods(tb, name, num);
}
static FactoryMethods newInstance(TestBean tb, int num, Integer something) {
static ExtendedFactoryMethods newInstance(TestBean tb, int num, Integer something) {
if (something != null) {
throw new IllegalStateException("Should never be called with non-null value");
}
return new FactoryMethods(tb, null, num);
return new ExtendedFactoryMethods(tb, null, num);
}
@SuppressWarnings("unused")
@@ -120,4 +120,12 @@ public class FactoryMethods {
this.name = name;
}
public static class ExtendedFactoryMethods extends FactoryMethods {
ExtendedFactoryMethods(TestBean tb, String name, int num) {
super(tb, name, num);
}
}
}
@@ -41,10 +41,12 @@ public class ProfileXmlBeanDefinitionTests {
private static final String PROD_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-prodProfile.xml";
private static final String DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-devProfile.xml";
private static final String NOT_DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-notDevProfile.xml";
private static final String ALL_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-noProfile.xml";
private static final String MULTI_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-multiProfile.xml";
private static final String MULTI_NOT_DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-multiProfileNotDev.xml";
private static final String MULTI_ELIGIBLE_SPACE_DELIMITED_XML = "ProfileXmlBeanDefinitionTests-spaceDelimitedProfile.xml";
private static final String UNKOWN_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-unknownProfile.xml";
private static final String UNKNOWN_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-unknownProfile.xml";
private static final String DEFAULT_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-defaultProfile.xml";
private static final String CUSTOM_DEFAULT_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-customDefaultProfile.xml";
private static final String DEFAULT_AND_DEV_ELIGIBLE_XML = "ProfileXmlBeanDefinitionTests-defaultAndDevProfile.xml";
@@ -71,10 +73,15 @@ public class ProfileXmlBeanDefinitionTests {
assertThat(beanFactoryFor(PROD_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, NONE_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, PROD_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, PROD_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(DEV_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, DEV_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(NOT_DEV_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, DEV_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(ALL_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
@@ -86,13 +93,19 @@ public class ProfileXmlBeanDefinitionTests {
assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, NONE_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, UNKNOWN_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, DEV_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, PROD_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_NOT_DEV_ELIGIBLE_XML, MULTI_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, NONE_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, UNKNOWN_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, DEV_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, PROD_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(MULTI_ELIGIBLE_SPACE_DELIMITED_XML, MULTI_ACTIVE), containsTargetBean());
assertThat(beanFactoryFor(UNKOWN_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean()));
assertThat(beanFactoryFor(UNKNOWN_ELIGIBLE_XML, MULTI_ACTIVE), not(containsTargetBean()));
}
@Test
@@ -29,7 +29,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.ObjectUtils;
/**
* @author Rick Evans
@@ -38,13 +38,13 @@ import org.springframework.tests.sample.beans.TestBean;
public class XmlBeanDefinitionReaderTests extends TestCase {
public void testSetParserClassSunnyDay() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(DefaultBeanDefinitionDocumentReader.class);
}
public void testSetParserClassToNull() {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(null);
fail("Should have thrown IllegalArgumentException (null parserClass)");
}
@@ -54,7 +54,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
public void testSetParserClassToUnsupportedParserType() throws Exception {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
new XmlBeanDefinitionReader(registry).setDocumentReaderClass(String.class);
fail("Should have thrown IllegalArgumentException (unsupported parserClass)");
}
@@ -64,7 +64,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
public void testWithOpenInputStream() {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)");
@@ -74,7 +74,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithOpenInputStreamAndExplicitValidationMode() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new InputStreamResource(getClass().getResourceAsStream("test.xml"));
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD);
@@ -83,14 +83,14 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithImport() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("import.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);
}
public void testWithWildcardImport() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("importPattern.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);
@@ -98,7 +98,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
public void testWithInputSource() {
try {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml"));
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
fail("Should have thrown BeanDefinitionStoreException (can't determine validation mode)");
@@ -108,7 +108,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithInputSourceAndExplicitValidationMode() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
InputSource resource = new InputSource(getClass().getResourceAsStream("test.xml"));
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_DTD);
@@ -117,7 +117,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
public void testWithFreshInputStream() {
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();;
SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
Resource resource = new ClassPathResource("test.xml", getClass());
new XmlBeanDefinitionReader(registry).loadBeanDefinitions(resource);
testBeanDefinitions(registry);
@@ -133,9 +133,10 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
assertEquals(TestBean.class.getName(), registry.getBeanDefinition("rod").getBeanClassName());
assertEquals(TestBean.class.getName(), registry.getBeanDefinition("aliased").getBeanClassName());
assertTrue(registry.isAlias("youralias"));
assertEquals(2, registry.getAliases("aliased").length);
assertEquals("myalias", registry.getAliases("aliased")[0]);
assertEquals("youralias", registry.getAliases("aliased")[1]);
String[] aliases = registry.getAliases("aliased");
assertEquals(2, aliases.length);
assertTrue(ObjectUtils.containsElement(aliases, "myalias"));
assertTrue(ObjectUtils.containsElement(aliases, "youralias"));
}
public void testDtdValidationAutodetect() throws Exception {
@@ -147,7 +148,7 @@ public class XmlBeanDefinitionReaderTests extends TestCase {
}
private void doTestValidation(String resourceName) throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();;
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
Resource resource = new ClassPathResource(resourceName, getClass());
new XmlBeanDefinitionReader(factory).loadBeanDefinitions(resource);
TestBean bean = (TestBean) factory.getBean("testBean");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,6 +71,11 @@ public class DerivedTestBean extends TestBean implements Serializable, BeanNameA
setSpouse(new TestBean(name));
}
@Override
public TestBean getSpouse() {
return (TestBean) super.getSpouse();
}
public void initialize() {
this.initialized = true;
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
profile="!dev,prod">
<bean id="foo" class="java.lang.String"/>
</beans>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
profile="!dev">
<bean id="foo" class="java.lang.String"/>
</beans>
@@ -35,11 +35,10 @@
</property>
</bean>
<bean id="pJenny" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
<bean id="pJenny" class="org.springframework.tests.sample.beans.DerivedTestBean" scope="prototype">
<property name="name"><value>Jenny</value></property>
<property name="age"><value>30</value></property>
<property name="spouse">
<!-- Could use id and href -->
<ref local="david"/>
</property>
</bean>
@@ -316,44 +316,52 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
this.cacheName = this.beanName;
}
// Fetch cache region: If none with the given name exists,
// create one on the fly.
Ehcache rawCache;
if (this.cacheManager.cacheExists(this.cacheName)) {
if (logger.isDebugEnabled()) {
logger.debug("Using existing EhCache cache region '" + this.cacheName + "'");
}
rawCache = this.cacheManager.getEhcache(this.cacheName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Creating new EhCache cache region '" + this.cacheName + "'");
}
rawCache = createCache();
this.cacheManager.addCache(rawCache);
}
synchronized (this.cacheManager) {
// Fetch cache region: If none with the given name exists,
// create one on the fly.
Ehcache rawCache;
boolean cacheExists = this.cacheManager.cacheExists(this.cacheName);
if (this.cacheEventListeners != null) {
for (CacheEventListener listener : this.cacheEventListeners) {
rawCache.getCacheEventNotificationService().registerListener(listener);
if (cacheExists) {
if (logger.isDebugEnabled()) {
logger.debug("Using existing EhCache cache region '" + this.cacheName + "'");
}
rawCache = this.cacheManager.getEhcache(this.cacheName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Creating new EhCache cache region '" + this.cacheName + "'");
}
rawCache = createCache();
}
}
if (this.statisticsEnabled) {
rawCache.setStatisticsEnabled(true);
}
if (this.sampledStatisticsEnabled) {
rawCache.setSampledStatisticsEnabled(true);
}
if (this.disabled) {
rawCache.setDisabled(true);
}
// Decorate cache if necessary.
Ehcache decoratedCache = decorateCache(rawCache);
if (decoratedCache != rawCache) {
this.cacheManager.replaceCacheWithDecoratedCache(rawCache, decoratedCache);
if (this.cacheEventListeners != null) {
for (CacheEventListener listener : this.cacheEventListeners) {
rawCache.getCacheEventNotificationService().registerListener(listener);
}
}
// Needs to happen after listener registration but before setStatisticsEnabled
if (!cacheExists) {
this.cacheManager.addCache(rawCache);
}
if (this.statisticsEnabled) {
rawCache.setStatisticsEnabled(true);
}
if (this.sampledStatisticsEnabled) {
rawCache.setSampledStatisticsEnabled(true);
}
if (this.disabled) {
rawCache.setDisabled(true);
}
Ehcache decoratedCache = decorateCache(rawCache);
if (decoratedCache != rawCache) {
this.cacheManager.replaceCacheWithDecoratedCache(rawCache, decoratedCache);
}
this.cache = decoratedCache;
}
this.cache = decoratedCache;
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +17,9 @@
package org.springframework.scheduling.commonj;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import javax.naming.NamingException;
import commonj.work.Work;
@@ -54,10 +53,8 @@ import org.springframework.util.Assert;
* server's JNDI environment, as defined in the server's management console.
*
* <p><b>Note: At the time of this writing, the CommonJ WorkManager facility
* is only supported on IBM WebSphere 6.0+ and BEA WebLogic 9.0+,
* is only supported on IBM WebSphere 6.1+ and BEA WebLogic 9.0+,
* despite being such a crucial API for an application server.</b>
* (There is a similar facility available on WebSphere 5.1 Enterprise,
* though, which we will discuss below.)
*
* <p><b>On JBoss and GlassFish, a similar facility is available through
* the JCA WorkManager.</b> See the
@@ -80,8 +77,7 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
/**
* Specify the CommonJ WorkManager to delegate to.
* <p>Alternatively, you can also specify the JNDI name
* of the target WorkManager.
* <p>Alternatively, you can also specify the JNDI name of the target WorkManager.
* @see #setWorkManagerName
*/
public void setWorkManager(WorkManager workManager) {
@@ -90,9 +86,8 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
/**
* Set the JNDI name of the CommonJ WorkManager.
* <p>This can either be a fully qualified JNDI name,
* or the JNDI name relative to the current environment
* naming context if "resourceRef" is set to "true".
* <p>This can either be a fully qualified JNDI name, or the JNDI name relative
* to the current environment naming context if "resourceRef" is set to "true".
* @see #setWorkManager
* @see #setResourceRef
*/
@@ -170,27 +165,19 @@ public class WorkManagerTaskExecutor extends JndiLocatorSupport
// Implementation of the CommonJ WorkManager interface
//-------------------------------------------------------------------------
public WorkItem schedule(Work work)
throws WorkException, IllegalArgumentException {
public WorkItem schedule(Work work) throws WorkException, IllegalArgumentException {
return this.workManager.schedule(work);
}
public WorkItem schedule(Work work, WorkListener workListener)
throws WorkException, IllegalArgumentException {
public WorkItem schedule(Work work, WorkListener workListener) throws WorkException {
return this.workManager.schedule(work, workListener);
}
public boolean waitForAll(Collection workItems, long timeout)
throws InterruptedException, IllegalArgumentException {
public boolean waitForAll(Collection workItems, long timeout) throws InterruptedException {
return this.workManager.waitForAll(workItems, timeout);
}
public Collection waitForAny(Collection workItems, long timeout)
throws InterruptedException, IllegalArgumentException {
public Collection waitForAny(Collection workItems, long timeout) throws InterruptedException {
return this.workManager.waitForAny(workItems, timeout);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import org.springframework.util.ReflectionUtils;
* JobFactory implementation that supports {@link java.lang.Runnable}
* objects as well as standard Quartz {@link org.quartz.Job} instances.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,7 +47,7 @@ import org.springframework.util.Assert;
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
* builder API instead. Alternatively, switch to Spring's {@link CronTriggerFactoryBean}
* which largely is a drop-in replacement for this class and its properties and
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
* consistently works against Quartz 1.x as well as Quartz 2.x.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ import org.springframework.util.ReflectionUtils;
* to automatically register a trigger for the corresponding JobDetail,
* instead of registering the JobDetail separately.
*
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
* in contrast to the older {@link CronTriggerBean} class.
*
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ import org.springframework.context.ApplicationContextAware;
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
* builder API instead. Alternatively, switch to Spring's {@link JobDetailFactoryBean}
* which largely is a drop-in replacement for this class and its properties and
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
* consistently works against Quartz 1.x as well as Quartz 2.x.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ import org.springframework.context.ApplicationContextAware;
* sensible defaults. This class uses the Spring bean name as job name,
* and the Quartz default group ("DEFAULT") as job group if not specified.
*
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
* in contrast to the older {@link JobDetailBean} class.
*
* @author Juergen Hoeller
@@ -62,6 +62,8 @@ public class JobDetailFactoryBean
private boolean durability = false;
private boolean requestsRecovery = false;
private String description;
private String beanName;
@@ -132,6 +134,14 @@ public class JobDetailFactoryBean
this.durability = durability;
}
/**
* Set the recovery flag for this job, i.e. whether or not the job should
* get re-executed if a 'recovery' or 'fail-over' situation is encountered.
*/
public void setRequestsRecovery(boolean requestsRecovery) {
this.requestsRecovery = requestsRecovery;
}
/**
* Set a textual description for this job.
*/
@@ -209,6 +219,7 @@ public class JobDetailFactoryBean
pvs.add("jobClass", this.jobClass);
pvs.add("jobDataMap", this.jobDataMap);
pvs.add("durability", this.durability);
pvs.add("requestsRecovery", this.requestsRecovery);
pvs.add("description", this.description);
bw.setPropertyValues(pvs);
this.jobDetail = (JobDetail) bw.getWrappedInstance();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ import org.springframework.util.ReflectionUtils;
* You need to implement your own Quartz Job as a thin wrapper for each case
* where you want a persistent job to delegate to a specific service method.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @author Alef Arendsen
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ import org.springframework.util.ReflectionUtils;
* <p>For concrete usage, check out the {@link SchedulerFactoryBean} and
* {@link SchedulerAccessorBean} classes.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.5.6
@@ -397,7 +397,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
else {
try {
Map jobDataMap = (Map) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
return (JobDetail) jobDataMap.get(JobDetailAwareTrigger.JOB_DETAIL_KEY);
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Inconsistent Quartz API: " + ex);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
* Spring bean-style class for accessing a Quartz Scheduler, i.e. for registering jobs,
* triggers and listeners on a given {@link org.quartz.Scheduler} instance.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.5.6
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,7 +74,7 @@ import org.springframework.util.CollectionUtils;
* automatically apply to Scheduler operations performed within those scopes.
* Alternatively, you may add transactional advice for the Scheduler itself.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ import org.springframework.core.Constants;
* Use Quartz 2.0's native {@code JobDetailImpl} class or the new Quartz 2.0
* builder API instead. Alternatively, switch to Spring's {@link SimpleTriggerFactoryBean}
* which largely is a drop-in replacement for this class and its properties and
* consistently works against Quartz 1.x as well as Quartz 2.0/2.1.
* consistently works against Quartz 1.x as well as Quartz 2.x.
*
* @author Juergen Hoeller
* @since 18.02.2004
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ import org.springframework.util.ReflectionUtils;
* to automatically register a trigger for the corresponding JobDetail,
* instead of registering the JobDetail separately.
*
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.0/2.1,
* <p><b>NOTE:</b> This FactoryBean works against both Quartz 1.x and Quartz 2.x,
* in contrast to the older {@link SimpleTriggerBean} class.
*
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ import org.springframework.util.ReflectionUtils;
* as bean property values. If no matching bean property is found, the entry
* is by default simply ignored. This is analogous to QuartzJobBean's behavior.
*
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0/2.1, as of Spring 3.1.
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @since 2.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,11 +39,15 @@ public interface Cache {
Object getNativeCache();
/**
* Return the value to which this cache maps the specified key. Returns
* {@code null} if the cache contains no mapping for this key.
* @param key key whose associated value is to be returned.
* Return the value to which this cache maps the specified key.
* <p>Returns {@code null} if the cache contains no mapping for this key;
* otherwise, the cached value (which may be {@code null} itself) will
* be returned in a {@link ValueWrapper}.
* @param key the key whose associated value is to be returned
* @return the value to which this cache maps the specified key,
* or {@code null} if the cache contains no mapping for this key
* contained within a {@link ValueWrapper} which may also hold
* a cached {@code null} value. A straight {@code null} being
* returned means that the cache contains no mapping for this key.
*/
ValueWrapper get(Object key);
@@ -25,6 +25,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
@@ -61,23 +62,25 @@ import org.springframework.util.StringUtils;
*/
public abstract class CacheAspectSupport implements InitializingBean {
public interface Invoker {
Object invoke();
}
private static final String CACHEABLE = "cacheable";
private static final String UPDATE = "cacheupdate";
private static final String EVICT = "cacheevict";
protected final Log logger = LogFactory.getLog(getClass());
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
private CacheManager cacheManager;
private CacheOperationSource cacheOperationSource;
private final ExpressionEvaluator evaluator = new ExpressionEvaluator();
private KeyGenerator keyGenerator = new DefaultKeyGenerator();
private boolean initialized = false;
private static final String CACHEABLE = "cacheable", UPDATE = "cacheupdate", EVICT = "cacheevict";
/**
* Set the CacheManager that this cache aspect should delegate to.
@@ -101,10 +104,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
*/
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
Assert.notEmpty(cacheOperationSources);
this.cacheOperationSource =
(cacheOperationSources.length > 1 ?
new CompositeCacheOperationSource(cacheOperationSources) :
cacheOperationSources[0]);
this.cacheOperationSource = (cacheOperationSources.length > 1 ?
new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
}
/**
@@ -134,13 +135,14 @@ public abstract class CacheAspectSupport implements InitializingBean {
throw new IllegalStateException("'cacheManager' is required");
}
if (this.cacheOperationSource == null) {
throw new IllegalStateException("The 'cacheOperationSources' property is required: "
+ "If there are no cacheable methods, then don't use a cache aspect.");
throw new IllegalStateException("The 'cacheOperationSources' property is required: " +
"If there are no cacheable methods, then don't use a cache aspect.");
}
this.initialized = true;
}
/**
* Convenience method to return a String representation of this Method
* for use in logging. Can be overridden in subclasses to provide a
@@ -161,7 +163,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
for (String cacheName : cacheNames) {
Cache cache = this.cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalArgumentException("Cannot find cache named [" + cacheName + "] for " + operation);
throw new IllegalArgumentException("Cannot find cache named '" + cacheName + "' for " + operation);
}
caches.add(cache);
}
@@ -186,39 +188,31 @@ public abstract class CacheAspectSupport implements InitializingBean {
if (targetClass == null && target != null) {
targetClass = target.getClass();
}
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);
// analyze caching information
if (!CollectionUtils.isEmpty(cacheOp)) {
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target, targetClass);
// start with evictions
inspectBeforeCacheEvicts(ops.get(EVICT));
// follow up with cacheable
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));
Object retVal = null;
Object retVal;
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));
if (status != null) {
if (status.updateRequired) {
updates.putAll(status.cUpdates);
updates.putAll(status.cacheUpdates);
}
// return cached object
else {
return status.retVal;
}
}
retVal = invoker.invoke();
inspectAfterCacheEvicts(ops.get(EVICT), retVal);
if (!updates.isEmpty()) {
update(updates, retVal);
}
return retVal;
}
@@ -229,27 +223,20 @@ public abstract class CacheAspectSupport implements InitializingBean {
inspectCacheEvicts(evictions, true, ExpressionEvaluator.NO_RESULT);
}
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions,
Object result) {
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions, Object result) {
inspectCacheEvicts(evictions, false, result);
}
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions,
boolean beforeInvocation, Object result) {
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions, boolean beforeInvocation, Object result) {
if (!evictions.isEmpty()) {
boolean log = logger.isTraceEnabled();
for (CacheOperationContext context : evictions) {
CacheEvictOperation evictOp = (CacheEvictOperation) context.operation;
if (beforeInvocation == evictOp.isBeforeInvocation()) {
if (context.isConditionPassing(result)) {
// for each cache
// lazy key initialization
Object key = null;
for (Cache cache : context.getCaches()) {
// cache-wide flush
if (evictOp.isCacheWide()) {
@@ -257,7 +244,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
if (log) {
logger.trace("Invalidating entire cache for operation " + evictOp + " on method " + context.method);
}
} else {
}
else {
// check key
if (key == null) {
key = context.generateKey();
@@ -268,7 +256,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
cache.evict(key);
}
}
} else {
}
else {
if (log) {
logger.trace("Cache condition failed on method " + context.method + " for operation " + context.operation);
}
@@ -279,49 +268,37 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
boolean updateRequired = false;
Map<CacheOperationContext, Object> cacheUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
boolean cacheHit = false;
Object retVal = null;
if (!cacheables.isEmpty()) {
boolean log = logger.isTraceEnabled();
boolean atLeastOnePassed = false;
for (CacheOperationContext context : cacheables) {
if (context.isConditionPassing()) {
atLeastOnePassed = true;
Object key = context.generateKey();
if (log) {
logger.trace("Computed cache key " + key + " for operation " + context.operation);
}
if (key == null) {
throw new IllegalArgumentException(
"Null key returned for cache operation (maybe you are using named params on classes without debug info?) "
+ context.operation);
throw new IllegalArgumentException("Null key returned for cache operation (maybe you " +
"are using named params on classes without debug info?) " + context.operation);
}
// add op/key (in case an update is discovered later on)
cUpdates.put(context, key);
boolean localCacheHit = false;
cacheUpdates.put(context, key);
// check whether the cache needs to be inspected or not (the method will be invoked anyway)
if (!updateRequired) {
if (!cacheHit) {
for (Cache cache : context.getCaches()) {
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper != null) {
retVal = wrapper.get();
localCacheHit = true;
cacheHit = true;
break;
}
}
}
if (!localCacheHit) {
updateRequired = true;
}
}
else {
if (log) {
@@ -330,51 +307,31 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
// return a status only if at least on cacheable matched
// return a status only if at least one cacheable matched
if (atLeastOnePassed) {
return new CacheStatus(cUpdates, updateRequired, retVal);
return new CacheStatus(cacheUpdates, !cacheHit, retVal);
}
}
return null;
}
private static class CacheStatus {
// caches/key
final Map<CacheOperationContext, Object> cUpdates;
final boolean updateRequired;
final Object retVal;
CacheStatus(Map<CacheOperationContext, Object> cUpdates, boolean updateRequired, Object retVal) {
this.cUpdates = cUpdates;
this.updateRequired = updateRequired;
this.retVal = retVal;
}
}
private Map<CacheOperationContext, Object> inspectCacheUpdates(Collection<CacheOperationContext> updates) {
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
Map<CacheOperationContext, Object> cacheUpdates = new LinkedHashMap<CacheOperationContext, Object>(updates.size());
if (!updates.isEmpty()) {
boolean log = logger.isTraceEnabled();
for (CacheOperationContext context : updates) {
if (context.isConditionPassing()) {
Object key = context.generateKey();
if (log) {
logger.trace("Computed cache key " + key + " for operation " + context.operation);
}
if (key == null) {
throw new IllegalArgumentException(
"Null key returned for cache operation (maybe you are using named params on classes without debug info?) "
+ context.operation);
throw new IllegalArgumentException("Null key returned for cache operation (maybe you " +
"are using named params on classes without debug info?) " + context.operation);
}
// add op/key (in case an update is discovered later on)
cUpdates.put(context, key);
cacheUpdates.put(context, key);
}
else {
if (log) {
@@ -383,14 +340,13 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
}
return cUpdates;
return cacheUpdates;
}
private void update(Map<CacheOperationContext, Object> updates, Object retVal) {
for (Map.Entry<CacheOperationContext, Object> entry : updates.entrySet()) {
CacheOperationContext operationContext = entry.getKey();
if(operationContext.canPutToCache(retVal)) {
if (operationContext.canPutToCache(retVal)) {
for (Cache cache : operationContext.getCaches()) {
cache.put(entry.getValue(), retVal);
}
@@ -398,37 +354,40 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
}
private Map<String, Collection<CacheOperationContext>> createOperationContext(Collection<CacheOperation> cacheOp,
Method method, Object[] args, Object target, Class<?> targetClass) {
Map<String, Collection<CacheOperationContext>> map = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
private Map<String, Collection<CacheOperationContext>> createOperationContext(
Collection<CacheOperation> cacheOperations, Method method, Object[] args, Object target, Class<?> targetClass) {
Map<String, Collection<CacheOperationContext>> result = new LinkedHashMap<String, Collection<CacheOperationContext>>(3);
Collection<CacheOperationContext> cacheables = new ArrayList<CacheOperationContext>();
Collection<CacheOperationContext> evicts = new ArrayList<CacheOperationContext>();
Collection<CacheOperationContext> updates = new ArrayList<CacheOperationContext>();
for (CacheOperation cacheOperation : cacheOp) {
for (CacheOperation cacheOperation : cacheOperations) {
CacheOperationContext opContext = getOperationContext(cacheOperation, method, args, target, targetClass);
if (cacheOperation instanceof CacheableOperation) {
cacheables.add(opContext);
}
if (cacheOperation instanceof CacheEvictOperation) {
evicts.add(opContext);
}
if (cacheOperation instanceof CachePutOperation) {
updates.add(opContext);
}
}
map.put(CACHEABLE, cacheables);
map.put(EVICT, evicts);
map.put(UPDATE, updates);
return map;
result.put(CACHEABLE, cacheables);
result.put(EVICT, evicts);
result.put(UPDATE, updates);
return result;
}
public interface Invoker {
Object invoke();
}
protected class CacheOperationContext {
private final CacheOperation operation;
@@ -459,8 +418,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
protected boolean isConditionPassing(Object result) {
if (StringUtils.hasText(this.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.condition(this.operation.getCondition(), this.method,
evaluationContext);
return evaluator.condition(this.operation.getCondition(), this.method, evaluationContext);
}
return true;
}
@@ -473,7 +431,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
else if (this.operation instanceof CachePutOperation) {
unless = ((CachePutOperation) this.operation).getUnless();
}
if(StringUtils.hasText(unless)) {
if (StringUtils.hasText(unless)) {
EvaluationContext evaluationContext = createEvaluationContext(value);
return !evaluator.unless(unless, this.method, evaluationContext);
}
@@ -493,12 +451,29 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
private EvaluationContext createEvaluationContext(Object result) {
return evaluator.createEvaluationContext(this.caches, this.method, this.args,
this.target, this.targetClass, result);
return evaluator.createEvaluationContext(this.caches, this.method, this.args, this.target, this.targetClass, result);
}
protected Collection<Cache> getCaches() {
return this.caches;
}
}
private static class CacheStatus {
// caches/key
final Map<CacheOperationContext, Object> cacheUpdates;
final boolean updateRequired;
final Object retVal;
CacheStatus(Map<CacheOperationContext, Object> cacheUpdates, boolean updateRequired, Object retVal) {
this.cacheUpdates = cacheUpdates;
this.updateRequired = updateRequired;
this.retVal = retVal;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -116,7 +116,10 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
(metaAnnotationTypes != null && metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME)) ||
annotationType.equals("javax.annotation.ManagedBean") ||
annotationType.equals("javax.inject.Named");
return (isStereotype && attributes != null && attributes.containsKey("value"));
return (isStereotype && attributes != null &&
attributes.containsKey("value") &&
attributes.get("value") instanceof String);
}
/**
@@ -109,7 +109,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
this.reader.setBeanNameGenerator(beanNameGenerator);
this.scanner.setBeanNameGenerator(beanNameGenerator);
this.getBeanFactory().registerSingleton(
getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
@@ -126,9 +126,9 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex
/**
* Register one or more annotated classes to be processed.
* Note that {@link #refresh()} must be called in order for the context to fully
* process the new class.
* <p>Calls to {@link #register} are idempotent; adding the same
* Note that {@link #refresh()} must be called in order for the context
* to fully process the new class.
* <p>Calls to {@code register} are idempotent; adding the same
* annotated class more than once has no additional effect.
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -230,7 +230,7 @@ public class AnnotationConfigUtils {
return new BeanDefinitionHolder(definition, beanName);
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
AnnotationMetadata metadata = abd.getMetadata();
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
@@ -260,5 +260,4 @@ public class AnnotationConfigUtils {
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
}
@@ -317,8 +317,8 @@ public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateCo
/**
* Determine whether the given new bean definition is compatible with
* the given existing bean definition.
* <p>The default implementation simply considers them as compatible
* when the bean class name matches.
* <p>The default implementation considers them as compatible when the existing
* bean definition comes from the same source or from a non-scanning source.
* @param newDefinition the new bean definition, originated from scanning
* @param existingDefinition the existing bean definition, potentially an
* explicitly defined one or a previously generated one from scanning
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -90,7 +90,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
/**
* Create a ClassPathScanningCandidateComponentProvider.
* Create a ClassPathScanningCandidateComponentProvider with a {@link StandardEnvironment}.
* @param useDefaultFilters whether to register the default filters for the
* {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
@@ -101,6 +101,15 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
this(useDefaultFilters, new StandardEnvironment());
}
/**
* Create a ClassPathScanningCandidateComponentProvider with the given {@link Environment}.
* @param useDefaultFilters whether to register the default filters for the
* {@link Component @Component}, {@link Repository @Repository},
* {@link Service @Service}, and {@link Controller @Controller}
* stereotype annotations
* @param environment the Environment to use
* @see #registerDefaultFilters()
*/
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
if (useDefaultFilters) {
registerDefaultFilters();
@@ -219,7 +228,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
logger.info("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
@@ -227,7 +236,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
logger.info("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -177,8 +177,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
private transient BeanFactory beanFactory;
private transient final Map<Class<?>, InjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<Class<?>, InjectionMetadata>(64);
private transient final Map<String, InjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<String, InjectionMetadata>(64);
/**
@@ -282,7 +282,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
if (beanType != null) {
InjectionMetadata metadata = findResourceMetadata(beanType);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType);
metadata.checkConfigMembers(beanDefinition);
}
}
@@ -298,7 +298,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
InjectionMetadata metadata = findResourceMetadata(bean.getClass());
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass());
try {
metadata.inject(bean, beanName, pvs);
}
@@ -309,12 +309,14 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
private InjectionMetadata findResourceMetadata(final Class<?> clazz) {
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz) {
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
@@ -388,7 +390,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
this.injectionMetadataCache.put(clazz, metadata);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
@@ -472,11 +474,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
public LookupElement(Member member, PropertyDescriptor pd) {
super(member, pd);
initAnnotation((AnnotatedElement) member);
}
protected abstract void initAnnotation(AnnotatedElement ae);
/**
* Return the resource name for the lookup.
*/
@@ -511,14 +510,11 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
*/
private class ResourceElement extends LookupElement {
protected boolean shareable = true;
protected final boolean shareable;
public ResourceElement(Member member, PropertyDescriptor pd) {
super(member, pd);
}
@Override
protected void initAnnotation(AnnotatedElement ae) {
AnnotatedElement ae = (AnnotatedElement) member;
Resource resource = ae.getAnnotation(Resource.class);
String resourceName = resource.name();
Class<?> resourceType = resource.type();
@@ -558,16 +554,13 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
*/
private class WebServiceRefElement extends LookupElement {
private Class<?> elementType;
private final Class<?> elementType;
private String wsdlLocation;
private final String wsdlLocation;
public WebServiceRefElement(Member member, PropertyDescriptor pd) {
super(member, pd);
}
@Override
protected void initAnnotation(AnnotatedElement ae) {
AnnotatedElement ae = (AnnotatedElement) member;
WebServiceRef resource = ae.getAnnotation(WebServiceRef.class);
String resourceName = resource.name();
Class<?> resourceType = resource.type();
@@ -647,14 +640,11 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
*/
private class EjbRefElement extends LookupElement {
private String beanName;
private final String beanName;
public EjbRefElement(Member member, PropertyDescriptor pd) {
super(member, pd);
}
@Override
protected void initAnnotation(AnnotatedElement ae) {
AnnotatedElement ae = (AnnotatedElement) member;
EJB resource = ae.getAnnotation(EJB.class);
String resourceBeanName = resource.beanName();
String resourceName = resource.name();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ import org.springframework.core.type.filter.TypeFilter;
* always registered, meaning that any attempt to disable them at the
* {@code @ComponentScan} level would be ignored.
*
* <p>See @{@link Configuration} Javadoc for usage examples.
* <p>See @{@link Configuration}'s javadoc for usage examples.
*
* @author Chris Beams
* @since 3.1
@@ -139,24 +139,18 @@ public @interface ComponentScan {
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
/**
* The type of filter to use.
* <p>Note that the filter types available are limited to those that may
* be expressed as a {@code Class} in the {@link #value()} attribute. This is
* in contrast to {@code <context:component-scan/>}, which allows for
* expression-based (i.e., string-based) filters such as AspectJ pointcuts.
* These filter types are intentionally not supported here, and not available
* in the {@link FilterType} enum.
* @see FilterType
* The type of filter to use. Default is {@link FilterType#ANNOTATION}.
*/
FilterType type() default FilterType.ANNOTATION;
/**
* The class or classes to use as the filter. In the case of
* {@link FilterType#ANNOTATION}, the class will be the annotation itself. In the
* case of {@link FilterType#ASSIGNABLE_TYPE}, the class will be the type that
* detected components should be assignable to. And in the case of
* {@link FilterType#CUSTOM}, the class will be an implementation of
* {@link FilterType#ANNOTATION}, the class will be the annotation itself.
* In the case of {@link FilterType#ASSIGNABLE_TYPE}, the class will be the
* type that detected components should be assignable to. And in the case
* of {@link FilterType#CUSTOM}, the class will be an implementation of
* {@link TypeFilter}.
* <p>When multiple classes are specified, OR logic is applied, e.g. "include
* types annotated with {@code @Foo} OR {@code @Bar}".
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
@@ -64,7 +65,7 @@ class ComponentScanAnnotationParser {
}
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) {
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
ClassPathBeanDefinitionScanner scanner =
new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"));
@@ -120,6 +121,12 @@ class ComponentScanAnnotationParser {
basePackages.add(ClassUtils.getPackageName(declaringClass));
}
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,8 +36,8 @@ import org.springframework.util.ClassUtils;
/**
* Represents a user-defined {@link Configuration @Configuration} class.
* Includes a set of {@link Bean} methods, including all such methods defined in the
* ancestry of the class, in a 'flattened-out' manner.
* Includes a set of {@link Bean} methods, including all such methods
* defined in the ancestry of the class, in a 'flattened-out' manner.
*
* @author Chris Beams
* @author Juergen Hoeller
@@ -51,15 +51,15 @@ final class ConfigurationClass {
private final Resource resource;
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<String, Class<? extends BeanDefinitionReader>>();
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
private String beanName;
private final boolean imported;
private final Set<BeanMethod> beanMethods = new LinkedHashSet<BeanMethod>();
private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
new LinkedHashMap<String, Class<? extends BeanDefinitionReader>>();
/**
* Create a new {@link ConfigurationClass} with the given name.
@@ -81,7 +81,7 @@ final class ConfigurationClass {
* using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}).
* @param metadataReader reader used to parse the underlying {@link Class}
* @param beanName name of the {@code @Configuration} class bean
* @param imported whether the given configuration class is being imported
* @since 3.1.1
*/
public ConfigurationClass(MetadataReader metadataReader, boolean imported) {
@@ -98,7 +98,7 @@ final class ConfigurationClass {
* @see ConfigurationClass#ConfigurationClass(Class, boolean)
*/
public ConfigurationClass(Class<?> clazz, String beanName) {
Assert.hasText(beanName, "bean name must not be null");
Assert.hasText(beanName, "Bean name must not be null");
this.metadata = new StandardAnnotationMetadata(clazz, true);
this.resource = new DescriptiveResource(clazz.toString());
this.beanName = beanName;
@@ -110,7 +110,7 @@ final class ConfigurationClass {
* using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}).
* @param clazz the underlying {@link Class} to represent
* @param beanName name of the {@code @Configuration} class bean
* @param imported whether the given configuration class is being imported
* @since 3.1.1
*/
public ConfigurationClass(Class<?> clazz, boolean imported) {
@@ -119,6 +119,7 @@ final class ConfigurationClass {
this.imported = imported;
}
public AnnotationMetadata getMetadata() {
return this.metadata;
}
@@ -131,6 +132,14 @@ final class ConfigurationClass {
return ClassUtils.getShortName(getMetadata().getClassName());
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return this.beanName;
}
/**
* Return whether this configuration class was registered via @{@link Import} or
* automatically registered due to being nested within another configuration class.
@@ -140,14 +149,6 @@ final class ConfigurationClass {
return this.imported;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public String getBeanName() {
return this.beanName;
}
public void addBeanMethod(BeanMethod method) {
this.beanMethods.add(method);
}
@@ -156,8 +157,7 @@ final class ConfigurationClass {
return this.beanMethods;
}
public void addImportedResource(
String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
this.importedResources.put(importedResource, readerClass);
}
@@ -166,27 +166,6 @@ final class ConfigurationClass {
}
public void validate(ProblemReporter problemReporter) {
// An @Bean method may only be overloaded through inheritance. No single
// @Configuration class may declare two @Bean methods with the same name.
final char hashDelim = '#';
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
for (BeanMethod beanMethod : beanMethods) {
String dClassName = beanMethod.getMetadata().getDeclaringClassName();
String methodName = beanMethod.getMetadata().getMethodName();
String fqMethodName = dClassName + hashDelim + methodName;
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = currentCount != null ? currentCount + 1 : 1;
methodNameCounts.put(fqMethodName, newCount);
}
for (String methodName : methodNameCounts.keySet()) {
int count = methodNameCounts.get(methodName);
if (count > 1) {
String shortMethodName = methodName.substring(methodName.indexOf(hashDelim)+1);
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
}
}
// A configuration class may not be final (CGLIB limitation)
if (getMetadata().isAnnotated(Configuration.class.getName())) {
if (getMetadata().isFinal()) {
@@ -194,12 +173,28 @@ final class ConfigurationClass {
}
}
// An @Bean method may only be overloaded through inheritance. No single
// @Configuration class may declare two @Bean methods with the same name.
Map<String, Integer> methodNameCounts = new HashMap<String, Integer>();
for (BeanMethod beanMethod : this.beanMethods) {
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = currentCount != null ? currentCount + 1 : 1;
methodNameCounts.put(fqMethodName, newCount);
}
for (String fqMethodName : methodNameCounts.keySet()) {
int count = methodNameCounts.get(fqMethodName);
if (count > 1) {
String shortMethodName = ConfigurationMethod.getShortMethodName(fqMethodName);
problemReporter.error(new BeanMethodOverloadingProblem(shortMethodName, count));
}
}
for (BeanMethod beanMethod : this.beanMethods) {
beanMethod.validate(problemReporter);
}
}
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof ConfigurationClass &&
@@ -213,7 +208,7 @@ final class ConfigurationClass {
@Override
public String toString() {
return String.format("[ConfigurationClass:beanName=%s,resource=%s]", this.beanName, this.resource);
return "ConfigurationClass:beanName=" + this.beanName + ",resource=" + this.resource;
}
@@ -134,8 +134,6 @@ class ConfigurationClassBeanDefinitionReader {
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
String className = metadata.getClassName();
configBeanDef.setBeanClassName(className);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
this.registry.registerBeanDefinition(configBeanName, configBeanDef);
@@ -146,7 +144,7 @@ class ConfigurationClassBeanDefinitionReader {
}
else {
this.problemReporter.error(
new InvalidConfigurationImportProblem(className, configClass.getResource(), metadata));
new InvalidConfigurationImportProblem(metadata.getClassName(), configClass.getResource(), metadata));
}
}
@@ -158,7 +156,7 @@ class ConfigurationClassBeanDefinitionReader {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
RootBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
@@ -190,9 +188,18 @@ class ConfigurationClassBeanDefinitionReader {
// has this already been overridden (e.g. via XML)?
if (this.registry.containsBeanDefinition(beanName)) {
BeanDefinition existingBeanDef = registry.getBeanDefinition(beanName);
// is the existing bean definition one that was created from a configuration class?
if (!(existingBeanDef instanceof ConfigurationClassBeanDefinition)) {
BeanDefinition existingBeanDef = this.registry.getBeanDefinition(beanName);
// Is the existing bean definition one that was created from a configuration class?
// -> allow the current bean method to override, since both are at second-pass level.
// However, if the bean method is an overloaded case on the same configuration class,
// preserve the existing bean definition.
if (existingBeanDef instanceof ConfigurationClassBeanDefinition) {
ConfigurationClassBeanDefinition ccbd = (ConfigurationClassBeanDefinition) existingBeanDef;
if (ccbd.getMetadata().getClassName().equals(beanMethod.getConfigurationClass().getMetadata().getClassName())) {
return;
}
}
else {
// no -> then it's an external override, probably XML
// overriding is legal, return immediately
if (logger.isDebugEnabled()) {
@@ -240,7 +247,7 @@ class ConfigurationClassBeanDefinitionReader {
beanDef.setDestroyMethodName(destroyMethodName);
}
// consider scoping
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes scope = attributesFor(metadata, Scope.class);
if (scope != null) {
@@ -251,7 +258,7 @@ class ConfigurationClassBeanDefinitionReader {
}
}
// replace the original bean definition with the target one, if necessary
// Replace the original bean definition with the target one, if necessary
BeanDefinition beanDefToRegister = beanDef;
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
@@ -261,7 +268,8 @@ class ConfigurationClassBeanDefinitionReader {
}
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()", configClass.getMetadata().getClassName(), beanName));
logger.debug(String.format("Registering bean definition for @Bean method %s.%s()",
configClass.getMetadata().getClassName(), beanName));
}
registry.registerBeanDefinition(beanName, beanDefToRegister);
@@ -312,6 +320,7 @@ class ConfigurationClassBeanDefinitionReader {
public ConfigurationClassBeanDefinition(ConfigurationClass configClass) {
this.annotationMetadata = configClass.getMetadata();
setLenientConstructorResolution(false);
}
public ConfigurationClassBeanDefinition(RootBeanDefinition original, ConfigurationClass configClass) {
@@ -50,15 +50,15 @@ import org.springframework.util.Assert;
*/
class ConfigurationClassEnhancer {
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
private static final CallbackFilter CALLBACK_FILTER = new ConfigurationClassCallbackFilter();
private static final Callback DISPOSABLE_BEAN_METHOD_INTERCEPTOR = new DisposableBeanMethodInterceptor();
private static final Class<?>[] CALLBACK_TYPES =
{BeanMethodInterceptor.class, DisposableBeanMethodInterceptor.class, NoOp.class};
private static final CallbackFilter CALLBACK_FILTER = new ConfigurationClassCallbackFilter();
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
private final Callback[] callbackInstances;
@@ -103,7 +103,7 @@ class ConfigurationClassEnhancer {
private Enhancer newEnhancer(Class<?> superclass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(superclass);
enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class});
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_TYPES);
@@ -116,13 +116,13 @@ class ConfigurationClassEnhancer {
*/
private Class<?> createClass(Enhancer enhancer) {
Class<?> subclass = enhancer.createClass();
// registering callbacks statically (as opposed to threadlocal) is critical for usage in an OSGi env (SPR-5932)
// Registering callbacks statically (as opposed to thread-local)
// is critical for usage in an OSGi environment (SPR-5932)...
Enhancer.registerStaticCallbacks(subclass, this.callbackInstances);
return subclass;
}
/**
* Marker interface to be implemented by all @Configuration CGLIB subclasses.
* Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance(Class)}
@@ -192,8 +192,8 @@ class ConfigurationClassEnhancer {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Enhancer.registerStaticCallbacks(obj.getClass(), null);
// does the actual (non-CGLIB) superclass actually implement DisposableBean?
// if so, call its dispose() method. If not, just exit.
// Does the actual (non-CGLIB) superclass actually implement DisposableBean?
// If so, call its dispose() method. If not, just exit.
if (DisposableBean.class.isAssignableFrom(obj.getClass().getSuperclass())) {
return proxy.invokeSuper(obj, args);
}
@@ -242,7 +242,7 @@ class ConfigurationClassEnhancer {
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// determine whether this bean is a scoped-proxy
// Determine whether this bean is a scoped-proxy
Scope scope = AnnotationUtils.findAnnotation(beanMethod, Scope.class);
if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
@@ -251,27 +251,27 @@ class ConfigurationClassEnhancer {
}
}
// to handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances
// To handle the case of an inter-bean method reference, we must explicitly check the
// container for already cached instances.
// first, check to see if the requested bean is a FactoryBean. If so, create a subclass
// First, check to see if the requested bean is a FactoryBean. If so, create a subclass
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// this ensures that the semantics of calling a FactoryBean from within @Bean methods
// This ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
if (factoryContainsBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanName)) {
Object factoryBean = this.beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// pass through - scoped proxy factory beans are a special case and should not
// Pass through - scoped proxy factory beans are a special case and should not
// be further proxied
}
else {
// it is a candidate FactoryBean - go ahead with enhancement
// It is a candidate FactoryBean - go ahead with enhancement
return enhanceFactoryBean(factoryBean.getClass(), beanName);
}
}
if (isCurrentlyInvokedFactoryMethod(beanMethod) && !this.beanFactory.containsSingleton(beanName)) {
// the factory is calling the bean method in order to instantiate and register the bean
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
if (BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
@@ -286,7 +286,7 @@ class ConfigurationClassEnhancer {
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
else {
// the user (i.e. not the factory) is requesting this bean through a
// The user (i.e. not the factory) is requesting this bean through a
// call to the bean method, direct or indirect. The bean may have already been
// marked as 'in creation' in certain autowiring scenarios; if so, temporarily
// set the in-creation status to false in order to avoid an exception.
@@ -303,7 +303,6 @@ class ConfigurationClassEnhancer {
}
}
}
}
/**
@@ -17,11 +17,12 @@
package org.springframework.context.annotation;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.NestedIOException;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
@@ -54,7 +56,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
@@ -83,16 +85,6 @@ class ConfigurationClassParser {
private final ProblemReporter problemReporter;
private final ImportStack importStack = new ImportStack();
private final Set<String> knownSuperclasses = new LinkedHashSet<String>();
private final Set<ConfigurationClass> configurationClasses =
new LinkedHashSet<ConfigurationClass>();
private final Stack<PropertySource<?>> propertySources =
new Stack<PropertySource<?>>();
private final Environment environment;
private final ResourceLoader resourceLoader;
@@ -101,6 +93,14 @@ class ConfigurationClassParser {
private final ComponentScanAnnotationParser componentScanParser;
private final Set<ConfigurationClass> configurationClasses = new LinkedHashSet<ConfigurationClass>();
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<String, ConfigurationClass>();
private final Stack<PropertySource<?>> propertySources = new Stack<PropertySource<?>>();
private final ImportStack importStack = new ImportStack();
/**
* Create a new {@link ConfigurationClassParser} instance that will be used
@@ -149,70 +149,42 @@ class ConfigurationClassParser {
}
}
// recursively process the configuration class and its superclass hierarchy
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
if (configClass.equals(it.next())) {
it.remove();
}
}
}
// Recursively process the configuration class and its superclass hierarchy.
do {
metadata = doProcessConfigurationClass(configClass, metadata);
}
while (metadata != null);
if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
}
this.configurationClasses.add(configClass);
}
/**
* @return annotation metadata of superclass, null if none found or previously processed
* @return annotation metadata of superclass, {@code null} if none found or previously processed
*/
protected AnnotationMetadata doProcessConfigurationClass(
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// recursively process any member (nested) classes first
for (String memberClassName : metadata.getMemberClassNames()) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
processMemberClasses(metadata);
// process any @PropertySource annotations
AnnotationAttributes propertySource =
attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
int nLocations = locations.length;
if (nLocations == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < nLocations; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (nLocations == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (String location : locations) {
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
}
this.propertySources.push(ps);
}
}
processPropertySource(propertySource);
}
// process any @ComponentScan annotions
// process any @ComponentScan annotations
AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// the config class is annotated with @ComponentScan -> perform the scan immediately
@@ -228,9 +200,11 @@ class ConfigurationClassParser {
}
// process any @Import annotations
Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>());
if (!CollectionUtils.isEmpty(imports)) {
processImport(configClass, imports.toArray(new String[imports.size()]), true);
Set<Object> imports = new LinkedHashSet<Object>();
Set<Object> visited = new LinkedHashSet<Object>();
collectImports(metadata, imports, visited);
if (!imports.isEmpty()) {
processImport(configClass, imports, true);
}
// process any @ImportResource annotations
@@ -239,7 +213,8 @@ class ConfigurationClassParser {
String[] resources = importResource.getStringArray("value");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
configClass.addImportedResource(resource, readerClass);
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
@@ -252,7 +227,8 @@ class ConfigurationClassParser {
// process superclass, if any
if (metadata.hasSuperClass()) {
String superclass = metadata.getSuperClassName();
if (this.knownSuperclasses.add(superclass)) {
if (!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// superclass found, return its annotation metadata and recurse
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
@@ -279,6 +255,65 @@ class ConfigurationClassParser {
return null;
}
/**
* Register member (nested) classes that happen to be configuration classes themselves.
* @param metadata the metadata representation of the containing class
* @throws IOException if there is any problem reading metadata from a member class
*/
private void processMemberClasses(AnnotationMetadata metadata) throws IOException {
if (metadata instanceof StandardAnnotationMetadata) {
for (Class<?> memberClass : ((StandardAnnotationMetadata) metadata).getIntrospectedClass().getDeclaredClasses()) {
if (ConfigurationClassUtils.isConfigurationCandidate(new StandardAnnotationMetadata(memberClass))) {
processConfigurationClass(new ConfigurationClass(memberClass, true));
}
}
}
else {
for (String memberClassName : metadata.getMemberClassNames()) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
}
}
/**
* Process the given <code>@PropertySource</code> annotation metadata.
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
* @throws IOException if loading a property source failed
*/
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
int locationCount = locations.length;
if (locationCount == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < locationCount; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (locationCount == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (int i = locations.length - 1; i >= 0; i--) {
ps.addPropertySource(new ResourcePropertySource(locations[i], classLoader));
}
this.propertySources.push(ps);
}
}
}
/**
* Recursively collect all declared {@code @Import} values. Unlike most
* meta-annotations it is valid to have several {@code @Import}s declared with
@@ -287,69 +322,103 @@ class ConfigurationClassParser {
* <p>For example, it is common for a {@code @Configuration} class to declare direct
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
* annotation.
* @param className the class name to search
* @param imports the imports collected so far or {@code null}
* @param visited used to track visited classes to prevent infinite recursion (must not be null)
* @return a set of all {@link Import#value() import values} or {@code null}
* @param metadata the metadata representation of the class to search
* @param imports the imports collected so far
* @param visited used to track visited classes to prevent infinite recursion
* @throws IOException if there is any problem reading metadata from the named class
*/
private Set<String> getImports(String className, Set<String> imports, Set<String> visited) throws IOException {
if (visited.add(className) && !className.startsWith("java")) {
AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata();
for (String annotationType : metadata.getAnnotationTypes()) {
imports = getImports(annotationType, imports, visited);
private void collectImports(AnnotationMetadata metadata, Set<Object> imports, Set<Object> visited) throws IOException {
String className = metadata.getClassName();
if (visited.add(className)) {
if (metadata instanceof StandardAnnotationMetadata) {
StandardAnnotationMetadata stdMetadata = (StandardAnnotationMetadata) metadata;
for (Annotation ann : stdMetadata.getIntrospectedClass().getAnnotations()) {
if (!ann.annotationType().getName().startsWith("java") && !(ann instanceof Import)) {
collectImports(new StandardAnnotationMetadata(ann.annotationType()), imports, visited);
}
}
Map<String, Object> attributes = stdMetadata.getAnnotationAttributes(Import.class.getName(), false);
if (attributes != null) {
Class[] value = (Class[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
imports.addAll(Arrays.asList(value));
}
}
}
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (value != null && value.length > 0) {
imports = (imports == null ? new LinkedHashSet<String>() : imports);
imports.addAll(Arrays.asList(value));
else {
for (String annotationType : metadata.getAnnotationTypes()) {
if (!className.startsWith("java") && !className.equals(Import.class.getName())) {
try {
collectImports(
new StandardAnnotationMetadata(this.resourceLoader.getClassLoader().loadClass(annotationType)),
imports, visited);
}
catch (ClassNotFoundException ex) {
//
}
}
}
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
imports.addAll(Arrays.asList(value));
}
}
}
}
return imports;
}
private void processImport(ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports) throws IOException {
private void processImport(ConfigurationClass configClass, Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
}
else {
this.importStack.push(configClass);
AnnotationMetadata importingClassMetadata = configClass.getMetadata();
for (String candidate : classesToImport) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(candidate);
if (new AssignableTypeFilter(ImportSelector.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportSelector -> delegate to it to determine imports
try {
ImportSelector selector = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportSelector.class);
processImport(configClass, selector.selectImports(importingClassMetadata), false);
try {
for (Object candidate : classesToImport) {
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
this.metadataReaderFactory.getMetadataReader((String) candidate));
if (checkAssignability(ImportSelector.class, candidateToCheck)) {
// the candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
processImport(configClass, Arrays.asList(selector.selectImports(importingClassMetadata)), false);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}
}
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
try {
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportBeanDefinitionRegistrar.class);
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
registrar.registerBeanDefinitions(importingClassMetadata, registry);
registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
else {
// candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata,
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) :
new ConfigurationClass((MetadataReader) candidateToCheck, true));
}
}
else {
// the candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata.getClassName(), candidate);
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
this.importStack.pop();
catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load import candidate class", ex);
}
finally {
this.importStack.pop();
}
}
}
private boolean checkAssignability(Class<?> clazz, Object candidate) throws IOException {
if (candidate instanceof Class) {
return clazz.isAssignableFrom((Class) candidate);
}
else {
return new AssignableTypeFilter(clazz).match((MetadataReader) candidate, this.metadataReaderFactory);
}
}
@@ -393,27 +462,27 @@ class ConfigurationClassParser {
return this.propertySources;
}
public ImportRegistry getImportRegistry() {
ImportRegistry getImportRegistry() {
return this.importStack;
}
interface ImportRegistry {
String getImportingClassFor(String importedClass);
AnnotationMetadata getImportingClassFor(String importedClass);
}
@SuppressWarnings("serial")
private static class ImportStack extends Stack<ConfigurationClass> implements ImportRegistry {
private final Map<String, String> imports = new HashMap<String, String>();
private final Map<String, AnnotationMetadata> imports = new HashMap<String, AnnotationMetadata>();
public void registerImport(String importingClass, String importedClass) {
public void registerImport(AnnotationMetadata importingClass, String importedClass) {
this.imports.put(importedClass, importingClass);
}
public String getImportingClassFor(String importedClass) {
public AnnotationMetadata getImportingClassFor(String importedClass) {
return this.imports.get(importedClass);
}

Some files were not shown because too many files have changed in this diff Show More