Compare commits

...

280 Commits

Author SHA1 Message Date
Spring Buildmaster ecd74399a8 Release version 4.1.8.RELEASE 2015-10-15 02:39:50 -07:00
Rossen Stoyanchev a95c3d820d Protect against RFD exploits
Issue: SPR-13548
2015-10-15 10:32:51 +02:00
Juergen Hoeller 271e5fd76a Reverted StrictMapAppenderConstructor constructor back to public
Issue: SPR-13504
(cherry picked from commit 627393a)
2015-10-14 15:24:25 +02:00
Juergen Hoeller 5d36ac08ef Added missing @since tags to DeferredResult 2015-10-14 14:48:48 +02:00
Brian Clozel 49393e54a1 Build 4.1.8 SNAPSHOTs 2015-10-14 10:42:07 +02:00
Juergen Hoeller 302a069257 AbstractFileResolvingResource uses extractArchiveURL for last-modified check
Issue: SPR-13393
2015-10-13 20:09:21 +02:00
Juergen Hoeller c33c26ac5d Support for GlassFish 4.1.1 (Tyrus 1.9 - 1.12)
Issue: SPR-13566
2015-10-13 20:09:13 +02:00
Rossen Stoyanchev 0086dd830b Enforce cacheLimit in DefaultSubscriptionRegistry
When the cacheLimit is reached and there is an eviction from the
updateCache, the accessCache is now also updated.

This change also ensures that adding a destination to the cache is
protected with synchronization on the updateCache.

Issue: SPR-13555
2015-10-13 12:28:27 -04:00
Juergen Hoeller 799a03e98d Polishing 2015-10-13 16:44:51 +02:00
Juergen Hoeller c0b6d320f1 Updated compatibility statements in RequestUpgradeStrategy javadocs 2015-10-13 12:31:35 +02:00
Juergen Hoeller d7a418356e Upgrade to Tomcat 8.0.28 2015-10-13 11:52:22 +02:00
Juergen Hoeller 13283ec918 Polishing 2015-10-12 23:24:36 +02:00
Juergen Hoeller ca60d796a8 Clarified that getBody() never returns null
As the only place that historically differed, HttpComponents(Async)ClientHttpResponse returns an empty stream instead of null now.

Issue: SPR-13563
(cherry picked from commit a5f81a0)
2015-10-12 23:24:29 +02:00
Juergen Hoeller 16cb73673e Fixed ContentNegotiationManager reference in MVC docs
Issue: SPR-13558
2015-10-10 22:54:26 +02:00
Juergen Hoeller 196adbd459 Polishing 2015-10-10 22:43:51 +02:00
Juergen Hoeller de932903ca Reliable null value handling in ConcurrentMapCache, GuavaCache, JCacheCache
The 4.1 variant of this fix just introduces readResolve declarations to the existing NullHolder classes.

Issue: SPR-13553
2015-10-10 22:43:06 +02:00
Juergen Hoeller 57125c0adc AbstractApplicationContext refinements (backported from 4.2.2)
Shutdown hook triggers doClose within startupShutdownMonitor; allow for re-refresh and re-close.

Issue: SPR-13556
Issue: SPR-13425
2015-10-10 22:35:05 +02:00
Juergen Hoeller 50c59425d9 Consistently detect spring-beans.dtd reference in last path segment
Issue: SPR-13549
(cherry picked from commit 8b3b8d0)
2015-10-10 22:23:14 +02:00
Sam Brannen fe36334232 Dispel myth that Spring MVC Test requires JUnit
Issue: SPR-13552
2015-10-08 17:14:08 +02:00
Juergen Hoeller e0a139a0d4 Latest applicable dependency updates (Netty 4.0.32, Tomcat 8.0.27) 2015-10-07 15:58:15 +02:00
Juergen Hoeller 3c549ef9fa Polishing 2015-10-07 15:51:41 +02:00
Juergen Hoeller 8429c4be74 Revised TransportHandlingSockJsService for defensive transport checking and consistent logging
Issue: SPR-13545
(cherry picked from commit 966f95b)
2015-10-07 15:48:28 +02:00
Juergen Hoeller be90f7ddd4 PathResourceTests defensively compares last-modified timestamps at seconds precision
Issue: SPR-13542
(cherry picked from commit 9cf2895)
2015-10-07 15:46:46 +02:00
Juergen Hoeller 315a848e6e Portlet MVC documentation consistently refers to Portlet 2.0 spec (JSR-286)
Issue: SPR-13513
2015-09-28 23:15:28 +02:00
Juergen Hoeller 1239595672 Polishing 2015-09-28 23:11:53 +02:00
Rossen Stoyanchev 4428c347a5 StompDecoder handles partial headers correctly
Issue: SPR-13416
2015-09-23 16:53:17 -04:00
Juergen Hoeller ad167066e7 Suppress unchecked warning with JRuby 1.7.22 2015-09-23 09:45:23 +02:00
Juergen Hoeller 9c40adb0da Upgrade to JRuby 1.7.22 2015-09-23 09:36:11 +02:00
Juergen Hoeller 1d698617f6 Upgrade to AspectJ 1.8.7 2015-09-21 23:20:16 +02:00
Juergen Hoeller 60d7a7f519 Polishing 2015-09-21 23:18:58 +02:00
Juergen Hoeller f1acd2882c XhrTransport implementations do not need to redeclare interface when extending from AbstractXhrTransport
(cherry picked from commit df0b26f)
2015-09-21 23:17:40 +02:00
Juergen Hoeller aa0f11788b AbstractEmbeddedDatabaseConfigurer explicitly closes JDBC Connection on shutdown
Issue: SPR-13474
(cherry picked from commit b23c232)
2015-09-21 23:15:44 +02:00
Juergen Hoeller 7202793db0 Polishing
(cherry picked from commit bc13cb2)
2015-09-10 14:45:34 +02:00
Juergen Hoeller 045016ebf9 DeferredResult accessors based on volatile fields for proper visibility
Issue: SPR-13451
(cherry picked from commit ae0d945)
2015-09-10 14:44:51 +02:00
Juergen Hoeller df3c3127a5 ConcurrentMapCache.putIfAbsent properly supports nulls
Issue: SPR-13458
(cherry picked from commit 4dee9cb)
2015-09-10 14:43:52 +02:00
Juergen Hoeller 2c73c5a893 Polishing 2015-09-09 13:06:03 +02:00
Juergen Hoeller 987d93f2ce MessagingException provides null description (instead of empty String) to NestedRuntimeException
Issue: SPR-13447
(cherry picked from commit c4f5a0f)
2015-09-09 12:57:32 +02:00
Juergen Hoeller 8bf9257fe8 Latest applicable dependency updates (Joda-Time 2.8.2, SnakeYAML 1.16) 2015-09-08 14:51:56 +02:00
Juergen Hoeller 38db9fa855 Polishing
(cherry picked from commit 667fc7e)
2015-09-08 14:48:05 +02:00
Juergen Hoeller af5f4e6fb4 AbstractEnvironment defensively synchronizes access to activeProfiles and defaultProfiles
Issue: SPR-13213
(cherry picked from commit e393c7b)
2015-09-08 13:10:46 +02:00
Juergen Hoeller 2dcf52797c Consistent and defensive Servlet 3.0 method calls across Spring's web abstraction
(in particular, also working in debug mode where method references may get resolved early, so ternary expressions are to be avoided)
2015-09-02 18:42:43 +02:00
Juergen Hoeller de0f3aec53 Undo AsyncRestTemplate's catching of Throwable in 4.1.x
Issue: SPR-13413
Issue: SPR-12887
2015-09-02 18:36:55 +02:00
Juergen Hoeller fd2252a14e Latest applicable dependency updates (Netty 4.0.31, Rome 1.5.1) 2015-09-02 18:11:19 +02:00
Juergen Hoeller 3402c13803 Undo FutureAdapter's catching of Throwable in 4.1.x
Issue: SPR-13413
Issue: SPR-12887
2015-09-02 18:04:11 +02:00
Juergen Hoeller cc741cdc51 Polishing 2015-09-02 17:29:40 +02:00
Juergen Hoeller 8daa932e69 ASM fix #317578
http://forge.ow2.org/tracker/?func=detail&aid=317578&group_id=23&atid=100023
(cherry picked from commit 0c2b787)
2015-09-02 17:24:54 +02:00
Juergen Hoeller f562eb5ff6 Avoid ConcurrentModificationException in SingleConnectionFactory's AggregatedExceptionListener
Issue: SPR-13421
(cherry picked from commit 1ed1167)
2015-09-02 17:23:57 +02:00
Juergen Hoeller 856561fa6e AsyncRestTemplate and FutureAdapter consistently throw ExecutionException
Issue: SPR-13413
(cherry picked from commit 2bb7164)
2015-09-02 17:23:32 +02:00
Juergen Hoeller c4a9abb6be Removed misleading note on readonly and disabled flags in spring-form.tld
Issue: SPR-13397
(cherry picked from commit eaba794)
2015-09-02 17:20:40 +02:00
Juergen Hoeller a6d17a6bd7 Polishing 2015-08-26 09:56:09 +02:00
Juergen Hoeller 7aa3175a71 Completed backport of lazy CacheManager resolution (including fixed test)
Issue: SPR-12850
2015-08-26 09:55:11 +02:00
Juergen Hoeller 49161da403 Latest applicable dependency updates (Hibernate 4.3.11, Jetty 9.2.13, Tomcat 8.0.26) 2015-08-26 00:46:20 +02:00
Juergen Hoeller a35f71964a Polishing 2015-08-26 00:44:32 +02:00
Juergen Hoeller 75187e3a8e Consistent detection of meta-annotation attributes via ASM
Issue: SPR-13394
(cherry picked from commit 3430f76)
2015-08-26 00:44:18 +02:00
Juergen Hoeller 4ff23f4708 StubWebApplicationContext supports AutowireCapableBeanFactory operations (as far as possible)
This is generally worthwhile but in particular fixes a regression with our Jackson SpringHandlerInstantiator in standalone MVC tests.

Issue: SPR-13375
(cherry picked from commit 7d30017)
2015-08-25 23:38:37 +02:00
Juergen Hoeller 42d5780cd3 Avoid ambiguous property warning for methods with multiple parameters
Issue: SPR-13349
(cherry picked from commit 05a16a1)
2015-08-25 23:34:15 +02:00
Rossen Stoyanchev 33f9eadd6a Ensure concurrent WebSocketSession wrapper is used
Issue: SPR-13326
2015-08-13 08:01:50 -04:00
Juergen Hoeller 7575271075 Polishing 2015-07-30 17:52:33 +02:00
Juergen Hoeller ce50fc59ee Latest web engine updates (Jetty 9.2.12, Netty 4.0.30, Tomcat 8.0.24, Undertow 1.1.8) 2015-07-30 17:09:39 +02:00
Juergen Hoeller b77cc7ae4a Prefer use of "Java EE" over "J2EE"
(cherry picked from commit 14f27bd)
2015-07-30 14:23:53 +02:00
Juergen Hoeller 4012b4df5e Clarify acknowledge mode semantics and transaction recommendations
Issue: SPR-13278
(cherry picked from commit e5a2b34829)
2015-07-30 14:23:36 +02:00
Juergen Hoeller ac4c278d3a PropertyOrFieldReference defensively catches Exception instead of just AccessException
Issue: SPR-13247
(cherry picked from commit 34a81b6)
2015-07-30 14:08:48 +02:00
Juergen Hoeller 35b257514d Allow for overriding of computeTransactionAttribute
Issue: SPR-13246
(cherry picked from commit a8fb551)
2015-07-30 14:04:32 +02:00
Brian Clozel 3a4085a286 Fix tests
Issue: SPR-13241
2015-07-17 13:41:25 +02:00
Brian Clozel daf94ea576 PathResourceResolver should not resolve root path
When resolving resources, the PathResourceResolver creates a Resource
instance and checks whether this resource `exists()` and `isReadable()`.
While that last call returns false for folders on the file system, both
calls return true for folders located inside JARs.

If a JAR location is configured as a resource location, then
PathResourceResolver can resolve folders in JARs as valid locations and
candidates for paths resolution.

Prior to this change, the PathResourceResolver would resolve "" as a
valid resource path (here, the "/META-INF/resources/webjars" if
configured, for example) and return a "" path for this resource,
effectively turning all "/" URLs into empty ones "".

This commit fixes the resolveUrlPathInternal implementation by not
allowing empty paths as valid resource paths.

Issue: SPR-13241
2015-07-17 11:05:11 +02:00
Juergen Hoeller 65a5ce3fa4 Polishing 2015-07-07 11:19:16 +02:00
Juergen Hoeller 4fbf6a3572 DefaultSubscriptionRegistry defensively checks for removal between keySet and get calls
Issue: SPR-13205
2015-07-07 11:19:07 +02:00
Juergen Hoeller 7c72a57a4d Polishing 2015-07-07 02:10:21 +02:00
Juergen Hoeller ca9beeac9d DefaultSubscriptionRegistry uses deep LinkedMultiValueMap copies between accessCache and updateCache
Also backported CopyOnWriteArraySet use from 4.2, for defensive iteration over registered subscriptions.

Issue: SPR-13185
2015-07-07 02:08:39 +02:00
Rossen Stoyanchev 3eb54cc0b3 Avoid duplicates from <websocket:decorator-factory>
Before this change <websocket:decorator-factory> decorated to
the SubProtocolWebSocketHandler RootBeanDefinition rather than
using a RuntimeBeanReference, which led to a separate instance
of SubProtocolWebSocketHandler to be created.

Issue: SPR-13190
2015-07-06 07:52:12 -04:00
Brian Clozel 2c32873309 Fix error message typo in ShallowEtagHeaderFilter
Issue: SPR-13194
2015-07-03 21:44:41 +02:00
Sam Brannen 40fc260d45 Updated required email dependencies in reference manual
Beginning with Java 6, the JavaBeans Activation Framework (JAF) is part
of the JDK. Thus, there is no longer a need to explicitly include a
dependency on `activation.jar` when using Spring's email support in
Spring Framework 4.0 and higher which anyway requires Java 6 or higher.

This commit therefore removes the JAF requirement from the reference
manual.
2015-06-30 18:20:02 +02:00
Rossen Stoyanchev c4e0f14ec4 Polish tests 2015-06-30 12:10:01 -04:00
Juergen Hoeller 38b8262e1e XML parsing tests pass on non-English locales now, plus a revised exception message and some minor polishing
Issue: SPR-13136
2015-06-30 16:02:17 +02:00
Rossen Stoyanchev 9c3580d04e Disable DTD when parsing untrusted XML input
Issue: SPR-13136
2015-06-30 08:58:03 -04:00
Juergen Hoeller a837cbe81f Latest applicable dependency updates (Netty 4.0.29, Undertow 1.1.7) 2015-06-30 14:54:12 +02:00
Juergen Hoeller f1b42b7d8f ContentCachingResponseWrapper defensively applies content length in case of sendError/sendRedirect
Issue: SPR-13004
(cherry picked from commit 4facb2f)
2015-06-30 14:25:57 +02:00
Juergen Hoeller 3d131c9f3c YamlProcessor explicitly closes UnicodeReader
Issue: SPR-13173
(cherry picked from commit 26acb48)
2015-06-30 14:18:06 +02:00
Sam Brannen a8ac6db43b Polish resource chain documentation 2015-06-29 16:16:34 +02:00
Brian Clozel bf94344139 document XML attributes in mvc:resource-chain
Issue: SPR-12804
2015-06-29 15:35:14 +02:00
Brian Clozel b3f01998d2 Fix NPE in GzipResourceResolver
This change fixes a NullPointerException in GzipResourceResolver, which
assumed that calls to the `resolveResource` method were made with only
non-null values for request.

This is not the case for the VersionResourceResolver, which tries to
resolve resources that aren't requested per se by the HTTP request.

Issue: SPR-13149
2015-06-22 11:45:57 +02:00
Martin Lippert 8dd182f76c Fix exception in AntPathMatcher for leading *
Issue: SPR-13139
2015-06-17 16:19:59 -04:00
Juergen Hoeller b731f7ad15 ObjenesisCglibAopProxy catches NoClassDefFoundError as well
Issue: SPR-13131
2015-06-17 16:54:56 +02:00
Juergen Hoeller 9dea9d57db Polishing 2015-06-17 14:52:31 +02:00
Juergen Hoeller c85127d3f8 TransactionAttributeSourcePointcut pointcut skips target classes with TransactionalProxy marker (e.g. Spring Data proxies)
Issue: SPR-13109
2015-06-17 14:52:21 +02:00
Juergen Hoeller 846fae241b Fixed fallback mode in ObjenesisCglibAopProxy
Issue: SPR-13131
2015-06-17 14:49:34 +02:00
Juergen Hoeller d08c0669da Polishing 2015-06-16 01:42:51 +02:00
Juergen Hoeller 13a2ae27e1 Latest dependency updates (H2 1.4.187, Joda-Time 2.8.1) 2015-06-16 01:42:43 +02:00
Juergen Hoeller ef9910c3c4 ConfigurationClassParser ignores unresolvable member classes
Issue: SPR-13115
(cherry picked from commit 1c01f57)
2015-06-16 01:42:35 +02:00
Sam Brannen 33b9bd72cc Proper support for Root WAC in Spring MVC Test
The modifications to DefaultMockMvcBuilder performed in conjunction
with SPR-12553 introduced a breaking change: the WebApplicationContext
supplied to DefaultMockMvcBuilder's constructor was *always* stored in
the ServletContext as the root WebApplicationContext, overwriting a
root WebApplicationContext that had been set by the user or by the
Spring TestContext Framework (TCF) -- for example, in
AbstractGenericWebContextLoader. Consequently, the changes in SPR-12553
cause tests that use @ContextHierarchy to fail if web components rely
on the correct WebApplicationContext being stored under the
WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE key.

This commit reverts the breaking changes introduced in SPR-12553: if
the root WebApplicationContext has already been set in the
ServletContext of the WebApplicationContext supplied to
DefaultMockMvcBuilder, no action is taken.

Furthermore, this commit introduces new code to address the initial
intent of SPR-12553. Specifically, if the root WebApplicationContext
has NOT been set in the ServletContext of the WebApplicationContext
supplied to DefaultMockMvcBuilder, the application context hierarchy
will be traversed in search of the root WebApplicationContext, and the
root WebApplicationContext will then be stored under the
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE key.

Issue: SPR-13075, SPR-12553
(cherry picked from commit f6d2fe471a)
2015-06-12 21:38:34 +02:00
Juergen Hoeller bccdefdf30 Polishing 2015-06-11 18:01:00 +02:00
Juergen Hoeller 2109db0c02 Stronger warning about lookup methods not working with @Bean
Includes an updated CGLIB AOP proxy note on constructor invocations.

Issue: SPR-13108
Issue: SPR-13103
2015-06-11 18:00:12 +02:00
Juergen Hoeller 6f7ad3b1c0 WebAsyncUtils avoids reflection for creating StandardServletAsyncWebRequest
Issue: SPR-13112
(cherry picked from commit 32b9ea9)
2015-06-11 17:59:30 +02:00
Juergen Hoeller 84ae28b2bb AspectJExpressionPointcut defensively catches exceptions thrown from ShadowMatch.matchesJoinPoint
Issue: SPR-13102
(cherry picked from commit 75edb39)
2015-06-11 17:58:44 +02:00
Juergen Hoeller d2621baf0a Enabled test for AspectJ pointcut matching against lambda-defined bean
Issue: SPR-11807
(cherry picked from commit b02352d)
2015-06-11 17:57:37 +02:00
Juergen Hoeller 7a6ce1c265 Latest dependency updates (AspectJ 1.8.6, Joda-Time 2.8) 2015-06-11 17:56:01 +02:00
Juergen Hoeller 063a720ac0 Reverted enhanceFactoryBean revision in 4.1.x (making it 4.2 only)
Issue: SPR-12915
Issue: SPR-13095
2015-06-11 17:53:26 +02:00
Stephane Nicoll 3227007816 Polish
Update copyright headers
2015-06-03 11:52:45 +02:00
Stephane Nicoll daf12a9723 Allow Cache annotations to not specify any cache name
Since Spring 4.1, a CacheResolver may be configured to customize the way
the cache(s) to use for a given cache operation are retrieved. Since a
CacheResolver implementation may not use the cache names information at
all, this attribute has been made optional.

However, a fix was still applied, preventing a Cache operation without a
cache name to be defined properly. We now allow this valid use case.

Issue: SPR-13081
2015-06-03 11:51:30 +02:00
Juergen Hoeller b5bb26b7c6 Latest dependency updates (Jetty 9.2.11, Tomcat 8.0.23) 2015-06-02 15:15:36 +02:00
Juergen Hoeller ae3cc67391 Lite configuration candidate check defensively handles method introspection failure
Issue: SPR-13091
(cherry picked from commit 4f1286a)
2015-06-02 15:07:01 +02:00
Juergen Hoeller 55de4a69ae SpringSessionSynchronization's beforeCompletion unbinds after disconnect failure as well
Issue: SPR-13089
(cherry picked from commit 8c337a4)
2015-06-02 15:02:34 +02:00
Juergen Hoeller bf38b3a4fc Polishing
(cherry picked from commit 92bf32b)
2015-05-23 20:37:21 +02:00
Juergen Hoeller aa3a78aa0e SockJsTransportFailureException provides constructor variant without session id
(cherry picked from commit e0a11f2)
2015-05-23 20:37:15 +02:00
Juergen Hoeller 6cdc208c73 Polishing 2015-05-23 00:09:58 +02:00
Juergen Hoeller fd1b5e80a7 Latest dependency updates (Hibernate ORM 4.3.10, Netty 4.0.28) 2015-05-22 17:24:48 +02:00
Juergen Hoeller 3c6f1f8352 Polishing 2015-05-22 17:24:40 +02:00
Juergen Hoeller c111bd7547 Message listener containers only call Session.recover() in client acknowledge mode
Issue: SPR-13052
(cherry picked from commit fee63fd)
2015-05-22 17:24:26 +02:00
Juergen Hoeller 1177f5c0a3 ByteBufferConverter explicitly declares applicability to byte[]
Includes an optimization for simple ByteBuffer duplication.

Issue: SPR-13056
(cherry picked from commit 792b7b9)
2015-05-22 17:23:57 +02:00
Stephane Nicoll bd05e3ade2 Apply DestinationResolver to listener container
Previously, a custom `DestinationResolver` was not made available
to the underlying `MessageListener`: if a reply needs to be sent, the
default `DestinationResolver` was used.

This commit ensures that if a custom `DestinationResolver` has been set,
it is also configured accordingly for replies.

Issue: SPR-12927
2015-05-22 15:50:19 +02:00
Stephane Nicoll bd601ce2e4 Make PropertyMatches public
Issue: SPR-13054
2015-05-21 20:20:38 +02:00
Stephane Nicoll 24783303a7 Add possible matches for field access
DirectFieldAccessor now support richer NotWritablePropertyException
content, including dedicated error message and possible matches.

Issue: SPR-13053
2015-05-21 20:20:16 +02:00
Brian Clozel 9e8e7aa6b9 Fix SPR-12999 backport (missing test dependency) 2015-05-21 15:18:49 +02:00
Brian Clozel c99cc53da1 Fix directories I/O in ResourceHttpRequestHandler
Prior to this commit, the `ResourceHttpRequestHandler` would not
properly handle HTTP requests to **directories contained in JARs**.
This would result in HTTP 500 errors, caused by `FileNotFoundException`
or `NullPointerException`.

This can be tracked to webapp ClassLoader implementations in servlet
containers:
* in Jetty9x, fetching a directory within a JAR as a `Resource` and
getting its InputStream work fine, but attempting to `close()` it
results in a NullPointerException as the underlying stream is null.
* In Tomcat6x, one cannot fetch an InputStream for the same `Resource`
as it throws a FileNotFoundException.

This change adds more try/catch clauses and catches more Exception so as
to result in HTTP 200 OK responses instead of server errors. While this
is inconsistent because the same code path would result in HTTP 404 with
existing directories on the file system, there's no other simple way to
make those checks for resources contained in JARs.

Issue: SPR-12999
2015-05-21 14:54:55 +02:00
Rossen Stoyanchev cd9b58b0ab Fix typo in reference
Issue: SPR-13043
2015-05-18 15:26:25 -04:00
Juergen Hoeller ae35e84c1e Polishing
(cherry picked from commit 0711d6d)
2015-05-13 17:27:41 +02:00
Juergen Hoeller 391f72d2e4 PropertyOrFieldReference avoids NPE through defensive copy of volatile accessor reference
Issue: SPR-13023
(cherry picked from commit 9799df3)
2015-05-13 16:12:33 +02:00
Juergen Hoeller 633d13ffab Actual hasText assertion in SockJsFrame
Issue: SPR-13019
(cherry picked from commit 02d28ae)
2015-05-13 16:11:59 +02:00
Juergen Hoeller ca17dc06a5 SimpleAliasRegistry prevents NPE for alias resolved to null
Issue: SPR-13016
(cherry picked from commit e83d495)
2015-05-13 16:10:53 +02:00
Brian Clozel 51c941ca11 Fix empty URLs handling in ResourceUrlEncodingFilter
Prior to this commit, the ResourceUrlEncodingFilter would fail with a
StringIndexOutOfBoundsException when:

* the current request has a servlet context
* the URL to encode is relative and is shorter than the context value

This change defensively checks for those lengths and delegates to the
parent implementation if necessary.

Issue: SPR-13018
2015-05-13 14:38:54 +02:00
Juergen Hoeller 9e925aa86c Polishing 2015-05-11 21:52:38 +02:00
Juergen Hoeller a899e066f2 RequestResponseBodyMethodProcessor decorates ServletInputStream as well
Issue: SPR-13014
2015-05-11 21:52:30 +02:00
Brian Clozel 89694b009a Fix CachingResourceResolver key generation
When used in combination with GzipResourceResolver, the
CachingResourceResolver does not properly cache results, since it only
takes the request path as a input for cache key generation.

Here's an example of that behavior:

1. an HTTP client requests a resource with `Accept-Encoding: gzip`, so
the GzipResourceResolver can resolve a gzipped resource.
2. the configured CachingResourceResolver caches that resource.
3. another HTTP client requests the same resource, but it does not
support gzip encoding; the previously cached gzipped resource is still
returned.

This commit uses the presence/absence of gzip encoding support as an
input in cache keys generation.

Issue: SPR-12982
2015-05-11 21:18:03 +02:00
Juergen Hoeller a8f75399f8 Javadoc fixes 2015-05-11 19:04:29 +02:00
Juergen Hoeller 14cd3ef2d5 Latest dependency updates (Hibernate 4.3.9, Jackson 2.4.6, JasperReports 6.0.4, Netty 4.0.27, SLF4J 1.7.12, Tomcat 8.0.22, Undertow 1.1.4) 2015-05-11 18:06:29 +02:00
Juergen Hoeller ce4e795f09 Polishing 2015-05-11 18:05:09 +02:00
Juergen Hoeller 0cd7fed050 CustomBooleanEditor avoids potential NPE in case of allowEmpty=false
Issue: SPR-13010
(cherry picked from commit 549e888)
2015-05-11 15:43:15 +02:00
Juergen Hoeller 8e074b6b67 Avoid infinite loop in PatternMatchUtils
Issue: SPR-12971
(cherry picked from commit db80378)
2015-05-11 15:42:08 +02:00
Juergen Hoeller 5b10575ce5 Fix for ASM issue 317555
Issue: SPR-12957
(cherry picked from commit 2c043ec)
2015-05-11 15:36:59 +02:00
Juergen Hoeller 6a7aab02aa PathMatchingResourcePatternResolver skips invalid jar classpath entries
Issue: SPR-12928
(cherry picked from commit 49f3046)
2015-05-11 15:36:12 +02:00
Juergen Hoeller e95a7a47c3 StatementCreatorUtils.setValue only uses setString etc for Types.OTHER in case of Oracle
Issue: SPR-12890
(cherry picked from commit 050e581)
2015-05-11 15:35:30 +02:00
Juergen Hoeller fb7476f543 InvocableHandlerMethod logs argument resolution exceptions at debug level
Issue: SPR-12925
(cherry picked from commit 10a51a4)
2015-05-11 15:34:57 +02:00
Juergen Hoeller 56f8d17b0c FactoryBean type check logs currently-in-creation exception at debug level
Issue: SPR-12900
(cherry picked from commit 65ba72f)
2015-05-11 15:33:57 +02:00
Juergen Hoeller 6783ba2903 @Bean-returned FactoryBean proxy delegates to actual target instance now
Issue: SPR-12915
(cherry picked from commit 1da98b0)
2015-05-11 15:30:57 +02:00
Juergen Hoeller 8f6ac19f50 HttpEntity and its subclasses insist on same target type for equality
Issue: SPR-12910
(cherry picked from commit af272c2)
2015-05-11 15:29:23 +02:00
Juergen Hoeller e67a63e1f7 AnnotationAsyncExecutionAspect properly accepts ListenableFuture return type
Issue: SPR-12895
(cherry picked from commit 8b2d995)
2015-05-11 15:26:55 +02:00
Juergen Hoeller f1dbe8db27 AnnotatedElementUtils leniently ignores TypeNotPresentExceptions (just like AnnotationUtils)
Also refines logIntrospectionFailure to just log at debug level for meta-annotation introspection failures.

Issue: SPR-12889
(cherry picked from commit e78b086)
2015-05-11 15:26:03 +02:00
Sam Brannen bf423b2ca0 Remove duplicate separators when combining paths
Prior to this commit, AntPathMatcher would not correctly combine a path
that ends with a separator with a path that starts with a separator.
For example, `/foo/` + `/bar` combined into `/foo//bar`.

Specifically, this commit:

 - Removes the duplicated separator in combined paths

 - Improves RequestMappingInfo's toString() representation

 - Fixes Javadoc formatting in AntPathMatcher

 - Polishes AntPathMatcherTests

 - Polishes Javadoc in AbstractRequestCondition

Issue: SPR-12975
(cherry picked from commit a80d0e87a4)
2015-05-08 14:12:28 +02:00
Sebastien Deleuze 581cf3a0a5 Fix JSON Views code sample in the documentation
Issue: SPR-12994
2015-05-07 10:28:30 +02:00
Rossen Stoyanchev b44044e36f Allow "ws" and "wss" for isValidCorsOrigin checks
Issue: SPR-12956
2015-05-04 11:02:55 -04:00
Juergen Hoeller 34a5fb28c2 Polishing 2015-04-01 17:12:29 +02:00
Juergen Hoeller 50f49774bc CronSequenceGenerator explicitly rejects invalid incrementer delta
Issue: SPR-12871
(cherry picked from commit ceb17fc)
2015-04-01 17:11:56 +02:00
Arjen Poutsma e799554ab8 Netty4ClientHttpRequest ignores query params
Before this commit, Netty4ClientHttpRequest ignored query parameters
(?foo=bar). This commit fixes that.

Issue: SPR-12779
(cherry picked from commit caee78a)
2015-04-01 17:11:50 +02:00
Brian Clozel e2a55ced50 Fix client-library-url ignored in MVC namespace
Prior to this commit, the `client-library-url` XML attribute was not
effective in the MVC namespace, leaving the default value configured:

```xml
<websocket:sockjs client-library-url="/js/sockjs.js" />
```

This commit fixes the sockjs namespace handler and makes sure that this
attribute is configured on the `SockJsService` Bean to be created.

Issue: SPR-12874
2015-04-01 15:38:33 +02:00
Juergen Hoeller 35bf96763d Polishing 2015-03-31 18:42:28 +02:00
Juergen Hoeller fc79ea3dd7 Latest dependency updates (Reactor 1.1.6, SLF4J 1.7.11, Tomcat 8.0.21) 2015-03-31 18:41:12 +02:00
Juergen Hoeller e9e2b7369e Clarification: Lifecycle does not imply auto-startup semantics
Issue: SPR-12855
(cherry picked from commit 7e22623)
2015-03-31 18:40:27 +02:00
Juergen Hoeller 89f5248189 AnnotationUtils.getAnnotationAttributes makes Method accessible (analogous to AnnotationUtils.getValue)
Issue: SPR-12858
(cherry picked from commit 1d33fd0)
2015-03-31 18:40:21 +02:00
Juergen Hoeller d506767202 BeanWrapperImpl.setPropertyValue throws InvalidPropertyException with correct property value for nested collection case
Issue: SPR-12866
(cherry picked from commit e377fc0)
2015-03-31 18:40:10 +02:00
Spring Buildmaster d0a9bd0696 Next Development Version 2015-03-25 09:21:43 -07:00
Juergen Hoeller 97f779674f Polishing 2015-03-25 15:28:30 +01:00
Stephane Nicoll 5f6ae13002 Only require an exception CacheResolver if necessary
Previously, a cache infrastructure with only a CacheResolver would have
worked fine until the JSR-107 API is added to the classpath. When this is
the case, the JCache support kicks in and an exception cache resolver is
all of the sudden required.

The CacheResolver _is_ different as the default implementation does look
different attributes so if a custom CacheResolver is set, it is not
possible to "reuse" it as a fallback exception CacheResolver.

Now, an exception CacheResolver is only required if a JSR-107 annotation
with an "exceptionCacheName" attribute is processed (i.e. the exception
CacheResolver is lazily instantiated if necessary).

The use case of having a CachingConfigurerSupport with only a
CacheResolver was still broken though since the JCache support only looks
for a JCacheConfigurer bean (per the generic type set on
AbstractCachingConfiguration). This has been fixed as well.

Issue: SPR-12850
(cherry picked from commit 314b069)
2015-03-25 15:26:00 +01:00
Juergen Hoeller 52ed9b7106 Consistent javadoc param declarations for type variables
(cherry picked from commit d23893f)
2015-03-25 01:02:40 +01:00
Juergen Hoeller ca09eb2c59 Fixed addConverterFactory assertion
(cherry picked from commit 22670b7)
2015-03-25 00:59:33 +01:00
Juergen Hoeller 13a87453b6 TcpConnection extends java.io.Closeable
Issue: SPR-12849
(cherry picked from commit 4e28da4)
2015-03-25 00:58:56 +01:00
Juergen Hoeller 673dac5620 Removed outdated references to Servlet 2.3/2.4 2015-03-24 21:21:18 +01:00
Juergen Hoeller 6892ad42d6 Alignment with ResolvableType revision in master 2015-03-24 21:17:48 +01:00
Juergen Hoeller 1d5128ed1b Polishing 2015-03-23 22:24:23 +01:00
Juergen Hoeller 34aac078b1 Deferred import processing reliably detects late registration attempts
Issue: SPR-12838
(cherry picked from commit 1a8c6fa)
2015-03-23 22:02:41 +01:00
Stephane Nicoll f52702ea3c Restore proper use of CacheLoader
Since Guava 11, CacheLoader is only invoked with a LoadingCache but the
GuavaCache wrapper is always invoking getIfPresent(), available on the
main Guava Cache interface.

Update GuavaCache#get to check for the presence of a LoadingCache and
call the appropriate method.

Issue: SPR-12842
(cherry picked from commit 9172a6d)
2015-03-23 22:02:25 +01:00
Juergen Hoeller d2d006b68f Latest dependency updates (Groovy 2.3.11, Jetty 9.2.10, Netty 4.0.26, Undertow 1.1.3) 2015-03-21 00:37:04 +01:00
Juergen Hoeller 8d14e7736a Polishing
(cherry picked from commit 162ee36)
2015-03-21 00:35:08 +01:00
Juergen Hoeller 2de5faf56c BeansDtdResolver resolves spring-beans.dtd declarations to spring-beans-2.0.dtd file
Issue: SPR-12836
(cherry picked from commit 8e4bfa9)
2015-03-20 23:58:29 +01:00
Juergen Hoeller 5f95ff6bfd Optimized access to resolved bean type (avoiding BeanFactory locks)
Revised HandlerMethod.getBeanType() impl for both web and messaging.
In addition, HandlerMethods get created with the internal BeanFactory now.

Issue: SPR-12832
(cherry picked from commit 898c24f)
2015-03-20 23:58:22 +01:00
Juergen Hoeller 4446b5fe8a Revised DefaultManagedAwareThreadFactory to make its non-JNDI fallback work
Issue: SPR-12830
(cherry picked from commit a3e5fbf)
2015-03-20 23:56:50 +01:00
Juergen Hoeller 76649a4455 Explicit documentation on 4.1+ properties in AbstractMessageListenerContainer
(cherry picked from commit 6f98cf3)
2015-03-20 23:56:37 +01:00
Juergen Hoeller 98d00ea698 Explicit documentation on MutablePersistenceUnitInfo's addManagedPackage
Issue: SPR-12821
(cherry picked from commit 4f1d9fd)
2015-03-20 23:56:28 +01:00
Juergen Hoeller ce84fafde4 ContentCachingRequestWrapper converts IOException to IllegalStateException
Issue: SPR-12810
2015-03-13 20:19:31 +01:00
Juergen Hoeller b352dbfdeb Polishing (in particular updating javadoc references to Apache Commons)
(cherry picked from commit bc6a98c)
2015-03-13 20:13:21 +01:00
Rossen Stoyanchev f42c53d9be Support comma-separated X-Forwarded-Proto
Issue: SPR-12816
2015-03-13 13:05:11 -04:00
Brian Clozel 151e96cac4 Fix InputStream caching in ContentCachingReqWrapper
Prior to this commit, the ContentCachingRequestWrapper would immediately
consume the wrapped request's InputStream when asked for the cached
content; that caused several issues:

* the request body was read in memory even if it wasn't yet consumed by
the application, leading to inefficiencies.
* when requesting the InputStream, an empty InputStream was returned
since the original was already read.

This case only happened for form POSTs requests.

This commit makes sure that the wrapper does not alter the request
expected behavior:

* when getting the inputstream, it is wrapped in order to cache its
content
* when getting request parameters, the request body is cached and its
inputstream is consumed, as expected

Issue: SPR-12810
2015-03-13 16:11:17 +01:00
Rossen Stoyanchev a522fa36af Support comma-separated X-Forwarded-Port
Issue: SPR-12813
2015-03-13 10:02:14 -04:00
Rossen Stoyanchev 5c463a1680 Move X-Forwarded-* tests to UriComponentsBuilderTests 2015-03-13 10:02:00 -04:00
Juergen Hoeller 0280a2a994 Explicit note on change of read-only handling in 4.1
Issue: SPR-8959
2015-03-11 21:25:12 +01:00
Juergen Hoeller b455626ce1 Fine-tuned varargs handling in ReflectiveMethodResolver (including useDistance mode)
Issue: SPR-12803
Issue: SPR-12808
2015-03-11 21:18:05 +01:00
Juergen Hoeller cb6459c271 ResponseEntity's headers(HttpHeaders) accepts null value
Issue: SPR-12792
(cherry picked from commit 73e8021)
2015-03-10 15:19:06 +01:00
Juergen Hoeller 6b9e89118f StandardMultipartFile declares itself as Serializable now
Issue: SPR-12795
(cherry picked from commit 5ba7b89)
2015-03-10 15:18:43 +01:00
Juergen Hoeller f2b9a0a117 PropertyResourceConfigurerTests accepts "." in operating system name
Issue: SPR-12794
(cherry picked from commit 6fe85c2)
2015-03-10 15:18:26 +01:00
Stephane Nicoll 406adb3381 Call AsyncUncaughtExceptionHandler when necessary
If a sub-class of Future (such as ListenableFuture) is used as a return
type and an exception is thrown, the AsyncUncaughtExceptionHandler is
called. Now checking for any Future implementation instead of a faulty
strict matching.

Issue: SPR-12797
2015-03-09 09:59:12 +01:00
Sam Brannen bac012f3e8 Support @NumberFormat as a meta-annotation
This commit ensures that @NumberFormat can be used as a
meta-annotation, as was already the case for @DateTimeFormat.

In addition, this commit polishes FormattingConversionServiceTests and
MvcNamespaceTests.

Issue: SPR-12743
(backported from commits df1d90f & c3408d8)
2015-03-07 21:44:42 +01:00
Juergen Hoeller f93394171a Polishing 2015-03-06 23:51:32 +01:00
Juergen Hoeller ebe45cf079 Dependency updates for spring-oxm generation tasks
(cherry picked from commit f8fd19d)
2015-03-06 18:50:54 +01:00
Juergen Hoeller 7ed7f981c9 Polishing
(cherry picked from commit b541fc9)
2015-03-06 18:50:49 +01:00
Juergen Hoeller f01a0303f1 getTypeForFactoryBean suppresses instantiation failures for non-singleton FactoryBeans
Issue: SPR-12786
(cherry picked from commit 9b25d6a)
2015-03-06 18:10:28 +01:00
Juergen Hoeller f2691901bb ObjectToOptionalConverter preserves existing Optional instances
Issue: SPR-12785
(cherry picked from commit f786fc3)
2015-03-06 18:09:32 +01:00
Juergen Hoeller 5f305759fa Converter interface explicitly documents null values
Issue: SPR-12780
(cherry picked from commit dcb1145)
2015-03-06 18:09:13 +01:00
Rossen Stoyanchev 410fc6d763 UriComponentsBuilder.fromHttpRequest sets port correctly
Cherry-picked from commit d64c48 on master

Issue: SPR-12771
2015-03-05 21:54:46 -05:00
Juergen Hoeller 3783591083 Polishing
(cherry picked from commit e5207e6)
2015-03-02 21:56:21 +01:00
Juergen Hoeller 1259671f3f LoadTimeWeavingConfiguration should not rely on private field injection
Issue: SPR-12776
2015-03-02 21:42:01 +01:00
Juergen Hoeller 590b23ccb3 Latest dependency updates (XMLUnit 1.6, JsonPath 1.2, H2 1.4.186) 2015-03-02 20:06:36 +01:00
Juergen Hoeller 2d98988d5c Latest dependency updates (SnakeYAML 1.15, FreeMarker 2.3.22, JRuby 1.7.19, JAMon 2.81, JiBX 1.2.6, XMLUnit 1.6) 2015-03-02 14:06:06 +01:00
Juergen Hoeller 364210b0e7 Fixed javadoc 2015-03-02 14:00:05 +01:00
Sam Brannen b6f22aa514 Fully support XML config in GroovyBeanDefinitionReader
Prior to this commit, the GroovyBeanDefinitionReader claimed (via its
Javadoc) that it fully supported XML configuration files in addition to
its Groovy DSL; however, this was unfortunately inaccurate since XML
validation was disabled by default which led to certain features of XML
configuration not working. For example, it was impossible to define a
<qualifier> in an XML config file without specifying the 'type'
attribute (which has a default value defined in the spring-beans XSD).

This commit fixes this issue by ensuring that bean definitions in XML
resources are loaded with a "standard" XmlBeanDefinitionReader that is
created with default settings (i.e., with XML validation enabled). With
regard to backwards compatibility, bean definitions defined using the
Groovy DSL are still loaded with an XmlBeanDefinitionReader that has
XML validation disabled by default which is necessary for proper
parsing of the Groovy DSL.

Issue: SPR-12769
(cherry picked from commit 7edc7c2c8f)
2015-02-28 23:19:57 +01:00
Sam Brannen 522c1b1b3d Polish Javadoc for GroovyBeanDefinitionReader 2015-02-28 23:19:27 +01:00
Sam Brannen 55eb5b622c Support XML config fully in web integration tests
Prior to this commit, it was impossible to use all features of XML
configuration (e.g., the <qualifier> tag) in web-based integration
tests (loaded using @WebAppConfiguration, @ContextConfiguration, etc.)
if the Groovy library was on the classpath. The reason is that the
GroovyBeanDefinitionReader used internally by
GenericGroovyXmlWebContextLoader disables XML validation for its
internal XmlBeanDefinitionReader, and this prevents some XML
configuration features from working properly. For example, the default
value for the 'type' attribute (defined in the spring-beans XSD) of the
<qualifier> tag gets ignored, resulting in an exception when the
application context is loaded.

This commit addresses this issue by refactoring the implementation of
loadBeanDefinitions() in GenericGroovyXmlWebContextLoader to use an
XmlBeanDefinitionReader or GroovyBeanDefinitionReader depending on the
file extension of the resource location from which bean definitions
should be loaded. This aligns the functionality of
GenericGroovyXmlWebContextLoader with the existing functionality of
GenericGroovyXmlContextLoader.

Issue: SPR-12768
(cherry picked from commit 2ba1151b7f)
2015-02-28 19:12:07 +01:00
Sam Brannen 6c93745f35 Include charset in EncodedResource.equals()
Prior to this commit, the implementation of equals() in EncodedResource
was based solely on the resource and encoding. Thus, if a Charset were
specified instead of an encoding, invocations of equals() would not
work as expected.

This commit addresses this issue by including the charset in the
implementation of equals() and introducing corresponding tests in a new
EncodedResourceTests class. Furthermore, this commit makes
EncodedResource immutable and updates all Javadoc to reflect support
for the encoding and charset properties.

Issue: SPR-12767
(cherry picked from commit 93c70b7440)
2015-02-28 17:54:06 +01:00
Juergen Hoeller ca9f6a1e1e Fixed javadoc warnings 2015-02-27 22:43:21 +01:00
Juergen Hoeller 3570a9a94a Polishing
(cherry picked from commit 2b34094)
2015-02-27 22:36:02 +01:00
Juergen Hoeller 91c47a9eb8 Revised documentation on AUTO_ACKNOWLEDGE behavior
Issue: SPR-12705
(cherry picked from commit c1a9e34)
2015-02-27 22:34:07 +01:00
Juergen Hoeller 7eb4679f28 RestTemplate avoids use of warn level for response errors
Protected handleResponse method replaces former private logResponseStatus/handleResponseError methods.

Issue: SPR-12760
(cherry picked from commit 594a14a)
2015-02-27 22:33:55 +01:00
Sam Brannen 0f95c81712 Refer to statement numbers in ScriptStatementFailedException
ScriptStatementFailedException now properly refers to statement numbers
instead of line numbers.

Issue: SPR-12752
(cherry picked from commit 291b3de72b)
2015-02-27 19:36:36 +01:00
Brian Clozel 2c47098b35 Allow file locations for resource handling
Prior to this change, location checks for serving resources would append
`/` to the location path it didn't already have one.

This commit makes sure not to append a `/` if the provided location is
actually a file.

Issue: SPR-12747
2015-02-27 18:46:10 +01:00
Rossen Stoyanchev b4d9fb9e6e Prevent ISE in the MockMvc PrintingResultHandler
Issue: SPR-12735
2015-02-27 11:33:57 -05:00
Rossen Stoyanchev 4a332bd0b2 Fix white space issues 2015-02-27 11:33:49 -05:00
Juergen Hoeller 772552b9ef Avoid potential deadlocks between event multicaster and singleton registry through shared lock
Issue: SPR-12739
(cherry picked from commit 81102de)
2015-02-26 20:54:00 +01:00
Juergen Hoeller 6be554cba5 Polishing
(cherry picked from commit cc33d3f)
2015-02-25 20:38:18 +01:00
Juergen Hoeller ce085a606f Revised condition override check based on method names instead of bean names
Issue: SPR-12744
(cherry picked from commit bb5b5d5)
2015-02-25 20:37:47 +01:00
Juergen Hoeller c0e550cfb4 ScriptUtils properly refers to statement numbers instead of line numbers
Issue: SPR-12752
(cherry picked from commit 8f228d1)
2015-02-25 20:37:37 +01:00
Juergen Hoeller 7a5b2e6a75 Latest dependency updates (Tomcat 8.0.20, Jetty 9.2.9, EhCache 2.9.1, EhCache-JCache 1.0.1) 2015-02-25 20:37:09 +01:00
Spring Buildmaster d7dcf8d6f4 Next Development Version 2015-02-20 03:10:10 -08:00
Juergen Hoeller d77af71e9c Revised common validation methods in AbstractMessageConverterMethodArgumentResolver
The protected validation methods are analogous to ModelAttributeMethodProcessor now.

Issue: SPR-12655
(cherry picked from commit 7191050)
2015-02-19 23:53:16 +01:00
Sebastien Deleuze 5db4e4bab0 Adjust log level for invalid SockJS or Websocket requests 2015-02-19 16:06:06 +01:00
Sebastien Deleuze 7cc56e1630 Improve error handling in WebUtils.isValidOrigin()
With this commit, WebUtils.isValidOrigin() logs an error message instead
of throwing an IllegalArgumentException when Origin header value is
invalid (for example when it does not contain the scheme).

Issue: SPR-12697
2015-02-19 14:12:10 +01:00
Juergen Hoeller b5e80390de Correct reference to executeAndReturnKey method
Issue: SPR-12639
(cherry picked from commit f20a624)
2015-02-18 22:30:20 +01:00
Juergen Hoeller 55a14eb684 MessageHeaderAccessor defensively checks id, timestamp and contentType values
Issue: SPR-12730
(cherry picked from commit dbd353b)
2015-02-18 22:30:04 +01:00
Sam Brannen d8269dd9fe Polish reference manual regarding WebSocket
- fixed typos
 - improved grammar and punctuation
 - fixed class names

(cherry picked from commit c7a456c0bf)
2015-02-18 20:33:34 +01:00
Juergen Hoeller aae7583141 Latest dependency updates (Groovy 2.3.10, SLF4J 1.7.10) 2015-02-18 18:54:38 +01:00
Rossen Stoyanchev 6fafe63311 Ignore Pong messages in StompSubProtocolHandler
Issue: SPR-12728
2015-02-18 12:27:13 -05:00
Rossen Stoyanchev f1e406c63b Fix handling of empty payload Pong message on Jetty
Issue: SPR-12727
2015-02-18 12:27:13 -05:00
Juergen Hoeller c8a4d1649f Latest dependency updates (AspectJ 1.8.5, Joda-Time 2.7, H2 1.4.185) 2015-02-18 17:54:43 +01:00
Juergen Hoeller 8dbe753963 Polishing 2015-02-18 17:54:16 +01:00
Sebastien Deleuze 23fa37b08b Change SockJS and Websocket default allowedOrigins to same origin
This commit adds support for a same origin check that compares
Origin header to Host header. It also changes the default setting
from all origins allowed to only same origin allowed.

Issues: SPR-12697, SPR-12685
(cherry picked from commit 6062e15)
2015-02-18 17:26:55 +01:00
Sebastien Deleuze cc78d40c6b Fix SockJS origin check
This commit introduces the following changes:
 - Requests without Origin header are not rejected anymore
 - Disable Iframe when allowedOrigins is not empty and not equals to *
 - The Iframe is not cached anymore in order to have a reliable origin check
 - allowedOrigins must not be null or empty
 - allowedOrigins format is now validated (should be * or start by http(s)://)

Issue: SPR-12660
(cherry picked from commit 9b3319b)
2015-02-18 17:26:44 +01:00
Sebastien Deleuze 1dc39324b9 Add parametrized constructors to MappingJackson2MessageConverter
Issue: SPR-12724
(cherry picked from commit 8159aa9)
2015-02-18 17:24:28 +01:00
Juergen Hoeller 2a240b0dc8 ServletUriComponentsBuilder.java avoids NPE on scheme check
Issue: SPR-12723
(cherry picked from commit 61cc3b5)
2015-02-18 17:14:43 +01:00
Juergen Hoeller 3b8d878285 ScheduledAnnotationBeanPostProcessor uses target class as cache key in case of proxy
Issue: SPR-12709
(cherry picked from commit 1273c90)
2015-02-18 17:14:33 +01:00
Sam Brannen d98f626be1 Make TestPropertySourceUtils more robust
- Added assertions for pre-conditions on method arguments for all
   public utility methods.

 - Introduced additional tests in TestPropertySourceUtilsTests to verify
   the new pre-conditions.

 - Introduced INLINED_PROPERTIES_PROPERTY_SOURCE_NAME constant for the
   name of the MapPropertySource created from inlined properties; the
   name therefore no longer contains the inlined properties, but the
   original values of the inlined properties can now be logged at debug
   level.

 - Simplified tests in InlinedPropertiesTestPropertySourceTests.

Issue: SPR-12721
(cherry picked from commit 42af33034d)
2015-02-17 19:52:51 +01:00
Sam Brannen b8dbf2345c Polish Javadoc for @TestPropertySource
(cherry picked from commit 0267715c9d)
2015-02-17 19:52:13 +01:00
Sam Brannen 2b135f0d51 Open up TestPropertySourceUtils for public consumption
Spring Framework 4.1 introduced support for @TestPropertySource;
however, the utilities used to parse inlined properties and add test
property sources to the environment are currently private which
prevents reuse by third-party frameworks like Spring Boot.

This commit addresses this issue by making such utilities public.

 - TestPropertySourceUtils is now a public class.

 - Various utility methods in TestPropertySourceUtils have been made
   public.

 - addResourcePropertySourcesToEnvironment() has been renamed to
   addPropertiesFilesToEnvironment().

 - extractEnvironmentProperties() has been renamed to
   convertInlinedPropertiesToMap().

 - All public methods in TestPropertySourceUtils are now fully
   documented.

Issue: SPR-12721
(cherry picked from commit 75e0bc9271)
2015-02-17 03:14:47 +01:00
Sam Brannen e5d41d91d5 Preserve ordering of inlined props in @TestPropertySource
The initial implementation for adding inlined properties configured via
@TestPropertySource to the context's environment did not preserve the
order in which the properties were physically declared. This makes
@TestPropertySource a poor testing facility for mimicking the
production environment's configuration if the property source mechanism
used in production preserves ordering of property names -- which is the
case for YAML-based property sources used in Spring Boot, Spring Yarn,
etc.

This commit addresses this issue by ensuring that the ordering of
inlined properties declared via @TestPropertySource is preserved.
Specifically, the original functionality has been refactored. extracted
from AbstractContextLoader, and moved to TestPropertySourceUtils where
it may later be made public for general purpose use in other frameworks.

Issue: SPR-12710
(cherry picked from commit d6a799ad4a)
2015-02-16 20:33:15 +01:00
Rossen Stoyanchev f398dd03a7 Pass SockJS session attributes to HandshakeHandler
Before this change the WebSocketTransportHandler passed
Collections.emptyMap as attributes to the HandshakeHandler because
it didn't matter what attributes the underlying WebSocketSession has
since it is wrapped by the SockJsSession and that's what exposed for
use everywhere.

This change has the WebSocketTransportHandler passing the attributes
from the SockJsSession instead since it's more accurate for the
underlying WebSocketSession to have access to the same map instance
and it allows the HandshakeHandler to change the attributes even if
it doesn't need to do that today.

Issue: SPR-12716
2015-02-16 14:32:03 -05:00
Sam Brannen f82c6635d7 Add further regression tests for @TestPropertySource
This commit introduces further regression tests to ensure proper parsing
of inlined properties configured via @TestPropertySource. Specifically,
these additional tests ensure that we do not introduce a bug like the
one raised in Spring Boot issue #1110 [0].

[0] https://github.com/spring-projects/spring-boot/issues/1110

Issue: SPR-12710
(cherry picked from commit 67934a22e2)
2015-02-12 20:26:48 +01:00
Andy Wilkinson 9499e4166c Fix Animal Sniffer
Jasper Reports’ transitive dependency on spring-context (via
castor-xml which is a new dependency in 6.0.3) was being mapped by
Gradle to a dependency on the spring-context project. For reasons that
I do not fully understand this was causing -source and -javadoc jars
to be added to the project's compile classpath which is used by the
Animal Sniffer Ant task. When the task runs these jars do not exist
which causes it to fail. This commit fixes the problem by adding an
exclusion of org.springframework:spring-context to the Jasper Reports
dependencies in spring-context-support and spring-webmvc.
(cherry picked from commit 7a6a132)
2015-02-11 20:17:54 +01:00
Juergen Hoeller bf442c093c Latest dependency updates (POI 3.11, FreeMarker 2.3.21) 2015-02-11 19:04:57 +01:00
Juergen Hoeller fab8dd3d0b Combined backport of Jackson configuration enhancements: Locale/TimeZone settings, refined module configuration
Issue: SPR-12594
Issue: SPR-12634
2015-02-11 19:03:54 +01:00
Stephane Nicoll 1646f62700 BeanWrapper auto-grows arrays if necessary
Previously, only indexed access for collections were supported. When
attempting to access the element of an array that had not the requested
size, the call would fail with an IndexOutOfBoundException

This commit harmonize the binding support so that the array is updated
according to the requested index if necessary.

Issue: SPR-12706
(cherry picked from commit aa21339)
2015-02-11 19:00:39 +01:00
Juergen Hoeller c8d9bfadad Latest dependency updates (JasperReports 6.0.3, Tomcat 8.0.18, Undertow 1.1.2) 2015-02-10 22:58:33 +01:00
Juergen Hoeller 0706889222 Polishing
(cherry picked from commit 058714b)
2015-02-10 22:58:16 +01:00
Juergen Hoeller 25644dbdb9 Revised validation javadoc, plus protected validate/isBindingErrorFatal template methods
Issue: SPR-12655
(cherry picked from commit 7585be8)
2015-02-10 22:00:11 +01:00
Juergen Hoeller 181b35243e Properly honor conditions on overriding bean methods
Issue: SPR-12694
(cherry picked from commit 981aefc)
2015-02-10 21:59:31 +01:00
Juergen Hoeller 6c47b5f5d3 Avoid ConcurrentModificationException in getBeansWithAnnotation
Issue: SPR-12688
(cherry picked from commit 918bc3b)
2015-02-10 21:59:09 +01:00
Rossen Stoyanchev 4a423e50a8 Add fromHttpRequest to UriComponentsBuilder
Before this change, detection of X-Forwarded-* headers was only built
into ServletUriComponentsBuilder.

This change adds a new method for creating a UriComponentsBuilder from
an existing HttpRequest. This is equivalent to the fromUri method +
X-Forwarded-* header values.
2015-02-10 06:54:10 +01:00
Brian Clozel 0225a7776c Revisit empty body response support in HTTP client
Prior to this commit, HTTP responses without body (response status 204
or 304, Content-Length: 0) were handled properly by RestTemplates. But
some other cases were not properly managed, throwing exceptions for
valid HTTP responses.

This commit better handles HTTP responses, using a response wrapper that
can tell if a response:

* has no message body (HTTP status 1XX, 204, 304 or Content-Length:0)
* has an empty message body

This covers rfc7230 Section 3.3.3.

Issue: SPR-8016
2015-02-09 15:10:39 +01:00
Brian Clozel d57f7f8783 Sort handler matches in ResourceUrlProvider
Prior to this change, the `ResourceUrlProvider.getForLookupPath` method
would try to match handlers using the keySet order in the
handlerMappings Map. In case of several matches, the handler used for
the return value could vary, since the registration order in the
handlerMappings can't be guaranteed in the configuration.

This commit now collects all matching handlers and sort them using a
`PatternComparator`, in order to try each handler from the most specific
mapping to the least.

Issue: SPR-12647
2015-02-09 15:08:54 +01:00
Brian Clozel 4550b4a254 Avoid loss of body content in AbstractRequestLoggingFilter
Prior to this commit, the `ContentCachingRequestWrapper` class would
cache the response content only if the reponse would be consumed using
its InputStream. In case of a Form request, Spring MVC consumes the
response using the `getParameter*` Servlet API methods. This causes the
cached content to never be written.

This commit makes the `ContentCachingResponseWrapper` write the request
body to the cache buffer by using the `getParameter*` API, thus avoiding
those issues.

Issue: SPR-7913
2015-02-09 15:08:35 +01:00
Brian Clozel f902fb911c Initialize ResourceUrlProvider only once
Prior to this change, the ResourceUrlProvider would listen to
ContextRefreshedEvents and autodetect resource handlers each time. This
can cause issues when multiple contexts are involved and the last one
has no resource handler, thus clearing the previously detected ones.

This commit disables resource handlers auto-detection once some have
been detected with a refreshed context.

Issue: SPR-12592
2015-02-09 15:08:15 +01:00
Brian Clozel 77c8aa53ae Allow relative paths within resource location path
Prior to this change, location paths used for resource handling would
not allow "non-cleaned, relative paths" such as
`file://home/user/static/../static/`. When checking if the resolved
resource's path starts with the location path, a mismatch would happen
when comparing for example:

* the location `file://home/user/static/../static/`
* and the resource `file://home/user/static/resource.txt`

This commit cleans the location path before comparing it to the resource
path.

Issue: SPR-12624
2015-02-09 15:07:52 +01:00
Brian Clozel bb5da15e1c Allow protocol relative URLs in CssLink Transformer
This commit allows the use of "protcol relative URLs" (i.e. URLs without
scheme, starting with `//`), often used to serve resources automatically
from https or http with third party domains.

This syntax is allowed by RFC 3986.

Issue: SPR-12632
2015-02-09 15:07:34 +01:00
Brian Clozel 0c8d07fcff Fix context-relative default value in XML parsing
This commit fixes the default value for the contextRelative attribute of
a RedirectView, when this view is registered via a
RedirectViewController in XML. The value is set to true.

Note that the default value for this is correctly documented in
spring-mvc-4.1.xsd. Also, the documentation and implementation for its
javadoc counterpart also enforces true as a default value.

Issue: SPR-12607
2015-02-09 15:07:06 +01:00
Stephane Nicoll 47fdac9214 Clarify the use of @Cacheable in PostConstruct code
Update documentation to explicitly mention that the cache interceptor
must be fully initialized to provide the expected behavior and therefore
initialization code should not rely on this feature, i;e. typically in
PostConstruct callback.

Since the Transactional infrastructure has the exact same infrastructure,
update that section of the doc as well.

Issue: SPR-12700
2015-02-09 10:28:14 +01:00
Stephane Nicoll 7ffa845aa8 Fix broken build
Add required  `@Deprecated` annotation.
2015-02-09 10:19:41 +01:00
Stephane Nicoll 09bd7037e9 Allow MBeans to be excluded additively
Previously, one could only set the list of bean names to exclude from
auto-detection and there was no way to add additional bean names.

MBeanExporter now exposes a addExcludedBean method that can be invoked
during the initialization phase to add bean names to ignore.

Issue: SPR-12686
2015-02-09 09:42:00 +01:00
Rossen Stoyanchev 49c21a0a06 Update javadoc for MultipartFile.transferTo
Issue: SPR-12650
2015-02-02 17:30:34 -05:00
Rossen Stoyanchev d9d8a79c30 Update Netty4ClientHttpRequestFactory buffer size
This change deprecates the maxRequestSize property and adds
maxResponseSize instead. The latter is required to create Netty's
HttpObjectAggregator and aggregates responses.

The maxRequestSize property is already removed in the master branch
and will not be available starting with 4.2.

Issue: SPR-12623
2015-02-02 16:15:42 -05:00
Rossen Stoyanchev 04840166af DefaultSubscriptionRegistry returns safe to iterate Map
Prior to this change when adding subscriptions
DefaultSubscriptionRegistry (incorrectly) made a copy of the given map
for its "access" cache rather than for its "update" cache.

Issue: SPR-12665
2015-02-02 13:57:46 -05:00
Stephane Nicoll 6fce6d4668 Allow subclasses to configure the Yaml instance
Provide an additional hook-point for YamlProcessor subclasses willing to
change how the Yaml instance is configured. Also expose the default
StrictMapAppenderConstructor so that  they can compose a custom instance
with it.

Issue: SPR-12671
2015-02-02 11:31:19 +01:00
Sam Brannen 0c856b3d22 Support @Configuration as meta-annotation in the TCF
Spring Framework 4.0 introduced support for using test-related
annotations as meta-annotations in the Spring TestContext Framework
(TCF) in order to create custom composed annotations within a test
suite; however, the detection of default @Configuration classes in test
classes was not updated to search for @Configuration declared as a
meta-annotation. Specifically, AnnotationConfigContextLoaderUtils
invokes Class.isAnnotated() which only searches for annotations
declared directly on the class in question.

This commit addresses this issue by refactoring the
isDefaultConfigurationClassCandidate() method in
AnnotationConfigContextLoaderUtils so that it uses
AnnotationUtils.findAnnotation() instead of Class.isAnnotated() for
detecting the presence of the @Configuration annotation, either
directly or as a meta-annotation.

Issue: SPR-12659
(cherry picked from commit 2d918380f0)
2015-01-23 22:18:56 +01:00
Rossen Stoyanchev d63cfc8eeb Add JdkIdGenerator and use it in SockJS client
Issue: SPR-12658
2015-01-22 21:29:18 -05:00
Rossen Stoyanchev 7621cc787d Remove ISE in ResourceUrlProvider
Issue: SPR-12630
2015-01-22 17:09:42 -05:00
Juergen Hoeller 2c1682af34 Latest applicable dependency updates (Jackson 2.4.5, Jetty 9.2.7) 2015-01-22 19:45:02 +01:00
Juergen Hoeller dcaa0987ee Polishing
(cherry picked from commit 1cd4433)
2015-01-22 19:44:38 +01:00
Juergen Hoeller 14a3bf3941 ScheduledAnnotationBeanPostProcessor registers tasks in ContextRefreshedEvent phase (again)
Issue: SPR-12641
(cherry picked from commit 0479ca6)
2015-01-22 19:42:44 +01:00
mgooty 23b09015fe Fix method documentation typo
Issue: SPR-12639
2015-01-22 19:23:51 +01:00
Juergen Hoeller b82e9c4d46 Allow schedulerWithHsqlDataSource to pass through reducing it to the trigger table check
Issue: SPR-12618
(cherry picked from commit 49e31c3)
2015-01-21 12:40:03 +01:00
Juergen Hoeller c158874d82 Latest dependency updates (Jackson 2.5, Hibernate 4.3.8, Netty 4.0.25)
(cherry picked from commit 4141bf3)
2015-01-21 12:39:45 +01:00
Juergen Hoeller 87b7cd6368 OperatorMatches caches compiled patterns
Issue: SPR-12610
(cherry picked from commit d34402d)
2015-01-21 12:34:24 +01:00
Juergen Hoeller 901d7d07db AbstractBeanDefinitionParser allows for skipping evaluation of XML "name" attribute
Issue: SPR-12643
(cherry picked from commit 11bf3b3)
2015-01-21 12:34:14 +01:00
Juergen Hoeller bfba988a0d AbstractRequestLoggingFilter allows for dedicated shouldLog check in CommonsRequestLoggingFilter
Issue: SPR-12609
(cherry picked from commit d4dac25)
2015-01-21 12:34:05 +01:00
Juergen Hoeller a7975c685d AnnotationUtils explicitly handles null parameters
Issue: SPR-12604
(cherry picked from commit 0ddf8dd)
2015-01-21 12:33:56 +01:00
Rossen Stoyanchev cdaf4497b6 Remove logging statement in ResponseBodyAdviceChain
Issue: SPR-12616
2015-01-20 17:23:47 -05:00
Rossen Stoyanchev 84807c5d61 Fix minor test issues
Issue: SPR-12615
2015-01-20 17:16:55 -05:00
Sam Brannen a76a6509e5 Enable reuse of DefaultActiveProfilesResolver
In order to allow DefaultActiveProfilesResolver to be reused (e.g., via
extension or delegation), the check which asserts that the 'resolver'
attribute of @ActiveProfiles is not set to a customer resolver class
has been removed.

Issue: SPR-12611
(cherry picked from commit 276712dcd1)
2015-01-10 20:37:55 +01:00
Sam Brannen 7d171e6722 Handle exceptions properly in SpringJUnit4ClassRunner
JUnit 4.9 introduced a regression in BlockJUnit4ClassRunner.runChild()
such that exceptions thrown from methodBlock() cause the current test
execution to abort immediately. As a result, the failing test method is
unrooted, and subsequent test methods are never invoked. Furthermore,
RunListeners registered with JUnit are not properly notified.

In conjunction with SPR-11908, SpringJUnit4ClassRunner was updated to
use the aforementioned changes to BlockJUnit4ClassRunner.runChild().
Consequently, SpringJUnit4ClassRunner now suffers from the same
regression.

This commit addresses this issue by ensuring that any exceptions thrown
during the invocation of methodBlock() are properly wrapped in a JUnit
Fail Statement.

Issue: SPR-12613
(cherry picked from commit b81c522ee1)
2015-01-10 17:58:18 +01:00
Juergen Hoeller 36da551280 Revised ExtendedBeanInfo test for SPR-8937 (for JDK 8u40 compatibility)
Issue: SPR-12582
(cherry picked from commit 7492129)
2015-01-02 15:54:18 +01:00
Juergen Hoeller ed665a12a3 ObjectToOptionalConverter uses Optional.ofNullable after ConversionService invocation
Issue: SPR-12589
(cherry picked from commit ec84fa6)
2015-01-02 15:53:55 +01:00
Stephane Nicoll adec0265a4 Restore default transaction manager by name lookup
Fix a regression introduced by 961574bd17 that prevents a proper lookup
of the default transaction manager by name as the absence of a qualifier
is represented by an empty string (passing the faulty null check).

Issue: SPR-12577
2014-12-31 16:01:56 +01:00
Juergen Hoeller 8c700b19da Polishing 2014-12-30 21:04:28 +01:00
Juergen Hoeller 9542313710 Polishing 2014-12-30 15:29:48 +01:00
Juergen Hoeller dcb821edb5 Polishing
(cherry picked from commit 730bd02)
2014-12-30 15:07:19 +01:00
Stephane Nicoll daa4adf2ed Next Development Version 2014-12-30 14:29:42 +01:00
578 changed files with 11931 additions and 6640 deletions
+46 -44
View File
@@ -5,7 +5,7 @@ buildscript {
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
classpath("org.asciidoctor:asciidoctor-gradle-plugin:0.7.0")
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
classpath("io.spring.gradle:docbook-reference-plugin:0.3.1")
classpath("ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1")
}
}
@@ -18,7 +18,7 @@ ext {
linkScmConnection = 'scm:git:git://github.com/spring-projects/spring-framework.git'
linkScmDevConnection = 'scm:git:ssh://git@github.com:spring-projects/spring-framework.git'
moduleProjects = subprojects.findAll {
moduleProjects = subprojects.findAll {
!it.name.equals('spring-build-src') && !it.name.equals('spring-framework-bom')
}
}
@@ -27,34 +27,34 @@ configure(allprojects) { project ->
group = "org.springframework"
version = qualifyVersionIfNecessary(version)
ext.aspectjVersion = "1.8.4"
ext.aspectjVersion = "1.8.7"
ext.eclipseLinkVersion = "2.4.2"
ext.ehcacheVersion = "2.9.0"
ext.ehcacheJCacheVersion = "1.0.0"
ext.groovyVersion = "2.3.9"
ext.ehcacheVersion = "2.9.1"
ext.ehcacheJCacheVersion = "1.0.1"
ext.groovyVersion = "2.3.11"
ext.gsonVersion = "2.3.1"
ext.hibernate3Version = "3.6.10.Final"
ext.hibernate4Version = "4.3.7.Final"
ext.hibernate4Version = "4.3.11.Final"
ext.hibVal4Version = "4.3.2.Final"
ext.hibVal5Version = "5.1.3.Final"
ext.hsqldbVersion = "2.3.2"
ext.jackson2Version = "2.4.4"
ext.jasperReportsVersion = "6.0.0"
ext.jettyVersion = "9.2.6.v20141205"
ext.jodaVersion = "2.6"
ext.jackson2Version = "2.4.6"
ext.jasperReportsVersion = "6.0.4"
ext.jettyVersion = "9.2.13.v20150730"
ext.jodaVersion = "2.8.2"
ext.junitVersion = "4.12"
ext.nettyVersion = "4.0.24.Final"
ext.nettyVersion = "4.0.32.Final"
ext.openJpaVersion = "2.2.2" // 2.3.0 not Java 8 compatible (based on ASM 4)
ext.protobufVersion = "2.6.1"
ext.reactorVersion = "1.1.5.RELEASE"
ext.slf4jVersion = "1.7.9"
ext.snakeYamlVersion = "1.14"
ext.reactorVersion = "1.1.6.RELEASE"
ext.slf4jVersion = "1.7.12"
ext.snakeYamlVersion = "1.16"
ext.snifferVersion = "1.11"
ext.tiles2Version = "2.2.2"
ext.tiles3Version = "3.0.5"
ext.tomcatVersion = "8.0.15"
ext.tomcatVersion = "8.0.28"
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
ext.undertowVersion = "1.1.1.Final"
ext.undertowVersion = "1.1.8.Final"
ext.woodstoxVersion = "4.4.1"
ext.xstreamVersion = "1.4.7"
@@ -86,13 +86,13 @@ configure(allprojects) { project ->
"-Xlint:-unchecked", "-Xlint:-options"]
compileJava {
sourceCompatibility=1.6
targetCompatibility=1.6
sourceCompatibility = 1.6
targetCompatibility = 1.6
}
compileTestJava {
sourceCompatibility=1.8
targetCompatibility=1.8
sourceCompatibility = 1.8
targetCompatibility = 1.8
options.compilerArgs += "-parameters"
}
@@ -123,7 +123,7 @@ configure(allprojects) { project ->
testCompile("org.hamcrest:hamcrest-all:1.3")
sniffer("org.codehaus.mojo:animal-sniffer-ant-tasks:${snifferVersion}")
javaApiSignature("org.codehaus.mojo.signature:java16:1.1@signature") // as from JDK 6 update 18
javaApiSignature("org.codehaus.mojo.signature:java16:1.1@signature") // API level from JDK 6 update 18
}
task copyJavaApiSignature(type: Copy) {
@@ -143,7 +143,6 @@ configure(allprojects) { project ->
inputs.dir sourceSets.main.output.classesDir
inputs.dir copyJavaApiSignature.to
outputs.upToDateWhen { true }
doLast {
ant.taskdef(
@@ -334,7 +333,7 @@ project("spring-core") {
optional("net.sf.jopt-simple:jopt-simple:4.8")
optional("log4j:log4j:1.2.17")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("org.codehaus.woodstox:woodstox-core-asl:${woodstoxVersion}") {
exclude group: "stax", module: "stax-api"
}
@@ -389,8 +388,8 @@ project("spring-beans-groovy") {
}
compileGroovy {
sourceCompatibility=1.6
targetCompatibility=1.6
sourceCompatibility = 1.6
targetCompatibility = 1.6
}
}
@@ -405,7 +404,7 @@ project("spring-aop") {
compile("aopalliance:aopalliance:1.0")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("commons-pool:commons-pool:1.6")
optional("com.jamonapi:jamon:2.79")
optional("com.jamonapi:jamon:2.81")
}
}
@@ -460,7 +459,7 @@ project("spring-context") {
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("org.beanshell:bsh:2.0b4")
optional("org.jruby:jruby:1.7.17")
optional("org.jruby:jruby:1.7.22")
testCompile("javax.inject:javax.inject-tck:1")
testCompile("commons-dbcp:commons-dbcp:1.4")
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
@@ -534,8 +533,8 @@ project("spring-oxm") {
compileTestJava {
// necessary to avoid java.lang.VerifyError on jibx compilation
// see http://jira.codehaus.org/browse/JIBX-465
sourceCompatibility=1.6
targetCompatibility=1.6
sourceCompatibility = 1.6
targetCompatibility = 1.6
}
dependencies {
@@ -552,9 +551,9 @@ project("spring-oxm") {
exclude group: 'xpp3', module: 'xpp3_min'
exclude group: 'xmlpull', module: 'xmlpull'
}
optional("org.jibx:jibx-run:1.2.5")
optional("org.jibx:jibx-run:1.2.6")
testCompile(project(":spring-context"))
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("xpp3:xpp3:1.1.4c")
testCompile("org.codehaus.jettison:jettison:1.3.7") {
exclude group: 'stax', module: 'stax-api'
@@ -595,7 +594,7 @@ project("spring-jdbc") {
optional("javax.transaction:javax.transaction-api:1.2")
optional("com.mchange:c3p0:0.9.2.1")
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
optional("com.h2database:h2:1.4.182")
optional("com.h2database:h2:1.4.187")
optional("org.apache.derby:derby:10.11.1.1")
optional("org.apache.derby:derbyclient:10.11.1.1")
}
@@ -617,7 +616,7 @@ project("spring-context-support") {
optional("org.quartz-scheduler:quartz:2.2.1")
optional("org.codehaus.fabric3.api:commonj:1.1.0")
optional("org.apache.velocity:velocity:1.7")
optional("org.freemarker:freemarker:2.3.21")
optional("org.freemarker:freemarker:2.3.22")
optional("com.lowagie:itext:2.1.7")
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
exclude group: "com.fasterxml.jackson.core", module: "jackson-annotations"
@@ -625,9 +624,10 @@ project("spring-context-support") {
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
exclude group: "org.olap4j", module: "olap4j"
exclude group: "xml-apis", module: "xml-apis"
exclude group: "org.springframework", module: "spring-context"
}
testCompile(project(":spring-context"))
testCompile("org.apache.poi:poi:3.10.1")
testCompile("org.apache.poi:poi:3.11")
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
@@ -680,7 +680,7 @@ project("spring-web") {
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
optional("com.google.code.gson:gson:${gsonVersion}")
optional("com.rometools:rome:1.5.0")
optional("com.rometools:rome:1.5.1")
optional("org.eclipse.jetty:jetty-servlet:${jettyVersion}") {
exclude group: "javax.servlet", module: "javax.servlet-api"
}
@@ -692,11 +692,12 @@ project("spring-web") {
optional("com.google.protobuf:protobuf-java:${protobufVersion}")
optional("javax.mail:javax.mail-api:1.5.2")
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
}
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
testRuntime("com.sun.mail:javax.mail:1.5.2")
}
@@ -826,10 +827,10 @@ project("spring-webmvc") {
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
optional("org.apache.poi:poi:3.10.1")
optional("org.apache.poi:poi:3.11")
optional("org.apache.velocity:velocity:1.7")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.20")
optional("org.freemarker:freemarker:2.3.22")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("com.lowagie:itext:2.1.7")
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
@@ -838,10 +839,11 @@ project("spring-webmvc") {
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
exclude group: "org.olap4j", module: "olap4j"
exclude group: "xml-apis", module: "xml-apis"
exclude group: "org.springframework", module: "spring-context"
}
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
optional("com.rometools:rome:1.5.0")
optional("com.rometools:rome:1.5.1")
optional("javax.el:javax.el-api:2.2.5")
optional("org.apache.tiles:tiles-api:${tiles3Version}")
optional("org.apache.tiles:tiles-core:${tiles3Version}") {
@@ -862,7 +864,7 @@ project("spring-webmvc") {
}
testCompile(project(":spring-aop"))
testCompile("rhino:js:1.7R1")
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("dom4j:dom4j:1.6.1") {
exclude group: "xml-apis", module: "xml-apis"
}
@@ -967,9 +969,9 @@ project("spring-test") {
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("org.hamcrest:hamcrest-core:1.3")
optional("com.jayway.jsonpath:json-path:1.1.0")
optional("com.jayway.jsonpath:json-path:1.2.0")
optional("org.skyscreamer:jsonassert:1.2.3")
optional("xmlunit:xmlunit:1.5")
optional("xmlunit:xmlunit:1.6")
testCompile(project(":spring-context-support"))
testCompile(project(":spring-oxm"))
testCompile("javax.mail:javax.mail-api:1.5.2")
@@ -979,7 +981,7 @@ project("spring-test") {
testCompile("org.hibernate:hibernate-validator:${hibVal5Version}")
testCompile("com.thoughtworks.xstream:xstream:${xstreamVersion}")
testCompile("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
testCompile("com.rometools:rome:1.5.0")
testCompile("com.rometools:rome:1.5.1")
testCompile("org.apache.tiles:tiles-api:${tiles3Version}")
testCompile("org.apache.tiles:tiles-core:${tiles3Version}") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
+1 -1
View File
@@ -1 +1 @@
version=4.1.4.BUILD-SNAPSHOT
version=4.1.8.RELEASE
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -203,8 +204,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
return parser.parsePointcutExpression(
replaceBooleanOperators(getExpression()),
return parser.parsePointcutExpression(replaceBooleanOperators(getExpression()),
this.pointcutDeclarationScope, pointcutParameters);
}
@@ -327,29 +327,41 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
catch (IllegalStateException ex) {
// No current invocation...
// TODO: Should we really proceed here?
logger.debug("Couldn't access current invocation - matching with limited context: " + ex);
}
JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
/*
* Do a final check to see if any this(TYPE) kind of residue match. For
* this purpose, we use the original method's (proxy method's) shadow to
* ensure that 'this' is correctly checked against. Without this check,
* we get incorrect match on this(TYPE) where TYPE matches the target
* type but not 'this' (as would be the case of JDK dynamic proxies).
* <p>See SPR-2979 for the original bug.
*/
if (pmi != null) { // there is a current invocation
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false;
}
if (joinPointMatch.matches()) {
bindParameters(pmi, joinPointMatch);
if (logger.isDebugEnabled()) {
logger.debug("Could not access current invocation - matching with limited context: " + ex);
}
}
return joinPointMatch.matches();
try {
JoinPointMatch joinPointMatch = shadowMatch.matchesJoinPoint(thisObject, targetObject, args);
/*
* Do a final check to see if any this(TYPE) kind of residue match. For
* this purpose, we use the original method's (proxy method's) shadow to
* ensure that 'this' is correctly checked against. Without this check,
* we get incorrect match on this(TYPE) where TYPE matches the target
* type but not 'this' (as would be the case of JDK dynamic proxies).
* <p>See SPR-2979 for the original bug.
*/
if (pmi != null) { // there is a current invocation
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false;
}
if (joinPointMatch.matches()) {
bindParameters(pmi, joinPointMatch);
}
}
return joinPointMatch.matches();
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to evaluate join point for arguments " + Arrays.asList(args) +
" - falling back to non-match", ex);
}
return false;
}
}
protected String getCurrentProxiedBeanName() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
@@ -76,7 +76,7 @@ public class AspectJProxyFactory extends ProxyCreatorSupport {
* Create a new {@code AspectJProxyFactory}.
* No target, only interfaces. Must add interceptors.
*/
public AspectJProxyFactory(Class<?>[] interfaces) {
public AspectJProxyFactory(Class<?>... interfaces) {
setInterfaces(interfaces);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,9 +102,9 @@ class CglibAopProxy implements AopProxy, Serializable {
/** The configuration used to configure this proxy */
protected final AdvisedSupport advised;
private Object[] constructorArgs;
protected Object[] constructorArgs;
private Class<?>[] constructorArgTypes;
protected Class<?>[] constructorArgTypes;
/** Dispatcher used for methods on Advised */
private final transient AdvisedDispatcher advisedDispatcher;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,14 +22,14 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.Factory;
import org.springframework.objenesis.ObjenesisException;
import org.springframework.objenesis.ObjenesisStd;
/**
* Objenesis based extension of {@link CglibAopProxy} to create proxy instances without
* invoking the constructor of the class.
* Objenesis-based extension of {@link CglibAopProxy} to create proxy instances
* without invoking the constructor of the class.
*
* @author Oliver Gierke
* @author Juergen Hoeller
* @since 4.0
*/
@SuppressWarnings("serial")
@@ -41,8 +41,8 @@ class ObjenesisCglibAopProxy extends CglibAopProxy {
/**
* Creates a new {@link ObjenesisCglibAopProxy} using the given {@link AdvisedSupport}.
* @param config must not be {@literal null}.
* Create a new ObjenesisCglibAopProxy for the given AOP configuration.
* @param config the AOP configuration as AdvisedSupport object
*/
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
@@ -53,18 +53,32 @@ class ObjenesisCglibAopProxy extends CglibAopProxy {
@Override
@SuppressWarnings("unchecked")
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;
try {
Factory factory = (Factory) this.objenesis.newInstance(enhancer.createClass());
factory.setCallbacks(callbacks);
return factory;
proxyInstance = this.objenesis.newInstance(proxyClass);
}
catch (ObjenesisException ex) {
// Fallback to regular proxy construction on unsupported JVMs
if (logger.isDebugEnabled()) {
logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex);
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
proxyInstance = (this.constructorArgs != null ?
proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
proxyClass.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
return super.createProxyClassAndInstance(enhancer, callbacks);
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -125,8 +125,10 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
Executor executorToUse = this.defaultExecutor;
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
Assert.notNull(this.beanFactory, "BeanFactory must be set on " + getClass().getSimpleName() +
" to access qualified executor '" + qualifier + "'");
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory must be set on " + getClass().getSimpleName() +
" to access qualified executor '" + qualifier + "'");
}
executorToUse = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
this.beanFactory, Executor.class, qualifier);
}
@@ -155,7 +157,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
/**
* Handles a fatal error thrown while asynchronously invoking the specified
* {@link Method}.
* <p>If the return type of the method is a {@link java.util.concurrent.Future} object, the original
* <p>If the return type of the method is a {@link Future} object, the original
* exception can be propagated by just throwing it at the higher level. However,
* for all other cases, the exception will not be transmitted back to the client.
* In that later case, the current {@link AsyncUncaughtExceptionHandler} will be
@@ -165,7 +167,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @param params the parameters used to invoke the method
*/
protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
if (method.getReturnType().isAssignableFrom(Future.class)) {
if (Future.class.isAssignableFrom(method.getReturnType())) {
ReflectionUtils.rethrowException(ex);
}
else {
@@ -78,7 +78,7 @@ public class CommonsPoolTargetSource extends AbstractPoolingTargetSource impleme
private byte whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
/**
* The Jakarta Commons {@code ObjectPool} used to pool target objects
* The Apache Commons {@code ObjectPool} used to pool target objects
*/
private ObjectPool pool;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -32,9 +32,9 @@ import static org.junit.Assert.*;
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AspectProxyFactoryTests {
public class AspectProxyFactoryTests {
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testWithNonAspect() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(TestBean.class);
@@ -70,7 +70,7 @@ public final class AspectProxyFactoryTests {
assertEquals(2, proxy1.getAge());
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testWithInstanceWithNonAspect() throws Exception {
AspectJProxyFactory pf = new AspectJProxyFactory();
pf.addAspect(new TestBean());
@@ -96,14 +96,14 @@ public final class AspectProxyFactoryTests {
assertEquals(target.getAge() * multiple, serializedProxy.getAge());
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testWithNonSingletonAspectInstance() throws Exception {
AspectJProxyFactory pf = new AspectJProxyFactory();
pf.addAspect(new PerThisAspect());
}
public static interface ITestBean {
public interface ITestBean {
int getAge();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -32,50 +32,55 @@ import static org.mockito.BDDMockito.*;
*/
public class JamonPerformanceMonitorInterceptorTests {
private JamonPerformanceMonitorInterceptor interceptor = new JamonPerformanceMonitorInterceptor();
private final JamonPerformanceMonitorInterceptor interceptor = new JamonPerformanceMonitorInterceptor();
private MethodInvocation mi = mock(MethodInvocation.class);
private final MethodInvocation mi = mock(MethodInvocation.class);
private Log log = mock(Log.class);
private final Log log = mock(Log.class);
@Before
public void setUp() {
MonitorFactory.reset();
}
@Before
public void setUp() {
MonitorFactory.reset();
}
@After
public void tearDown() {
MonitorFactory.reset();
}
@After
public void tearDown() {
MonitorFactory.reset();
}
@Test
public void testInvokeUnderTraceWithNormalProcessing() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
@Test
public void testInvokeUnderTraceWithNormalProcessing() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
interceptor.invokeUnderTrace(mi, log);
interceptor.invokeUnderTrace(mi, log);
assertEquals("jamon must track the method being invoked", 1, MonitorFactory.getNumRows());
assertTrue("The jamon report must contain the toString method that was invoked", MonitorFactory.getReport().contains("toString"));
}
assertTrue("jamon must track the method being invoked", MonitorFactory.getNumRows() > 0);
assertTrue("The jamon report must contain the toString method that was invoked",
MonitorFactory.getReport().contains("toString"));
}
@Test
public void testInvokeUnderTraceWithExceptionTracking() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
given(mi.proceed()).willThrow(new IllegalArgumentException());
@Test
public void testInvokeUnderTraceWithExceptionTracking() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
given(mi.proceed()).willThrow(new IllegalArgumentException());
try {
interceptor.invokeUnderTrace(mi, log);
fail("Must have propagated the IllegalArgumentException");
}
try {
interceptor.invokeUnderTrace(mi, log);
fail("Must have propagated the IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
}
assertEquals("Monitors must exist for the method invocation and 2 exceptions", 3, MonitorFactory.getNumRows());
assertTrue("The jamon report must contain the toString method that was invoked", MonitorFactory.getReport().contains("toString"));
assertTrue("The jamon report must contain the generic exception: " + MonitorFactory.EXCEPTIONS_LABEL, MonitorFactory.getReport().contains(MonitorFactory.EXCEPTIONS_LABEL));
assertTrue("The jamon report must contain the specific exception: IllegalArgumentException'", MonitorFactory.getReport().contains("IllegalArgumentException"));
}
assertEquals("Monitors must exist for the method invocation and 2 exceptions",
3, MonitorFactory.getNumRows());
assertTrue("The jamon report must contain the toString method that was invoked",
MonitorFactory.getReport().contains("toString"));
assertTrue("The jamon report must contain the generic exception: " + MonitorFactory.EXCEPTIONS_LABEL,
MonitorFactory.getReport().contains(MonitorFactory.EXCEPTIONS_LABEL));
assertTrue("The jamon report must contain the specific exception: IllegalArgumentException'",
MonitorFactory.getReport().contains("IllegalArgumentException"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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,9 +28,9 @@ import org.springframework.context.annotation.Role;
* annotated with @{@link org.springframework.beans.factory.annotation.Configurable
* Configurable}.
*
* <p>This configuration class is automatically imported when using the @{@link
* EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured} Javadoc for
* complete usage details.
* <p>This configuration class is automatically imported when using the
* @{@link EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured}'s
* javadoc for complete usage details.
*
* @author Chris Beams
* @since 3.1
@@ -42,9 +42,10 @@ public class SpringConfiguredConfiguration {
public static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME =
"org.springframework.context.config.internalBeanConfigurerAspect";
@Bean(name=BEAN_CONFIGURER_ASPECT_BEAN_NAME)
@Bean(name = BEAN_CONFIGURER_ASPECT_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AnnotationBeanConfigurerAspect beanConfigurerAspect() {
return AnnotationBeanConfigurerAspect.aspectOf();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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,15 +23,15 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.annotation.Async;
/**
* Aspect to route methods based on the {@link Async} annotation.
* Aspect to route methods based on Spring's {@link Async} annotation.
*
* <p>This aspect routes methods marked with the {@link Async} annotation
* as well as methods in classes marked with the same. Any method expected
* to be routed asynchronously must return either {@code void}, {@link Future},
* or a subtype of {@link Future}. This aspect, therefore, will produce
* a compile-time error for methods that violate this constraint on the return type.
* If, however, a class marked with {@code @Async} contains a method that violates this
* constraint, it produces only a warning.
* <p>This aspect routes methods marked with the {@link Async} annotation as well as methods
* in classes marked with the same. Any method expected to be routed asynchronously must
* return either {@code void}, {@link Future}, or a subtype of {@link Future} (in particular,
* Spring's {@link org.springframework.util.concurrent.ListenableFuture}). This aspect,
* therefore, will produce a compile-time error for methods that violate this constraint
* on the return type. If, however, a class marked with {@code @Async} contains a method
* that violates this constraint, it produces only a warning.
*
* @author Ramnivas Laddad
* @author Chris Beams
@@ -39,42 +39,41 @@ import org.springframework.scheduling.annotation.Async;
*/
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
private pointcut asyncMarkedMethod()
: execution(@Async (void || Future+) *(..));
private pointcut asyncMarkedMethod() : execution(@Async (void || Future+) *(..));
private pointcut asyncTypeMarkedMethod()
: execution((void || Future+) (@Async *).*(..));
private pointcut asyncTypeMarkedMethod() : execution((void || Future+) (@Async *).*(..));
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
/**
* {@inheritDoc}
* <p>This implementation inspects the given method and its declaring class for the
* {@code @Async} annotation, returning the qualifier value expressed by
* {@link Async#value()}. If {@code @Async} is specified at both the method and class level, the
* method's {@code #value} takes precedence (even if empty string, indicating that
* the default executor should be used preferentially).
* This implementation inspects the given method and its declaring class for the
* {@code @Async} annotation, returning the qualifier value expressed by {@link Async#value()}.
* If {@code @Async} is specified at both the method and class level, the method's
* {@code #value} takes precedence (even if empty string, indicating that the default
* executor should be used preferentially).
* @return the qualifier if specified, otherwise empty string indicating that the
* {@linkplain #setExecutor(Executor) default executor} should be used
* {@linkplain #setExecutor default executor} should be used
* @see #determineAsyncExecutor(Method)
*/
@Override
protected String getExecutorQualifier(Method method) {
// maintainer's note: changes made here should also be made in
// Maintainer's note: changes made here should also be made in
// AnnotationAsyncExecutionInterceptor#getExecutorQualifier
Async async = AnnotationUtils.findAnnotation(method, Async.class);
if (async == null) {
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
}
return async == null ? null : async.value();
return (async != null ? async.value() : null);
}
declare error:
execution(@Async !(void||Future) *(..)):
execution(@Async !(void || Future+) *(..)):
"Only methods that return void or Future may have an @Async annotation";
declare warning:
execution(!(void||Future) (@Async *).*(..)):
execution(!(void || Future+) (@Async *).*(..)):
"Methods in a class marked with @Async that do not return void or Future will " +
"be routed synchronously";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -35,6 +35,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.Matchers.not;
@@ -50,9 +51,10 @@ public class AnnotationAsyncExecutionAspectTests {
private static final long WAIT_TIME = 1000; //milliseconds
private final AsyncUncaughtExceptionHandler defaultExceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
private CountingExecutor executor;
private AsyncUncaughtExceptionHandler defaultExceptionHandler = new SimpleAsyncUncaughtExceptionHandler();
@Before
public void setUp() {
@@ -62,6 +64,7 @@ public class AnnotationAsyncExecutionAspectTests {
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
}
@Test
public void asyncMethodGetsRoutedAsynchronously() {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
@@ -184,7 +187,9 @@ public class AnnotationAsyncExecutionAspectTests {
@SuppressWarnings("serial")
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
int submitStartCounter;
int submitCompleteCounter;
@Override
@@ -209,6 +214,7 @@ public class AnnotationAsyncExecutionAspectTests {
static class ClassWithoutAsyncAnnotation {
int counter;
@Async public void incrementAsync() {
@@ -239,6 +245,7 @@ public class AnnotationAsyncExecutionAspectTests {
@Async
static class ClassWithAsyncAnnotation {
int counter;
public void increment() {
@@ -261,17 +268,19 @@ public class AnnotationAsyncExecutionAspectTests {
static class ClassWithQualifiedAsyncMethods {
@Async
public Future<Thread> defaultWork() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e1")
public Future<Thread> e1Work() {
public ListenableFuture<Thread> e1Work() {
return new AsyncResult<Thread>(Thread.currentThread());
}
}
static class ClassWithException {
@Async
@@ -279,4 +288,5 @@ public class AnnotationAsyncExecutionAspectTests {
throw new UnsupportedOperationException("failWithVoid");
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,6 +31,7 @@ import groovy.lang.GroovyObjectSupport;
import groovy.lang.GroovyShell;
import groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.InvokerHelper;
@@ -58,8 +59,17 @@ import org.springframework.util.StringUtils;
/**
* A Groovy-based reader for Spring bean definitions: like a Groovy builder,
* but more of a DSL for Spring configuration. Allows syntax like:
* but more of a DSL for Spring configuration.
*
* <p>This bean definition reader also understands XML bean definition files,
* allowing for seamless mixing and matching with Groovy bean definition files.
*
* <p>Typically applied to a
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
* or a {@link org.springframework.context.support.GenericApplicationContext},
* but can be used against any {@link BeanDefinitionRegistry} implementation.
*
* <h3>Example Syntax</h3>
* <pre class="code">
* import org.hibernate.SessionFactory
* import org.apache.commons.dbcp.BasicDataSource
@@ -84,8 +94,9 @@ import org.springframework.util.StringUtils;
* }</pre>
*
* <p>You can also load resources containing beans defined in a Groovy script using
* either the {@link #loadBeanDefinitions(org.springframework.core.io.Resource...)}
* or {@link #loadBeanDefinitions(String...)} method, with a script looking as follows:
* either the {@link #loadBeanDefinitions(Resource...)} or
* {@link #loadBeanDefinitions(String...)} method, with a script looking similar to
* the following.
*
* <pre class="code">
* import org.hibernate.SessionFactory
@@ -109,17 +120,10 @@ import org.springframework.util.StringUtils;
* }
* }</pre>
*
* <p><b>This bean definition reader also understands XML bean definition files,
* allowing for seamless mixing and matching with Groovy bean definition files.</b>
*
* <p>Typically applied to a
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
* or a {@link org.springframework.context.support.GenericApplicationContext},
* but can be used against any {@link BeanDefinitionRegistry} implementation.
*
* @author Jeff Brown
* @author Graeme Rocher
* @author Juergen Hoeller
* @author Sam Brannen
* @since 4.0
* @see BeanDefinitionRegistry
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory
@@ -128,7 +132,21 @@ import org.springframework.util.StringUtils;
*/
public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader implements GroovyObject {
private final XmlBeanDefinitionReader xmlBeanDefinitionReader;
/**
* Standard {@code XmlBeanDefinitionReader} created with default
* settings for loading bean definitions from XML files.
*/
private final XmlBeanDefinitionReader standardXmlBeanDefinitionReader;
/**
* Groovy DSL {@code XmlBeanDefinitionReader} for loading bean definitions
* via the Groovy DSL, typically configured with XML validation disabled.
*/
private final XmlBeanDefinitionReader groovyDslXmlBeanDefinitionReader;
private final Map<String, String> namespaces = new HashMap<String, String>();
private final Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
private MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
@@ -136,31 +154,28 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
private GroovyBeanDefinitionWrapper currentBeanDefinition;
private final Map <String, String> namespaces = new HashMap<String, String>();
private final Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
/**
* Create new GroovyBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
* Create a new {@code GroovyBeanDefinitionReader} for the given {@link BeanDefinitionRegistry}.
* @param registry the {@code BeanDefinitionRegistry} to load bean definitions into
*/
public GroovyBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
this.xmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
this.xmlBeanDefinitionReader.setValidating(false);
this.standardXmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
this.groovyDslXmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
this.groovyDslXmlBeanDefinitionReader.setValidating(false);
}
/**
* Create new GroovyBeanDefinitionReader based on the given XmlBeanDefinitionReader,
* using the same registry and delegating XML loading to it.
* @param xmlBeanDefinitionReader the XmlBeanDefinitionReader to derive the registry
* Create a new {@code GroovyBeanDefinitionReader} based on the given {@link XmlBeanDefinitionReader},
* using its {@code BeanDefinitionRegistry} and delegating Groovy DSL loading to it.
* @param xmlBeanDefinitionReader the {@code XmlBeanDefinitionReader} to derive the registry
* from and to delegate XML loading to
*/
public GroovyBeanDefinitionReader(XmlBeanDefinitionReader xmlBeanDefinitionReader) {
super(xmlBeanDefinitionReader.getRegistry());
this.xmlBeanDefinitionReader = xmlBeanDefinitionReader;
this.standardXmlBeanDefinitionReader = new XmlBeanDefinitionReader(xmlBeanDefinitionReader.getRegistry());
this.groovyDslXmlBeanDefinitionReader = xmlBeanDefinitionReader;
}
@@ -174,7 +189,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Set the binding, i.e. the Groovy variables available in the scope
* of a GroovyBeanDefinitionReader closure.
* of a {@code GroovyBeanDefinitionReader} closure.
*/
public void setBinding(Binding binding) {
this.binding = binding;
@@ -192,9 +207,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Load bean definitions from the specified Groovy script or XML file.
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
* <p>Note that {@code ".xml"} files will be parsed as XML content; all other kinds
* of resources will be parsed as Groovy scripts.
* @param resource the resource descriptor for the Groovy script
* @param resource the resource descriptor for the Groovy script or XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
@@ -204,18 +219,18 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Load bean definitions from the specified Groovy script or XML file.
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
* <p>Note that {@code ".xml"} files will be parsed as XML content; all other kinds
* of resources will be parsed as Groovy scripts.
* @param encodedResource the resource descriptor for the Groovy script,
* allowing to specify an encoding to use for parsing the file
* @param encodedResource the resource descriptor for the Groovy script or XML file,
* allowing specification of an encoding to use for parsing the file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// Check for XML files and redirect them to the XmlBeanDefinitionReader
// Check for XML files and redirect them to the "standard" XmlBeanDefinitionReader
String filename = encodedResource.getResource().getFilename();
if (StringUtils.endsWithIgnoreCase(filename, ".xml")) {
return this.xmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
return this.standardXmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
}
Closure beans = new Closure(this) {
@@ -255,14 +270,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Defines a set of beans for the given block or closure.
* @param closure the block or closure
* @return this GroovyBeanDefinitionReader instance
* @return this {@code GroovyBeanDefinitionReader} instance
*/
public GroovyBeanDefinitionReader beans(Closure closure) {
return invokeBeanDefiningClosure(closure);
}
/**
* Defines an inner bean definition.
* Define an inner bean definition.
* @param type the bean type
* @return the bean definition
*/
@@ -307,7 +322,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* Define a Spring namespace definition to use.
* Define a Spring XML namespace definition to use.
* @param definition the namespace definition
*/
public void xmlns(Map<String, String> definition) {
@@ -318,7 +333,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
if (uri == null) {
throw new IllegalArgumentException("Namespace definition must supply a non-null URI");
}
NamespaceHandler namespaceHandler = this.xmlBeanDefinitionReader.getNamespaceHandlerResolver().resolve(uri);
NamespaceHandler namespaceHandler = this.groovyDslXmlBeanDefinitionReader.getNamespaceHandlerResolver().resolve(
uri);
if (namespaceHandler == null) {
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for URI: " + uri,
new Location(new DescriptiveResource(("Groovy")))));
@@ -419,7 +435,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* When a method argument is only a closure it is a set of bean definitions.
* @param callable the closure argument
* @return this GroovyBeanDefinitionReader instance
* @return this {@code GroovyBeanDefinitionReader} instance
*/
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) {
callable.setDelegate(this);
@@ -534,8 +550,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* Checks whether there are any {@link RuntimeBeanReference}s inside the Map
* and converts it to a ManagedMap if necessary.
* Checks whether there are any {@link RuntimeBeanReference}s inside the {@link Map}
* and converts it to a {@link ManagedMap} if necessary.
* @param map the original Map
* @return either the original map or a managed copy of it
*/
@@ -556,8 +572,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* Checks whether there are any {@link RuntimeBeanReference}s inside the List
* and converts it to a ManagedList if necessary.
* Checks whether there are any {@link RuntimeBeanReference}s inside the {@link List}
* and converts it to a {@link ManagedList} if necessary.
* @param list the original List
* @return either the original list or a managed copy of it
*/
@@ -578,7 +594,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* This method overrides property setting in the scope of the GroovyBeanDefinitionReader
* This method overrides property setting in the scope of the {@code GroovyBeanDefinitionReader}
* to set properties on the current bean definition.
*/
public void setProperty(String name, Object value) {
@@ -619,12 +635,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* This method overrides property retrieval in the scope of the
* GroovyBeanDefinitionReader to either:
* {@code GroovyBeanDefinitionReader} to either:
* <ul>
* <li>Retrieve a variable from the bean builder's binding if it exists
* <li>Retrieve a RuntimeBeanReference for a specific bean if it exists
* <li>Otherwise just delegate to MetaClass.getProperty which will resolve
* properties from the GroovyBeanDefinitionReader itself
* properties from the {@code GroovyBeanDefinitionReader} itself
* </ul>
*/
public Object getProperty(String name) {
@@ -670,7 +686,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
private GroovyDynamicElementReader createDynamicElementReader(String namespace) {
XmlReaderContext readerContext = this.xmlBeanDefinitionReader.createReaderContext(new DescriptiveResource("Groovy"));
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(new DescriptiveResource(
"Groovy"));
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
boolean decorating = (this.currentBeanDefinition != null);
if (!decorating) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,6 +78,7 @@ import org.springframework.util.StringUtils;
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rob Harrop
* @author Stephane Nicoll
* @since 15 April 2001
* @see #registerCustomEditor
* @see #setPropertyValues
@@ -978,6 +979,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
int length = Array.getLength(propValue);
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(actualName, newArray);
propValue = getPropertyValue(actualName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
@@ -1046,7 +1055,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
else {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Property referenced in indexed property path '" + propertyName +
"' is neither an array nor a List nor a Map; returned value was [" + pv.getValue() + "]");
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,8 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
Set<Method> ambiguousCandidates = new HashSet<Method>();
for (Method method : beanClass.getMethods()) {
if (method.getName().equals(writeMethodToUse.getName()) &&
!method.equals(writeMethodToUse) && !method.isBridge()) {
!method.equals(writeMethodToUse) && !method.isBridge() &&
method.getParameterTypes().length == writeMethodToUse.getParameterTypes().length) {
ambiguousCandidates.add(method);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,24 +17,31 @@
package org.springframework.beans;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Helper class for calculating bean property matches, according to.
* Used by BeanWrapperImpl to suggest alternatives for an invalid property name.
* Helper class for calculating property matches, according to a configurable
* distance. Provide the list of potential matches and an easy way to generate
* an error message. Works for both java bean properties and fields.
* <p>
* Mainly for use within the framework and in particular the binding facility
*
* @author Alef Arendsen
* @author Arjen Poutsma
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 2.0
* @see #forProperty(String, Class)
* @see #forField(String, Class)
*/
final class PropertyMatches {
public abstract class PropertyMatches {
//---------------------------------------------------------------------
// Static section
@@ -60,7 +67,26 @@ final class PropertyMatches {
* @param maxDistance the maximum property distance allowed for matches
*/
public static PropertyMatches forProperty(String propertyName, Class<?> beanClass, int maxDistance) {
return new PropertyMatches(propertyName, beanClass, maxDistance);
return new BeanPropertyMatches(propertyName, beanClass, maxDistance);
}
/**
* Create PropertyMatches for the given field property.
* @param propertyName the name of the field to find possible matches for
* @param beanClass the bean class to search for matches
*/
public static PropertyMatches forField(String propertyName, Class<?> beanClass) {
return forField(propertyName, beanClass, DEFAULT_MAX_DISTANCE);
}
/**
* Create PropertyMatches for the given field property.
* @param propertyName the name of the field to find possible matches for
* @param beanClass the bean class to search for matches
* @param maxDistance the maximum property distance allowed for matches
*/
public static PropertyMatches forField(String propertyName, Class<?> beanClass, int maxDistance) {
return new FieldPropertyMatches(propertyName, beanClass, maxDistance);
}
@@ -74,13 +100,19 @@ final class PropertyMatches {
/**
* Create a new PropertyMatches instance for the given property.
* Create a new PropertyMatches instance for the given property and possible matches.
*/
private PropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
private PropertyMatches(String propertyName, String[] possibleMatches) {
this.propertyName = propertyName;
this.possibleMatches = calculateMatches(BeanUtils.getPropertyDescriptors(beanClass), maxDistance);
this.possibleMatches = possibleMatches;
}
/**
* Return the name of the requested property.
*/
public String getPropertyName() {
return propertyName;
}
/**
* Return the calculated possible matches.
@@ -93,53 +125,21 @@ final class PropertyMatches {
* Build an error message for the given invalid property name,
* indicating the possible property matches.
*/
public String buildErrorMessage() {
StringBuilder msg = new StringBuilder();
msg.append("Bean property '");
msg.append(this.propertyName);
msg.append("' is not writable or has an invalid setter method. ");
public abstract String buildErrorMessage();
if (ObjectUtils.isEmpty(this.possibleMatches)) {
msg.append("Does the parameter type of the setter match the return type of the getter?");
}
else {
msg.append("Did you mean ");
for (int i = 0; i < this.possibleMatches.length; i++) {
msg.append('\'');
msg.append(this.possibleMatches[i]);
if (i < this.possibleMatches.length - 2) {
msg.append("', ");
}
else if (i == this.possibleMatches.length - 2){
msg.append("', or ");
}
}
msg.append("'?");
}
return msg.toString();
}
/**
* Generate possible property alternatives for the given property and
* class. Internally uses the {@code getStringDistance} method, which
* in turn uses the Levenshtein algorithm to determine the distance between
* two Strings.
* @param propertyDescriptors the JavaBeans property descriptors to search
* @param maxDistance the maximum distance to accept
*/
private String[] calculateMatches(PropertyDescriptor[] propertyDescriptors, int maxDistance) {
List<String> candidates = new ArrayList<String>();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getWriteMethod() != null) {
String possibleAlternative = pd.getName();
if (calculateStringDistance(this.propertyName, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative);
}
protected void appendHintMessage(StringBuilder msg) {
msg.append("Did you mean ");
for (int i = 0; i < this.possibleMatches.length; i++) {
msg.append('\'');
msg.append(this.possibleMatches[i]);
if (i < this.possibleMatches.length - 2) {
msg.append("', ");
}
else if (i == this.possibleMatches.length - 2) {
msg.append("', or ");
}
}
Collections.sort(candidates);
return StringUtils.toStringArray(candidates);
msg.append("'?");
}
/**
@@ -149,7 +149,7 @@ final class PropertyMatches {
* @param s2 the second String
* @return the distance value
*/
private int calculateStringDistance(String s1, String s2) {
private static int calculateStringDistance(String s1, String s2) {
if (s1.length() == 0) {
return s2.length();
}
@@ -184,4 +184,93 @@ final class PropertyMatches {
return d[s1.length()][s2.length()];
}
private static class BeanPropertyMatches extends PropertyMatches {
private BeanPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
super(propertyName, calculateMatches(propertyName,
BeanUtils.getPropertyDescriptors(beanClass), maxDistance));
}
/**
* Generate possible property alternatives for the given property and
* class. Internally uses the {@code getStringDistance} method, which
* in turn uses the Levenshtein algorithm to determine the distance between
* two Strings.
* @param propertyDescriptors the JavaBeans property descriptors to search
* @param maxDistance the maximum distance to accept
*/
private static String[] calculateMatches(String propertyName, PropertyDescriptor[] propertyDescriptors, int maxDistance) {
List<String> candidates = new ArrayList<String>();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getWriteMethod() != null) {
String possibleAlternative = pd.getName();
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative);
}
}
}
Collections.sort(candidates);
return StringUtils.toStringArray(candidates);
}
@Override
public String buildErrorMessage() {
String propertyName = getPropertyName();
String[] possibleMatches = getPossibleMatches();
StringBuilder msg = new StringBuilder();
msg.append("Bean property '");
msg.append(propertyName);
msg.append("' is not writable or has an invalid setter method. ");
if (ObjectUtils.isEmpty(possibleMatches)) {
msg.append("Does the parameter type of the setter match the return type of the getter?");
}
else {
appendHintMessage(msg);
}
return msg.toString();
}
}
private static class FieldPropertyMatches extends PropertyMatches {
private FieldPropertyMatches(String propertyName, Class<?> beanClass, int maxDistance) {
super(propertyName, calculateMatches(propertyName, beanClass, maxDistance));
}
private static String[] calculateMatches(final String propertyName, Class<?> beanClass, final int maxDistance) {
final List<String> candidates = new ArrayList<String>();
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
String possibleAlternative = field.getName();
if (calculateStringDistance(propertyName, possibleAlternative) <= maxDistance) {
candidates.add(possibleAlternative);
}
}
});
Collections.sort(candidates);
return StringUtils.toStringArray(candidates);
}
@Override
public String buildErrorMessage() {
String propertyName = getPropertyName();
String[] possibleMatches = getPossibleMatches();
StringBuilder msg = new StringBuilder();
msg.append("Bean property '");
msg.append(propertyName);
msg.append("' has no matching field. ");
if (!ObjectUtils.isEmpty(possibleMatches)) {
appendHintMessage(msg);
}
return msg.toString();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -204,7 +204,7 @@ class TypeConverterDelegate {
if (Object.class.equals(requiredType)) {
return (T) convertedValue;
}
if (requiredType.isArray()) {
else if (requiredType.isArray()) {
// Array required -> apply appropriate conversion of elements.
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
@@ -339,7 +339,6 @@ class TypeConverterDelegate {
catch (Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Field [" + convertedValue + "] isn't an enum value", ex);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -114,6 +114,7 @@ public interface BeanFactory {
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>This method allows a Spring BeanFactory to be used as a replacement for the
@@ -160,6 +161,7 @@ public interface BeanFactory {
* @return an instance of the single bean matching the required type
* @throws NoSuchBeanDefinitionException if no bean of the given type was found
* @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found
* @throws BeansException if the bean could not be created
* @since 3.0
* @see ListableBeanFactory
*/
@@ -202,6 +204,7 @@ public interface BeanFactory {
*/
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
/**
* Does this bean factory contain a bean definition or externally registered singleton
* instance with the given name?
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,7 +16,6 @@
package org.springframework.beans.factory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,12 +38,15 @@ import java.lang.annotation.Target;
* container to fill them in at runtime. In both cases, the container will generate
* runtime subclasses of the method's containing class via CGLIB, which is why such
* lookup methods can only work on beans that the container instantiates through
* regular constructors (i.e. lookup methods cannot get replaced on beans returned
* from factory methods where we can't dynamically provide a subclass for them).
* regular constructors: i.e. lookup methods cannot get replaced on beans returned
* from factory methods where we cannot dynamically provide a subclass for them.
*
* <p>Note: When used with component scanning or any other mechanism that filters
* out abstract beans, provide stub implementations of your lookup methods to be
* able to declare them as concrete classes.
* <p><b>Concrete limitations in typical Spring configuration scenarios:</b>
* When used with component scanning or any other mechanism that filters out abstract
* beans, provide stub implementations of your lookup methods to be able to declare
* them as concrete classes. And please remember that lookup methods won't work on
* beans returned from {@code @Bean} methods in configuration classes; you'll have
* to resort to {@code @Inject Provider&lt;TargetBean&gt;} or the like instead.
*
* @author Juergen Hoeller
* @since 4.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,33 +30,33 @@ import org.springframework.util.StringValueResolver;
*
* <p>The default placeholder syntax follows the Ant / Log4J / JSP EL style:
*
*<pre class="code">${...}</pre>
* <pre class="code">${...}</pre>
*
* Example XML bean definition:
*
*<pre class="code">{@code
*<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
* <property name="driverClassName" value="}${driver}{@code "/>
* <property name="url" value="jdbc:}${dbname}{@code "/>
*</bean>
*}</pre>
* <pre class="code">
* <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"/>
* <property name="driverClassName" value="${driver}"/>
* <property name="url" value="jdbc:${dbname}"/>
* </bean>
* </pre>
*
* Example properties file:
*
* <pre class="code"> driver=com.mysql.jdbc.Driver
* <pre class="code">driver=com.mysql.jdbc.Driver
* dbname=mysql:mydb</pre>
*
* Annotated bean definitions may take advantage of property replacement using
* the {@link org.springframework.beans.factory.annotation.Value @Value} annotation:
*
*<pre class="code">@Value("${person.age}")</pre>
* <pre class="code">@Value("${person.age}")</pre>
*
* Implementations check simple property values, lists, maps, props, and bean names
* in bean references. Furthermore, placeholder values can also cross-reference
* other placeholders, like:
*
*<pre class="code">rootPath=myrootdir
*subPath=${rootPath}/subdir</pre>
* <pre class="code">rootPath=myrootdir
* subPath=${rootPath}/subdir</pre>
*
* In contrast to {@link PropertyOverrideConfigurer}, subclasses of this type allow
* filling in of explicit placeholders in bean definitions.
@@ -75,9 +75,9 @@ import org.springframework.util.StringValueResolver;
*
* <p>Example XML property with default value:
*
*<pre class="code">{@code
* <property name="url" value="jdbc:}${dbname:defaultdb}{@code "/>
*}</pre>
* <pre class="code">
* <property name="url" value="jdbc:${dbname:defaultdb}"/>
* </pre>
*
* @author Chris Beams
* @author Juergen Hoeller
@@ -107,14 +107,14 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
/** Defaults to {@value #DEFAULT_VALUE_SEPARATOR} */
protected String valueSeparator = DEFAULT_VALUE_SEPARATOR;
protected boolean ignoreUnresolvablePlaceholders = false;
protected String nullValue;
private BeanFactory beanFactory;
protected boolean ignoreUnresolvablePlaceholders = false;
private String beanName;
private BeanFactory beanFactory;
/**
* Set the prefix that a placeholder string starts with.
@@ -143,13 +143,13 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
}
/**
* Set a value that should be treated as {@code null} when
* resolved as a placeholder value: e.g. "" (empty String) or "null".
* Set a value that should be treated as {@code null} when resolved
* as a placeholder value: e.g. "" (empty String) or "null".
* <p>Note that this will only apply to full property values,
* not to parts of concatenated values.
* <p>By default, no such null value is defined. This means that
* there is no way to express {@code null} as a property
* value unless you explicitly map a corresponding value here.
* there is no way to express {@code null} as a property value
* unless you explicitly map a corresponding value here.
*/
public void setNullValue(String nullValue) {
this.nullValue = nullValue;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -219,8 +219,7 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
throws BeansException {
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
this.doProcessProperties(beanFactoryToProcess, valueResolver);
doProcessProperties(beanFactoryToProcess, valueResolver);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,7 @@
package org.springframework.beans.factory.config;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
@@ -35,13 +35,14 @@ import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.parser.ParserException;
import org.yaml.snakeyaml.reader.UnicodeReader;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Base class for Yaml factories.
* Base class for YAML factories.
*
* @author Dave Syer
* @since 4.1
@@ -64,7 +65,6 @@ public abstract class YamlProcessor {
* some of the documents in a YAML resource. In YAML documents are
* separated by <code>---<code> lines, and each document is converted
* to properties before the match is made. E.g.
*
* <pre class="code">
* environment: dev
* url: http://dev.bar.com
@@ -74,11 +74,9 @@ public abstract class YamlProcessor {
* url:http://foo.bar.com
* name: My Cool App
* </pre>
*
* when mapped with
* <code>documentMatchers = YamlProcessor.mapMatcher({"environment": "prod"})</code>
* would end up as
*
* <pre class="code">
* environment=prod
* url=http://foo.bar.com
@@ -102,9 +100,9 @@ public abstract class YamlProcessor {
}
/**
* Method to use for resolving resources. Each resource will be converted to a Map, so
* this property is used to decide which map entries to keep in the final output from
* this factory.
* Method to use for resolving resources. Each resource will be converted to a Map,
* so this property is used to decide which map entries to keep in the final output
* from this factory.
* @param resolutionMethod the resolution method to set (defaults to
* {@link ResolutionMethod#OVERRIDE}).
*/
@@ -126,13 +124,14 @@ public abstract class YamlProcessor {
* Provide an opportunity for subclasses to process the Yaml parsed from the supplied
* resources. Each resource is parsed in turn and the documents inside checked against
* the {@link #setDocumentMatchers(DocumentMatcher...) matchers}. If a document
* matches it is passed into the callback, along with its representation as
* Properties. Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all
* of the documents will be parsed.
* matches it is passed into the callback, along with its representation as Properties.
* Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all of the
* documents will be parsed.
* @param callback a callback to delegate to once matching documents are found
* @see #createYaml()
*/
protected void process(MatchCallback callback) {
Yaml yaml = new Yaml(new StrictMapAppenderConstructor());
Yaml yaml = createYaml();
for (Resource resource : this.resources) {
boolean found = process(callback, yaml, resource);
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
@@ -141,15 +140,22 @@ public abstract class YamlProcessor {
}
}
/**
* Create the {@link Yaml} instance to use.
*/
protected Yaml createYaml() {
return new Yaml(new StrictMapAppenderConstructor());
}
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
int count = 0;
try {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loading from YAML: " + resource);
}
InputStream stream = resource.getInputStream();
Reader reader = new UnicodeReader(resource.getInputStream());
try {
for (Object object : yaml.loadAll(stream)) {
for (Object object : yaml.loadAll(reader)) {
if (object != null && process(asMap(object), callback)) {
count++;
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND) {
@@ -163,7 +169,7 @@ public abstract class YamlProcessor {
}
}
finally {
stream.close();
reader.close();
}
}
catch (IOException ex) {
@@ -331,7 +337,7 @@ public abstract class YamlProcessor {
/**
* Status returned from {@link DocumentMatcher#matches(java.util.Properties)}
*/
public static enum MatchStatus {
public enum MatchStatus {
/**
* A match was found.
@@ -360,7 +366,7 @@ public abstract class YamlProcessor {
/**
* Method to use for resolving resources.
*/
public static enum ResolutionMethod {
public enum ResolutionMethod {
/**
* Replace values from earlier in the list.
@@ -382,9 +388,10 @@ public abstract class YamlProcessor {
/**
* A specialized {@link Constructor} that checks for duplicate keys.
*/
private static class StrictMapAppenderConstructor extends Constructor {
protected static class StrictMapAppenderConstructor extends Constructor {
public StrictMapAppenderConstructor() {
// Declared as public for use in subclasses
public StrictMapAppenderConstructor() {
super();
}
@@ -392,9 +399,10 @@ public abstract class YamlProcessor {
protected Map<Object, Object> constructMapping(MappingNode node) {
try {
return super.constructMapping(node);
} catch (IllegalStateException e) {
}
catch (IllegalStateException ex) {
throw new ParserException("while parsing MappingNode",
node.getStartMark(), e.getMessage(), node.getEndMark());
node.getStartMark(), ex.getMessage(), node.getEndMark());
}
}
@@ -405,7 +413,7 @@ public abstract class YamlProcessor {
@Override
public Object put(Object key, Object value) {
if (delegate.containsKey(key)) {
throw new IllegalStateException("duplicate key: " + key);
throw new IllegalStateException("Duplicate key: " + key);
}
return delegate.put(key, value);
}
@@ -415,7 +423,6 @@ public abstract class YamlProcessor {
}
};
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -679,7 +679,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
// No declared type variables to inspect, so just process the standard return type.
// Declared type variables to inspect?
if (factoryMethod.getTypeParameters().length > 0) {
try {
// Fully resolve parameter names and argument values.
@@ -833,8 +833,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/**
* Obtain a "shortcut" singleton FactoryBean instance to use for a
* {@code getObjectType()} call, without full initialization
* of the FactoryBean.
* {@code getObjectType()} call, without full initialization of the FactoryBean.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the FactoryBean instance, or {@code null} to indicate
@@ -875,8 +874,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/**
* Obtain a "shortcut" non-singleton FactoryBean instance to use for a
* {@code getObjectType()} call, without full initialization
* of the FactoryBean.
* {@code getObjectType()} call, without full initialization of the FactoryBean.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return the FactoryBean instance, or {@code null} to indicate
@@ -897,6 +895,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
instance = bw.getWrappedInstance();
}
}
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isDebugEnabled()) {
logger.debug("Bean creation exception on non-singleton FactoryBean type check: " + ex);
}
onSuppressedException(ex);
return null;
}
finally {
// Finished partial creation of this bean.
afterPrototypeCreation(beanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -1422,9 +1422,15 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return getTypeForFactoryBean(factoryBean);
}
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isWarnEnabled()) {
logger.warn("Bean creation exception on FactoryBean type check: " + ex);
if (ex instanceof BeanCurrentlyInCreationException) {
if (logger.isDebugEnabled()) {
logger.debug("Bean currently in creation on FactoryBean type check: " + ex);
}
}
else {
if (logger.isWarnEnabled()) {
logger.warn("Bean creation exception on FactoryBean type check: " + ex);
}
}
onSuppressedException(ex);
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -279,7 +279,7 @@ public class BeanDefinitionBuilder {
*/
public BeanDefinitionBuilder addDependsOn(String beanName) {
if (this.beanDefinition.getDependsOn() == null) {
this.beanDefinition.setDependsOn(new String[] {beanName});
this.beanDefinition.setDependsOn(beanName);
}
else {
String[] added = ObjectUtils.addObjectToArray(this.beanDefinition.getDependsOn(), beanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
@@ -150,8 +150,8 @@ public class BeanDefinitionReaderUtils {
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -323,7 +323,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
//---------------------------------------------------------------------
// Implementation of ListableBeanFactory interface
// Implementation of remaining BeanFactory methods
//---------------------------------------------------------------------
@Override
@@ -562,17 +562,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
Map<String, Object> results = new LinkedHashMap<String, Object>();
for (String beanName : this.beanDefinitionNames) {
BeanDefinition beanDefinition = getBeanDefinition(beanName);
if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
}
for (String beanName : this.manualSingletonNames) {
if (!results.containsKey(beanName) && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
String[] beanNames = getBeanNamesForAnnotation(annotationType);
Map<String, Object> results = new LinkedHashMap<String, Object>(beanNames.length);
for (String beanName : beanNames) {
results.put(beanName, getBean(beanName));
}
return results;
}
@@ -811,7 +804,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
@@ -820,7 +813,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
" with a framework-generated bean definition ': replacing [" +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -607,13 +607,13 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
/**
* Expose the singleton mutex to subclasses.
* Exposes the singleton mutex to subclasses and external collaborators.
* <p>Subclasses should synchronize on the given Object if they perform
* any sort of extended singleton creation phase. In particular, subclasses
* should <i>not</i> have their own mutexes involved in singleton creation,
* to avoid the potential for deadlocks in lazy-init situations.
*/
protected final Object getSingletonMutex() {
public final Object getSingletonMutex() {
return this.singletonObjects;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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,12 +49,13 @@ import org.springframework.util.StringUtils;
*/
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
/** Constant for the id attribute */
/** Constant for the "id" attribute */
public static final String ID_ATTRIBUTE = "id";
/** Constant for the name attribute */
/** Constant for the "name" attribute */
public static final String NAME_ATTRIBUTE = "name";
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
@@ -66,10 +67,12 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = new String[0];
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
@@ -170,7 +173,18 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars
}
/**
* Controls whether this parser is supposed to fire a
* Determine whether the element's "name" attribute should get parsed as
* bean definition aliases, i.e. alternative bean definition names.
* <p>The default implementation returns {@code true}.
* @return whether the parser should evaluate the "name" attribute as aliases
* @since 4.1.5
*/
protected boolean shouldParseNameAsAliases() {
return true;
}
/**
* Determine whether this parser is supposed to fire a
* {@link org.springframework.beans.factory.parsing.BeanComponentDefinition}
* event after parsing the bean definition.
* <p>This implementation returns {@code true} by default; that is,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.xml;
import java.io.IOException;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -45,7 +44,9 @@ public class BeansDtdResolver implements EntityResolver {
private static final String DTD_EXTENSION = ".dtd";
private static final String[] DTD_NAMES = {"spring-beans-2.0", "spring-beans"};
private static final String DTD_FILENAME = "spring-beans-2.0";
private static final String DTD_NAME = "spring-beans";
private static final Log logger = LogFactory.getLog(BeansDtdResolver.class);
@@ -58,30 +59,28 @@ public class BeansDtdResolver implements EntityResolver {
}
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
int lastPathSeparator = systemId.lastIndexOf("/");
for (String DTD_NAME : DTD_NAMES) {
int dtdNameStart = systemId.indexOf(DTD_NAME);
if (dtdNameStart > lastPathSeparator) {
String dtdFile = systemId.substring(dtdNameStart);
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex);
}
}
int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
if (dtdNameStart != -1) {
String dtdFile = DTD_FILENAME + DTD_EXTENSION;
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
}
}
}
}
@@ -92,7 +91,7 @@ public class BeansDtdResolver implements EntityResolver {
@Override
public String toString() {
return "EntityResolver for DTDs " + Arrays.toString(DTD_NAMES);
return "EntityResolver for spring-beans DTD";
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
@@ -95,6 +95,7 @@ public class CustomBooleanEditor extends PropertyEditorSupport {
this.allowEmpty = allowEmpty;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
String input = (text != null ? text.trim() : null);
@@ -102,20 +103,20 @@ public class CustomBooleanEditor extends PropertyEditorSupport {
// Treat empty String as null value.
setValue(null);
}
else if (this.trueString != null && input.equalsIgnoreCase(this.trueString)) {
else if (this.trueString != null && this.trueString.equalsIgnoreCase(input)) {
setValue(Boolean.TRUE);
}
else if (this.falseString != null && input.equalsIgnoreCase(this.falseString)) {
else if (this.falseString != null && this.falseString.equalsIgnoreCase(input)) {
setValue(Boolean.FALSE);
}
else if (this.trueString == null &&
(input.equalsIgnoreCase(VALUE_TRUE) || input.equalsIgnoreCase(VALUE_ON) ||
input.equalsIgnoreCase(VALUE_YES) || input.equals(VALUE_1))) {
(VALUE_TRUE.equalsIgnoreCase(input) || VALUE_ON.equalsIgnoreCase(input) ||
VALUE_YES.equalsIgnoreCase(input) || VALUE_1.equals(input))) {
setValue(Boolean.TRUE);
}
else if (this.falseString == null &&
(input.equalsIgnoreCase(VALUE_FALSE) || input.equalsIgnoreCase(VALUE_OFF) ||
input.equalsIgnoreCase(VALUE_NO) || input.equals(VALUE_0))) {
(VALUE_FALSE.equalsIgnoreCase(input) || VALUE_OFF.equalsIgnoreCase(input) ||
VALUE_NO.equalsIgnoreCase(input) || VALUE_0.equals(input))) {
setValue(Boolean.FALSE);
}
else {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -518,6 +518,36 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor
assertTrue("correct values", pt.stringArray[0].equals("a1") && pt.stringArray[1].equals("b2"));
}
@Test
public void testStringArrayAutoGrow() throws Exception {
StringArrayBean target = new StringArrayBean();
BeanWrapper bw = new BeanWrapperImpl(target);
bw.setAutoGrowNestedPaths(true);
bw.setPropertyValue("array[0]", "Test0");
assertEquals(1, target.getArray().length);
bw.setPropertyValue("array[2]", "Test2");
assertEquals(3, target.getArray().length);
assertTrue("correct values", target.getArray()[0].equals("Test0") && target.getArray()[1] == null &&
target.getArray()[2].equals("Test2"));
}
@Test
public void testPrimitiveArrayAutoGrow() throws Exception {
PrimitiveArrayBean target = new PrimitiveArrayBean();
BeanWrapper bw = new BeanWrapperImpl(target);
bw.setAutoGrowNestedPaths(true);
bw.setPropertyValue("array[0]", 1);
assertEquals(1, target.getArray().length);
bw.setPropertyValue("array[2]", 3);
assertEquals(3, target.getArray().length);
assertTrue("correct values", target.getArray()[0] == 1 && target.getArray()[1] == 0 &&
target.getArray()[2] == 3);
}
@Test
public void testStringPropertyWithCustomEditor() throws Exception {
TestBean tb = new TestBean();
@@ -1723,6 +1753,20 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor
}
}
@SuppressWarnings("unused")
private static class StringArrayBean {
private String[] array;
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
}
@SuppressWarnings("unused")
private static class NumberPropertyBean {
@@ -841,19 +841,24 @@ public class ExtendedBeanInfoTests {
public String getAddress(int index){ return null; }
}
{ // baseline. ExtendedBeanInfo needs to behave exactly like the following
// Baseline: ExtendedBeanInfo needs to behave exactly like the following...
boolean hasReadMethod;
boolean hasWriteMethod;
boolean hasIndexedReadMethod;
boolean hasIndexedWriteMethod;
{
BeanInfo bi = Introspector.getBeanInfo(A.class);
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
hasReadMethod = hasReadMethodForProperty(bi, "address");
hasWriteMethod = hasWriteMethodForProperty(bi, "address");
hasIndexedReadMethod = hasIndexedReadMethodForProperty(bi, "address");
hasIndexedWriteMethod = hasIndexedWriteMethodForProperty(bi, "address");
}
{
BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
assertEquals(hasReadMethodForProperty(bi, "address"), hasReadMethod);
assertEquals(hasWriteMethodForProperty(bi, "address"), hasWriteMethod);
assertEquals(hasIndexedReadMethodForProperty(bi, "address"), hasIndexedReadMethod);
assertEquals(hasIndexedWriteMethodForProperty(bi, "address"), hasIndexedWriteMethod);
}
}
@@ -0,0 +1,192 @@
/*
* Copyright 2002-2015 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;
import org.junit.Test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Tests for {@link PropertyMatches}.
*
* @author Stephane Nicoll
*/
public class PropertyMatchesTests {
@Test
public void simpleBeanPropertyTypo() {
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches(), hasItemInArray("name"));
}
@Test
public void complexBeanPropertyTypo() {
PropertyMatches matches = PropertyMatches.forProperty("desriptn", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches(), emptyArray());
}
@Test
public void unknownBeanProperty() {
PropertyMatches matches = PropertyMatches.forProperty("unknown", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches(), emptyArray());
}
@Test
public void severalMatchesBeanProperty() {
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
assertThat(matches.getPossibleMatches(), hasItemInArray("counter1"));
assertThat(matches.getPossibleMatches(), hasItemInArray("counter2"));
assertThat(matches.getPossibleMatches(), hasItemInArray("counter3"));
}
@Test
public void simpleBeanPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forProperty("naem", SampleBeanProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg, containsString("naem"));
assertThat(msg, containsString("name"));
assertThat(msg, containsString("setter"));
assertThat(msg, not(containsString("field")));
}
@Test
public void complexBeanPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forProperty("counter", SampleBeanProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg, containsString("counter"));
assertThat(msg, containsString("counter1"));
assertThat(msg, containsString("counter2"));
assertThat(msg, containsString("counter3"));
}
@Test
public void simpleFieldPropertyTypo() {
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches(), hasItemInArray("name"));
}
@Test
public void complexFieldPropertyTypo() {
PropertyMatches matches = PropertyMatches.forField("desriptn", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches(), emptyArray());
}
@Test
public void unknownFieldProperty() {
PropertyMatches matches = PropertyMatches.forField("unknown", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches(), emptyArray());
}
@Test
public void severalMatchesFieldProperty() {
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
assertThat(matches.getPossibleMatches(), hasItemInArray("counter1"));
assertThat(matches.getPossibleMatches(), hasItemInArray("counter2"));
assertThat(matches.getPossibleMatches(), hasItemInArray("counter3"));
}
@Test
public void simpleFieldPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forField("naem", SampleFieldProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg, containsString("naem"));
assertThat(msg, containsString("name"));
assertThat(msg, containsString("field"));
assertThat(msg, not(containsString("setter")));
}
@Test
public void complexFieldPropertyErrorMessage() {
PropertyMatches matches = PropertyMatches.forField("counter", SampleFieldProperties.class);
String msg = matches.buildErrorMessage();
assertThat(msg, containsString("counter"));
assertThat(msg, containsString("counter1"));
assertThat(msg, containsString("counter2"));
assertThat(msg, containsString("counter3"));
}
private static class SampleBeanProperties {
private String name;
private String description;
private int counter1;
private int counter2;
private int counter3;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getCounter1() {
return counter1;
}
public void setCounter1(int counter1) {
this.counter1 = counter1;
}
public int getCounter2() {
return counter2;
}
public void setCounter2(int counter2) {
this.counter2 = counter2;
}
public int getCounter3() {
return counter3;
}
public void setCounter3(int counter3) {
this.counter3 = counter3;
}
}
private static class SampleFieldProperties {
private String name;
private String description;
private int counter1;
private int counter2;
private int counter3;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,8 +23,6 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@@ -53,16 +51,16 @@ public final class BeanFactoryUtilsTests {
private static final Resource LEAF_CONTEXT = qualifiedResource(CLASS, "leaf.xml");
private static final Resource DEPENDENT_BEANS_CONTEXT = qualifiedResource(CLASS, "dependentBeans.xml");
private ConfigurableListableBeanFactory listableBeanFactory;
private DefaultListableBeanFactory listableBeanFactory;
private DefaultListableBeanFactory dependentBeansFactory;
private ConfigurableListableBeanFactory dependentBeansBF;
@Before
public void setUp() {
// Interesting hierarchical factory to test counts.
// Slow to read so we cache it.
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
DefaultListableBeanFactory parent = new DefaultListableBeanFactory(grandParent);
@@ -70,12 +68,13 @@ public final class BeanFactoryUtilsTests {
DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
new XmlBeanDefinitionReader(child).loadBeanDefinitions(LEAF_CONTEXT);
this.dependentBeansBF = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader((BeanDefinitionRegistry) this.dependentBeansBF).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
dependentBeansBF.preInstantiateSingletons();
this.dependentBeansFactory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(this.dependentBeansFactory).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
dependentBeansFactory.preInstantiateSingletons();
this.listableBeanFactory = child;
}
@Test
public void testHierarchicalCountBeansWithNonHierarchicalFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
@@ -92,22 +91,21 @@ public final class BeanFactoryUtilsTests {
// Leaf count
assertTrue(this.listableBeanFactory.getBeanDefinitionCount() == 1);
// Count minus duplicate
assertTrue("Should count 7 beans, not "
+ BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
assertTrue("Should count 7 beans, not " + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
}
@Test
public void testHierarchicalNamesWithNoMatch() throws Exception {
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
NoOp.class));
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
assertEquals(0, names.size());
}
@Test
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
IndexedTestBean.class));
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
assertEquals(1, names.size());
assertTrue(names.contains("indexedBean"));
// Distinguish from default ListableBeanFactory behavior
@@ -116,8 +114,8 @@ public final class BeanFactoryUtilsTests {
@Test
public void testGetBeanNamesForTypeWithOverride() throws Exception {
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
ITestBean.class));
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
assertEquals(4, names.size());
assertTrue(names.contains("test"));
@@ -130,7 +128,7 @@ public final class BeanFactoryUtilsTests {
public void testNoBeansOfType() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
lbf.addBean("foo", new Object());
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
assertTrue(beans.isEmpty());
}
@@ -147,7 +145,7 @@ public final class BeanFactoryUtilsTests {
lbf.addBean("t3", t3);
lbf.addBean("t4", t4);
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
assertEquals(2, beans.size());
assertEquals(t1, beans.get("t1"));
assertEquals(t2, beans.get("t2"));
@@ -191,8 +189,8 @@ public final class BeanFactoryUtilsTests {
this.listableBeanFactory.registerSingleton("t3", t3);
this.listableBeanFactory.registerSingleton("t4", t4);
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
false);
Map<String, ?> beans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
assertEquals(6, beans.size());
assertEquals(test3, beans.get("test3"));
assertEquals(test, beans.get("test"));
@@ -200,12 +198,9 @@ public final class BeanFactoryUtilsTests {
assertEquals(t2, beans.get("t2"));
assertEquals(t3.getObject(), beans.get("t3"));
assertTrue(beans.get("t4") instanceof TestBean);
// t3 and t4 are found here as of Spring 2.0, since they are
// pre-registered
// singleton instances, while testFactory1 and testFactory are *not*
// found
// because they are FactoryBean definitions that haven't been
// initialized yet.
// t3 and t4 are found here as of Spring 2.0, since they are pre-registered
// singleton instances, while testFactory1 and testFactory are *not* found
// because they are FactoryBean definitions that haven't been initialized yet.
beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, true);
Object testFactory1 = this.listableBeanFactory.getBean("testFactory1");
@@ -247,8 +242,8 @@ public final class BeanFactoryUtilsTests {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
false);
Map<String, ?> beans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
assertEquals(2, beans.size());
assertEquals(test3, beans.get("test3"));
assertEquals(test, beans.get("test"));
@@ -283,25 +278,25 @@ public final class BeanFactoryUtilsTests {
@Test
public void testADependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("a");
String[] deps = this.dependentBeansFactory.getDependentBeans("a");
assertTrue(ObjectUtils.isEmpty(deps));
}
@Test
public void testBDependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("b");
String[] deps = this.dependentBeansFactory.getDependentBeans("b");
assertTrue(Arrays.equals(new String[] { "c" }, deps));
}
@Test
public void testCDependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("c");
String[] deps = this.dependentBeansFactory.getDependentBeans("c");
assertTrue(Arrays.equals(new String[] { "int", "long" }, deps));
}
@Test
public void testIntDependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("int");
String[] deps = this.dependentBeansFactory.getDependentBeans("int");
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -200,7 +200,7 @@ public class DefaultListableBeanFactoryTests {
}
@Test
public void testPrototypeSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
public void testSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
Properties p = new Properties();
p.setProperty("x1.(class)", DummyFactory.class.getName());
@@ -1340,10 +1340,10 @@ public class DefaultListableBeanFactoryTests {
public void testDependsOnCycle() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
bd1.setDependsOn(new String[] {"tb2"});
bd1.setDependsOn("tb2");
lbf.registerBeanDefinition("tb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setDependsOn(new String[] {"tb1"});
bd2.setDependsOn("tb1");
lbf.registerBeanDefinition("tb2", bd2);
try {
lbf.preInstantiateSingletons();
@@ -1361,13 +1361,13 @@ public class DefaultListableBeanFactoryTests {
public void testImplicitDependsOnCycle() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
bd1.setDependsOn(new String[] {"tb2"});
bd1.setDependsOn("tb2");
lbf.registerBeanDefinition("tb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setDependsOn(new String[] {"tb3"});
bd2.setDependsOn("tb3");
lbf.registerBeanDefinition("tb2", bd2);
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
bd3.setDependsOn(new String[] {"tb1"});
bd3.setDependsOn("tb1");
lbf.registerBeanDefinition("tb3", bd3);
try {
lbf.preInstantiateSingletons();
@@ -1381,7 +1381,7 @@ public class DefaultListableBeanFactoryTests {
}
}
@Test(expected=NoSuchBeanDefinitionException.class)
@Test(expected = NoSuchBeanDefinitionException.class)
public void testGetBeanByTypeWithNoneFound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.getBean(TestBean.class);
@@ -1397,7 +1397,7 @@ public class DefaultListableBeanFactoryTests {
assertThat(bean.getBeanName(), equalTo("bd1"));
}
@Test(expected=NoUniqueBeanDefinitionException.class)
@Test(expected = NoUniqueBeanDefinitionException.class)
public void testGetBeanByTypeWithAmbiguity() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
@@ -1540,7 +1540,7 @@ public class DefaultListableBeanFactoryTests {
}
@Test
public void testGetBeanByTypeInstanceWithPrimary() throws Exception {
public void testGetBeanByTypeInstanceWithPrimary() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
@@ -1553,7 +1553,7 @@ public class DefaultListableBeanFactoryTests {
}
@Test
public void testGetBeanByTypeInstanceWithMultiplePrimary() throws Exception {
public void testGetBeanByTypeInstanceWithMultiplePrimary() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
@@ -1584,16 +1584,35 @@ public class DefaultListableBeanFactoryTests {
try {
lbf.getBean(TestBean.class, 67);
fail("Should have thrown NoSuchBeanDefinitionException");
} catch (NoSuchBeanDefinitionException ex) {
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
@Test
public void testGetBeanWithArgsNotCreatedForFactoryBeanChecking() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(ConstructorDependency.class);
bd1.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bd1.getConstructorArgumentValues().addGenericArgumentValue(String.valueOf(age));
return bd1;
lbf.registerBeanDefinition("bd1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("bd2", bd2);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class, 42);
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(42));
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependency.class).length);
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length);
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependency.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bd.getConstructorArgumentValues().addGenericArgumentValue(String.valueOf(age));
return bd;
}
@Test
@@ -1641,7 +1660,7 @@ public class DefaultListableBeanFactoryTests {
* Java method names. In other words, you can't name a method
* {@code set&amp;FactoryBean(...)}.
*/
@Test(expected=TypeMismatchException.class)
@Test(expected = TypeMismatchException.class)
public void testAutowireBeanWithFactoryBeanByName() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
@@ -1664,8 +1683,8 @@ public class DefaultListableBeanFactoryTests {
}
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().indexOf("test") != -1);
assertTrue(ex.getMessage().indexOf("spouse") != -1);
assertTrue(ex.getMessage().contains("test"));
assertTrue(ex.getMessage().contains("spouse"));
}
}
@@ -1682,8 +1701,8 @@ public class DefaultListableBeanFactoryTests {
}
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().indexOf("test") != -1);
assertTrue(ex.getMessage().indexOf("spouse") != -1);
assertTrue(ex.getMessage().contains("test"));
assertTrue(ex.getMessage().contains("spouse"));
}
}
@@ -2518,7 +2537,7 @@ public class DefaultListableBeanFactoryTests {
assertEquals(expectedNameFromArgs, tb2.getName());
}
@Test(expected=IllegalStateException.class)
@Test(expected = IllegalStateException.class)
public void testScopingBeanToUnregisteredScopeResultsInAnException() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
@@ -11,7 +11,7 @@
<bean id="gamma" class="org.springframework.beans.factory.FactoryBeanTests$Gamma"/>
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean">
<bean id="betaFactory" class="org.springframework.beans.factory.FactoryBeanTests$BetaFactoryBean" autowire="constructor">
<property name="beta" ref="beta"/>
</bean>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -39,7 +38,7 @@ import static org.springframework.tests.TestResourceUtils.*;
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class FactoryBeanTests {
public class FactoryBeanTests {
private static final Class<?> CLASS = FactoryBeanTests.class;
private static final Resource RETURNS_NULL_CONTEXT = qualifiedResource(CLASS, "returnsNull.xml");
@@ -47,6 +46,7 @@ public final class FactoryBeanTests {
private static final Resource ABSTRACT_CONTEXT = qualifiedResource(CLASS, "abstract.xml");
private static final Resource CIRCULAR_CONTEXT = qualifiedResource(CLASS, "circular.xml");
@Test
public void testFactoryBeanReturnsNull() throws Exception {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@@ -63,10 +63,13 @@ public final class FactoryBeanTests {
BeanFactoryPostProcessor ppc = (BeanFactoryPostProcessor) factory.getBean("propertyPlaceholderConfigurer");
ppc.postProcessBeanFactory(factory);
assertNull(factory.getType("betaFactory"));
Alpha alpha = (Alpha) factory.getBean("alpha");
Beta beta = (Beta) factory.getBean("beta");
Gamma gamma = (Gamma) factory.getBean("gamma");
Gamma gamma2 = (Gamma) factory.getBean("gammaFactory");
assertSame(beta, alpha.getBeta());
assertSame(gamma, beta.getGamma());
assertSame(gamma2, beta.getGamma());
@@ -194,6 +197,9 @@ public final class FactoryBeanTests {
@Component
public static class BetaFactoryBean implements FactoryBean<Object> {
public BetaFactoryBean(Alpha alpha) {
}
private Beta beta;
public void setBeta(Beta beta) {
@@ -238,12 +244,12 @@ public final class FactoryBeanTests {
public void setInstanceName(String instanceName) {
this.instanceName = instanceName;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public T getObject() {
if (instance == null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -27,7 +27,6 @@ import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import java.util.prefs.PreferencesFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
@@ -53,13 +52,13 @@ import static org.springframework.tests.TestResourceUtils.*;
* {@link PropertyPlaceholderConfigurer}, {@link PropertyOverrideConfigurer} and
* {@link PreferencesPlaceholderConfigurer}.
*
* @see PropertyPlaceholderConfigurerTests
* @since 02.10.2003
* @author Juergen Hoeller
* @author Chris Beams
* @author Phillip Webb
* @since 02.10.2003
* @see PropertyPlaceholderConfigurerTests
*/
public final class PropertyResourceConfigurerTests {
public class PropertyResourceConfigurerTests {
static {
System.setProperty("java.util.prefs.PreferencesFactory", MockPreferencesFactory.class.getName());
@@ -70,23 +69,15 @@ public final class PropertyResourceConfigurerTests {
private static final Resource XTEST_PROPS = qualifiedResource(CLASS, "xtest.properties"); // does not exist
private static final Resource TEST_PROPS_XML = qualifiedResource(CLASS, "test.properties.xml");
private DefaultListableBeanFactory factory;
private final DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@Before
public void setUp() {
factory = new DefaultListableBeanFactory();
}
@Test
public void testPropertyOverrideConfigurer() {
BeanDefinition def1 = BeanDefinitionBuilder
.genericBeanDefinition(TestBean.class)
.getBeanDefinition();
BeanDefinition def1 = BeanDefinitionBuilder.genericBeanDefinition(TestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb1", def1);
BeanDefinition def2 = BeanDefinitionBuilder
.genericBeanDefinition(TestBean.class)
.getBeanDefinition();
BeanDefinition def2 = BeanDefinitionBuilder.genericBeanDefinition(TestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb2", def2);
PropertyOverrideConfigurer poc1;
@@ -123,9 +114,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithNestedProperty() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc;
@@ -143,9 +132,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithNestedPropertyAndDotInBeanName() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("my.tb", def);
PropertyOverrideConfigurer poc;
@@ -164,9 +151,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithNestedMapPropertyAndDotInMapKey() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc;
@@ -184,9 +169,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithHeldProperties() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(PropertiesHolder.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(PropertiesHolder.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc;
@@ -200,23 +183,9 @@ public final class PropertyResourceConfigurerTests {
assertEquals("true", tb.getHeldProperties().getProperty("mail.smtp.auth"));
}
static class PropertiesHolder {
private Properties props = new Properties();
public Properties getHeldProperties() {
return props;
}
public void setHeldProperties(Properties props) {
this.props = props;
}
}
@Test
public void testPropertyOverrideConfigurerWithPropertiesFile() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
@@ -230,13 +199,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithInvalidPropertiesFile() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
poc.setLocations(new Resource[] { TEST_PROPS, XTEST_PROPS });
poc.setLocations(TEST_PROPS, XTEST_PROPS);
poc.setIgnoreResourceNotFound(true);
poc.postProcessBeanFactory(factory);
@@ -247,9 +214,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithPropertiesXmlFile() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
@@ -263,9 +228,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithConvertProperties() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
ConvertingOverrideConfigurer bfpp = new ConvertingOverrideConfigurer();
@@ -389,7 +352,6 @@ public final class PropertyResourceConfigurerTests {
cas.addGenericArgumentValue("${var}name${age}");
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("stringArray", new String[] {"${os.name}", "${age}"});
List<Object> friends = new ManagedList<Object>();
@@ -409,7 +371,7 @@ public final class PropertyResourceConfigurerTests {
someMap.put("key1", new RuntimeBeanReference("${ref}"));
someMap.put("key2", "${age}name");
MutablePropertyValues innerPvs = new MutablePropertyValues();
innerPvs.add("touchy", "${os.name}");
innerPvs.add("country", "${os.name}");
RootBeanDefinition innerBd = new RootBeanDefinition(TestBean.class);
innerBd.setPropertyValues(innerPvs);
someMap.put("key3", innerBd);
@@ -459,30 +421,28 @@ public final class PropertyResourceConfigurerTests {
TestBean inner2 = (TestBean) tb2.getSomeMap().get("mykey4");
assertEquals(0, inner1.getAge());
assertEquals(null, inner1.getName());
assertEquals(System.getProperty("os.name"), inner1.getTouchy());
assertEquals(System.getProperty("os.name"), inner1.getCountry());
assertEquals(98, inner2.getAge());
assertEquals("namemyvarmyvar${", inner2.getName());
assertEquals(System.getProperty("os.name"), inner2.getTouchy());
assertEquals(System.getProperty("os.name"), inner2.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithSystemPropertyFallback() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("country", "${os.name}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals(System.getProperty("os.name"), tb.getTouchy());
assertEquals(System.getProperty("os.name"), tb.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithSystemPropertyNotUsed() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("country", "${os.name}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -491,14 +451,13 @@ public final class PropertyResourceConfigurerTests {
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals("myos", tb.getTouchy());
assertEquals("myos", tb.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithOverridingSystemProperty() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("country", "${os.name}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -508,14 +467,13 @@ public final class PropertyResourceConfigurerTests {
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals(System.getProperty("os.name"), tb.getTouchy());
assertEquals(System.getProperty("os.name"), tb.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithUnresolvableSystemProperty() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${user.dir}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${user.dir}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_NEVER);
@@ -532,9 +490,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithUnresolvablePlaceholder() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -550,9 +507,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithIgnoreUnresolvablePlaceholder() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setIgnoreUnresolvablePlaceholders(true);
@@ -564,9 +520,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithEmptyStringAsNull() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setNullValue("");
@@ -578,9 +533,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithEmptyStringInPlaceholderAsNull() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setNullValue("");
@@ -595,9 +549,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithNestedPlaceholderInKey() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my${key}key}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my${key}key}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -612,8 +565,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithPlaceholderInAlias() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerAlias("tb", "${alias}");
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -629,8 +581,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithSelfReferencingPlaceholderInAlias() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerAlias("tb", "${alias}");
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -646,11 +597,10 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithCircularReference() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("age", "${age}")
.addPropertyValue("name", "name${var}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("age", "${age}")
.addPropertyValue("name", "name${var}")
.getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -670,9 +620,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithDefaultProperties() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -686,9 +635,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithInlineDefault() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.postProcessBeanFactory(factory);
@@ -699,9 +647,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithAliases() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
factory.registerAlias("tb", "${myAlias}");
factory.registerAlias("${myTarget}", "alias2");
@@ -724,12 +671,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPreferencesPlaceholderConfigurer() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
Properties props = new Properties();
@@ -752,12 +698,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPreferencesPlaceholderConfigurerWithCustomTreePaths() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
Properties props = new Properties();
@@ -782,12 +727,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPreferencesPlaceholderConfigurerWithPathInPlaceholder() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${mypath/myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myotherpath/myTouchy}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${mypath/myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myotherpath/myTouchy}")
.getBeanDefinition());
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
Properties props = new Properties();
@@ -811,6 +755,20 @@ public final class PropertyResourceConfigurerTests {
}
static class PropertiesHolder {
private Properties props = new Properties();
public Properties getHeldProperties() {
return props;
}
public void setHeldProperties(Properties props) {
this.props = props;
}
}
private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer {
@Override
@@ -819,26 +777,28 @@ public final class PropertyResourceConfigurerTests {
}
}
/**
* {@link PreferencesFactory} to create {@link MockPreferences}.
*/
public static class MockPreferencesFactory implements PreferencesFactory {
private Preferences systemRoot = new MockPreferences();
private final Preferences userRoot = new MockPreferences();
private Preferences userRoot = new MockPreferences();
private final Preferences systemRoot = new MockPreferences();
@Override
public Preferences systemRoot() {
return systemRoot;
return this.systemRoot;
}
@Override
public Preferences userRoot() {
return userRoot;
return this.userRoot;
}
}
/**
* Mock implementation of {@link Preferences} that behaves the same regardless of the
* underlying operating system and will never throw security exceptions.
@@ -904,4 +864,5 @@ public final class PropertyResourceConfigurerTests {
protected void flushSpi() throws BackingStoreException {
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -770,7 +770,7 @@ public class BeanFactoryGenericsTests {
}
@Test
public void testSpr11250() {
public void testGenericMatchingWithBeanNameDifferentiation() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
@@ -780,8 +780,23 @@ public class BeanFactoryGenericsTests {
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
NumberBean nb = bf.getBean(NumberBean.class);
assertNotNull(nb.getDoubleStore());
assertNotNull(nb.getFloatStore());
assertSame(bf.getBean("doubleStore"), nb.getDoubleStore());
assertSame(bf.getBean("floatStore"), nb.getFloatStore());
}
@Test
public void testGenericMatchingWithFullTypeDifferentiation() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
bf.registerBeanDefinition("store1", new RootBeanDefinition(DoubleStore.class));
bf.registerBeanDefinition("store2", new RootBeanDefinition(FloatStore.class));
bf.registerBeanDefinition("numberBean",
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
NumberBean nb = bf.getBean(NumberBean.class);
assertSame(bf.getBean("store1"), nb.getDoubleStore());
assertSame(bf.getBean("store2"), nb.getFloatStore());
}
@@ -851,6 +866,14 @@ public class BeanFactoryGenericsTests {
}
public static class DoubleStore extends NumberStore<Double> {
}
public static class FloatStore extends NumberStore<Float> {
}
public static class NumberBean {
private final NumberStore<Double> doubleStore;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,7 +59,6 @@ import static org.junit.Assert.*;
* @author Rob Harrop
* @author Arjen Poutsma
* @author Chris Beams
*
* @since 10.06.2003
*/
public class CustomEditorTests {
@@ -302,8 +301,8 @@ public class CustomEditorTests {
@Test
public void testCustomBooleanEditorWithSpecialTrueAndFalseStrings() throws Exception {
final String trueString = "pechorin";
final String falseString = "nash";
String trueString = "pechorin";
String falseString = "nash";
CustomBooleanEditor editor = new CustomBooleanEditor(trueString, falseString, false);
@@ -320,6 +319,14 @@ public class CustomEditorTests {
editor.setAsText(falseString.toUpperCase());
assertFalse(((Boolean) editor.getValue()).booleanValue());
assertEquals(falseString, editor.getAsText());
try {
editor.setAsText(null);
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
}
@Test
@@ -423,7 +430,7 @@ public class CustomEditorTests {
assertTrue("Correct bigDecimal value", new BigDecimal("4.5").equals(tb.getBigDecimal()));
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testCustomNumberEditorCtorWithNullNumberType() throws Exception {
new CustomNumberEditor(null, true);
}
@@ -543,7 +550,7 @@ public class CustomEditorTests {
assertNull(cb.getMyCharacter());
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testCharacterEditorSetAsTextWithStringLongerThanOneCharacter() throws Exception {
PropertyEditor charEditor = new CharacterEditor(false);
charEditor.setAsText("ColdWaterCanyon");
@@ -562,7 +569,7 @@ public class CustomEditorTests {
assertEquals(" ", charEditor.getAsText());
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testCharacterEditorSetAsTextWithNullNotAllowingEmptyAsNull() throws Exception {
PropertyEditor charEditor = new CharacterEditor(false);
charEditor.setAsText(null);
@@ -583,7 +590,7 @@ public class CustomEditorTests {
assertEquals("", classEditor.getAsText());
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testClassEditorWithNonExistentClass() throws Exception {
PropertyEditor classEditor = new ClassEditor();
classEditor.setAsText("hairdresser.on.Fire");
@@ -685,26 +692,40 @@ public class CustomEditorTests {
@Test
public void testCustomBooleanEditor() {
CustomBooleanEditor editor = new CustomBooleanEditor(false);
editor.setAsText("true");
assertEquals(Boolean.TRUE, editor.getValue());
assertEquals("true", editor.getAsText());
editor.setAsText("false");
assertEquals(Boolean.FALSE, editor.getValue());
assertEquals("false", editor.getAsText());
editor.setValue(null);
assertEquals(null, editor.getValue());
assertEquals("", editor.getAsText());
try {
editor.setAsText(null);
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
}
@Test
public void testCustomBooleanEditorWithEmptyAsNull() {
CustomBooleanEditor editor = new CustomBooleanEditor(true);
editor.setAsText("true");
assertEquals(Boolean.TRUE, editor.getValue());
assertEquals("true", editor.getAsText());
editor.setAsText("false");
assertEquals(Boolean.FALSE, editor.getValue());
assertEquals("false", editor.getAsText());
editor.setValue(null);
assertEquals(null, editor.getValue());
assertEquals("", editor.getAsText());
@@ -750,7 +771,7 @@ public class CustomEditorTests {
}
catch (IllegalArgumentException ex) {
// expected
assertTrue(ex.getMessage().indexOf("10") != -1);
assertTrue(ex.getMessage().contains("10"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2006 the original author or authors.
* Copyright 2002-2015 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,9 +30,9 @@ import static org.junit.Assert.*;
* @author Rick Evans
* @author Chris Beams
*/
public final class InputStreamEditorTests {
public class InputStreamEditorTests {
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testCtorWithNullResourceEditor() throws Exception {
new InputStreamEditor(null);
}
@@ -41,7 +41,8 @@ public final class InputStreamEditorTests {
public void testSunnyDay() throws Exception {
InputStream stream = null;
try {
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class";
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) +
"/" + ClassUtils.getShortName(getClass()) + ".class";
InputStreamEditor editor = new InputStreamEditor();
editor.setAsText(resource);
Object value = editor.getValue();
@@ -49,14 +50,15 @@ public final class InputStreamEditorTests {
assertTrue(value instanceof InputStream);
stream = (InputStream) value;
assertTrue(stream.available() > 0);
} finally {
}
finally {
if (stream != null) {
stream.close();
}
}
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void testWhenResourceDoesNotExist() throws Exception {
String resource = "classpath:bingo!";
InputStreamEditor editor = new InputStreamEditor();
@@ -66,7 +68,8 @@ public final class InputStreamEditorTests {
@Test
public void testGetAsTextReturnsNullByDefault() throws Exception {
assertNull(new InputStreamEditor().getAsText());
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) + "/" + ClassUtils.getShortName(getClass()) + ".class";
String resource = "classpath:" + ClassUtils.classPackageAsResourcePath(getClass()) +
"/" + ClassUtils.getShortName(getClass()) + ".class";
InputStreamEditor editor = new InputStreamEditor();
editor.setAsText(resource);
assertNull(editor.getAsText());
@@ -1,5 +1,5 @@
<?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">
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -24,7 +24,6 @@ import net.sf.ehcache.Status;
import org.springframework.cache.Cache;
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
import org.springframework.util.Assert;
/**
* CacheManager backed by an EhCache {@link net.sf.ehcache.CacheManager}.
@@ -81,8 +80,10 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
@Override
protected Collection<Cache> loadCaches() {
Status status = getCacheManager().getStatus();
Assert.isTrue(Status.STATUS_ALIVE.equals(status),
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
if (!Status.STATUS_ALIVE.equals(status)) {
throw new IllegalStateException(
"An 'alive' EhCache CacheManager is required - current cache is " + status.toString());
}
String[] names = getCacheManager().getCacheNames();
Collection<Cache> caches = new LinkedHashSet<Cache>(names.length);
@@ -94,8 +95,7 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
@Override
protected Cache getMissingCache(String name) {
// check the EhCache cache again
// (in case the cache was added at runtime)
// Check the EhCache cache again (in case the cache was added at runtime)
Ehcache ehcache = getCacheManager().getEhcache(name);
if (ehcache != null) {
return new EhCacheCache(ehcache);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -20,13 +20,16 @@ import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;
/**
* Spring {@link Cache} adapter implementation on top of a
* Guava {@link com.google.common.cache.Cache} instance.
* Spring {@link org.springframework.cache.Cache} adapter implementation
* on top of a Guava {@link com.google.common.cache.Cache} instance.
*
* <p>Requires Google Guava 12.0 or higher.
*
@@ -88,8 +91,16 @@ public class GuavaCache implements Cache {
@Override
public ValueWrapper get(Object key) {
Object value = this.cache.getIfPresent(key);
return toWrapper(value);
if (this.cache instanceof LoadingCache) {
try {
Object value = ((LoadingCache<Object, Object>) this.cache).get(key);
return toWrapper(value);
}
catch (ExecutionException ex) {
throw new UncheckedExecutionException(ex.getMessage(), ex);
}
}
return toWrapper(this.cache.getIfPresent(key));
}
@Override
@@ -163,6 +174,10 @@ public class GuavaCache implements Cache {
@SuppressWarnings("serial")
private static class NullHolder implements Serializable {
private Object readResolve() {
return NULL_HOLDER;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -142,6 +142,10 @@ public class JCacheCache implements Cache {
@SuppressWarnings("serial")
private static class NullHolder implements Serializable {
private Object readResolve() {
return NULL_HOLDER;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.cache.jcache.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cache.annotation.AbstractCachingConfiguration;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
import org.springframework.cache.jcache.interceptor.JCacheOperationSource;
@@ -34,14 +35,16 @@ import org.springframework.context.annotation.Role;
* @see JCacheConfigurer
*/
@Configuration
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration<JCacheConfigurer> {
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration {
protected CacheResolver exceptionCacheResolver;
@Override
protected void useCachingConfigurer(JCacheConfigurer config) {
protected void useCachingConfigurer(CachingConfigurer config) {
super.useCachingConfigurer(config);
this.exceptionCacheResolver = config.exceptionCacheResolver();
if (config instanceof JCacheConfigurer) {
this.exceptionCacheResolver = ((JCacheConfigurer) config).exceptionCacheResolver();
}
}
@Bean(name = "jCacheOperationSource")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,19 +29,18 @@ import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.ClassUtils;
/**
* Abstract implementation of {@link JCacheOperationSource} that caches
* attributes for methods and implements a fallback policy: 1. specific
* target method; 2. declaring method.
* Abstract implementation of {@link JCacheOperationSource} that caches attributes
* for methods and implements a fallback policy: 1. specific target method;
* 2. declaring method.
*
* <p>This implementation caches attributes by method after they are
* first used.
* <p>This implementation caches attributes by method after they are first used.
*
* @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.1
* @see org.springframework.cache.interceptor.AbstractFallbackCacheOperationSource
*/
public abstract class AbstractFallbackJCacheOperationSource
implements JCacheOperationSource {
public abstract class AbstractFallbackJCacheOperationSource implements JCacheOperationSource {
/**
* Canonical value held in cache to indicate no caching attribute was
@@ -49,34 +48,31 @@ public abstract class AbstractFallbackJCacheOperationSource
*/
private final static Object NULL_CACHING_ATTRIBUTE = new Object();
protected final Log logger = LogFactory.getLog(getClass());
private final Map<Object, Object> cache =
new ConcurrentHashMap<Object, Object>(1024);
private final Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>(1024);
@Override
public JCacheOperation<?> getCacheOperation(Method method, Class<?> targetClass) {
// First, see if we have a cached value.
Object cacheKey = new MethodCacheKey(method, targetClass);
Object cached = this.cache.get(cacheKey);
if (cached != null) {
if (cached == NULL_CACHING_ATTRIBUTE) {
return null;
}
return (JCacheOperation<?>) cached;
return (cached != NULL_CACHING_ATTRIBUTE ? (JCacheOperation<?>) cached : null);
}
else {
JCacheOperation<?> operation = computeCacheOperation(method, targetClass);
if (operation == null) {
this.cache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
else {
if (operation != null) {
if (logger.isDebugEnabled()) {
logger.debug("Adding cacheable method '" + method.getName()
+ "' with operation: " + operation);
logger.debug("Adding cacheable method '" + method.getName() + "' with operation: " + operation);
}
this.cache.put(cacheKey, operation);
}
else {
this.cache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
return operation;
}
}
@@ -108,6 +104,7 @@ public abstract class AbstractFallbackJCacheOperationSource
return null;
}
/**
* Subclasses need to implement this to return the caching operation
* for the given method, if any.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,6 +16,8 @@
package org.springframework.cache.jcache.interceptor;
import java.util.Collection;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -23,7 +25,9 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.cache.interceptor.SimpleCacheResolver;
@@ -128,9 +132,9 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
@Override
public void afterSingletonsInstantiated() {
// Make sure those are initialized on startup...
// Make sure that the cache resolver is initialized. An exception cache resolver is only
// required if the exceptionCacheName attribute is set on an operation
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized");
}
@@ -179,7 +183,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
@Override
protected CacheResolver getDefaultExceptionCacheResolver() {
if (this.exceptionCacheResolver == null) {
this.exceptionCacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager());
this.exceptionCacheResolver = new LazyCacheResolver();
}
return this.exceptionCacheResolver;
}
@@ -189,4 +193,27 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
return this.adaptedKeyGenerator;
}
/**
* Only resolve the default exception cache resolver when an exception needs to be handled.
* <p>A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. If only
* the latter is specified, it is not possible to extract a default exception {@code CacheResolver}
* from a custom {@code CacheResolver} implementation so we have to fallback on the {@code CacheManager}.
* <p>This gives this weird situation of a perfectly valid configuration that breaks all the sudden
* because the JCache support is enabled. To avoid this we resolve the default exception {@code CacheResolver}
* as late as possible to avoid such hard requirement in other cases.
*/
class LazyCacheResolver implements CacheResolver {
private CacheResolver cacheResolver;
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
if (this.cacheResolver == null) {
this.cacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager());
}
return this.cacheResolver.resolveCaches(context);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,21 +28,21 @@ import org.springframework.cache.interceptor.CacheResolver;
* <p>A cache operation can be statically cached as it does not contain
* any runtime operation of a specific cache invocation.
*
* @param <A> the type of the JSR-107 annotation
* @author Stephane Nicoll
* @since 4.1
* @param <A> the type of the JSR-107 annotation
*/
public interface JCacheOperation<A extends Annotation> extends BasicOperation, CacheMethodDetails<A> {
/**
* Return the {@link CacheResolver} instance to use to resolve the cache to
* use for this operation.
* Return the {@link CacheResolver} instance to use to resolve the cache
* to use for this operation.
*/
CacheResolver getCacheResolver();
/**
* Return the {@link CacheInvocationParameter} instances based on the specified
* method arguments.
* Return the {@link CacheInvocationParameter} instances based on the
* specified method arguments.
* <p>The method arguments must match the signature of the related method invocation
* @param values the parameters value for a particular invocation
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,9 +30,12 @@ import org.springframework.cache.transaction.AbstractTransactionSupportingCacheM
public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests<EhCacheCacheManager> {
private CacheManager nativeCacheManager;
private EhCacheCacheManager cacheManager;
private EhCacheCacheManager transactionalCacheManager;
@Before
public void setup() {
nativeCacheManager = new CacheManager(new Configuration().name("EhCacheCacheManagerTests")
@@ -58,7 +61,8 @@ public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCache
protected EhCacheCacheManager getCacheManager(boolean transactionAware) {
if (transactionAware) {
return transactionalCacheManager;
} else {
}
else {
return cacheManager;
}
}
@@ -77,4 +81,5 @@ public class EhCacheCacheManagerTests extends AbstractTransactionSupportingCache
protected void removeNativeCache(String cacheName) {
nativeCacheManager.removeCache(cacheName);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,7 +18,10 @@ package org.springframework.cache.guava;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
@@ -32,6 +35,9 @@ import static org.mockito.Mockito.*;
*/
public class GuavaCacheManagerTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void testDynamicMode() {
CacheManager cm = new GuavaCacheManager();
@@ -150,6 +156,28 @@ public class GuavaCacheManagerTests {
assertNotNull(cm.getCache("someCache"));
}
@Test
public void cacheLoaderUseLoadingCache() {
GuavaCacheManager cm = new GuavaCacheManager("c1");
cm.setCacheLoader(new CacheLoader<Object, Object>() {
@Override
public Object load(Object key) throws Exception {
if ("ping".equals(key)) {
return "pong";
}
throw new IllegalArgumentException("I only know ping");
}
});
Cache cache1 = cm.getCache("c1");
Cache.ValueWrapper value = cache1.get("ping");
assertNotNull(value);
assertEquals("pong", value.get());
thrown.expect(UncheckedExecutionException.class);
thrown.expectMessage("I only know ping");
assertNull(cache1.get("foo"));
}
@SuppressWarnings("unchecked")
private CacheLoader<Object, Object> mockCacheLoader() {
return mock(CacheLoader.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -33,9 +33,12 @@ import static org.mockito.BDDMockito.*;
public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheManagerTests<JCacheCacheManager> {
private CacheManagerMock cacheManagerMock;
private JCacheCacheManager cacheManager;
private JCacheCacheManager transactionalCacheManager;
@Before
public void setupOnce() {
cacheManagerMock = new CacheManagerMock();
@@ -55,7 +58,8 @@ public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheM
protected JCacheCacheManager getCacheManager(boolean transactionAware) {
if (transactionAware) {
return transactionalCacheManager;
} else {
}
else {
return cacheManager;
}
}
@@ -75,9 +79,11 @@ public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheM
cacheManagerMock.removeCache(cacheName);
}
private static class CacheManagerMock {
private final List<String> cacheNames;
private final CacheManager cacheManager;
private CacheManagerMock() {
@@ -103,4 +109,5 @@ public class JCacheCacheManagerTests extends AbstractTransactionSupportingCacheM
given(cacheManager.getCache(name)).willReturn(null);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,12 +18,15 @@ package org.springframework.cache.jcache.config;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.config.SomeKeyGenerator;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
@@ -35,7 +38,6 @@ import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.cache.jcache.interceptor.AnnotatedJCacheableService;
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
import org.springframework.cache.jcache.interceptor.JCacheInterceptor;
import org.springframework.cache.jcache.interceptor.SimpleExceptionCacheResolver;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.ApplicationContext;
@@ -51,15 +53,20 @@ import static org.junit.Assert.*;
*/
public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Override
protected ApplicationContext getApplicationContext() {
return new AnnotationConfigApplicationContext(EnableCachingConfig.class);
}
@Test
public void fullCachingConfig() throws Exception {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(FullCachingConfig.class);
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
assertSame(context.getBean(KeyGenerator.class), cos.getKeyGenerator());
assertSame(context.getBean("cacheResolver", CacheResolver.class),
@@ -80,10 +87,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
assertEquals(SimpleCacheResolver.class, cos.getCacheResolver().getClass());
assertSame(context.getBean(CacheManager.class),
((SimpleCacheResolver) cos.getCacheResolver()).getCacheManager());
assertNotNull(cos.getExceptionCacheResolver());
assertEquals(SimpleExceptionCacheResolver.class, cos.getExceptionCacheResolver().getClass());
assertSame(context.getBean(CacheManager.class),
((SimpleExceptionCacheResolver) cos.getExceptionCacheResolver()).getCacheManager());
assertNull(cos.getExceptionCacheResolver());
context.close();
}
@@ -99,6 +103,27 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
context.close();
}
@Test
public void exceptionCacheResolverLazilyRequired() {
ConfigurableApplicationContext context =
new AnnotationConfigApplicationContext(NoExceptionCacheResolverConfig.class);
try {
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
assertSame(context.getBean("cacheResolver"), cos.getCacheResolver());
JCacheableService<?> service = context.getBean(JCacheableService.class);
service.cache("id");
// This call requires the cache manager to be set
thrown.expect(IllegalStateException.class);
service.cacheWithException("test", false);
}
finally {
context.close();
}
}
@Configuration
@EnableCaching
@@ -126,11 +151,11 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
}
}
@Configuration
@EnableCaching
public static class FullCachingConfig implements JCacheConfigurer {
@Override
@Bean
public CacheManager cacheManager() {
@@ -162,6 +187,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
}
}
@Configuration
@EnableCaching
public static class EmptyConfigSupportConfig extends JCacheConfigurerSupport {
@@ -171,6 +197,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
}
}
@Configuration
@EnableCaching
static class FullCachingConfigSupport extends JCacheConfigurerSupport {
@@ -200,4 +227,21 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
}
}
@Configuration
@EnableCaching
static class NoExceptionCacheResolverConfig extends JCacheConfigurerSupport {
@Override
@Bean
public CacheResolver cacheResolver() {
return new NamedCacheResolver(new ConcurrentMapCacheManager(), "default");
}
@Bean
public JCacheableService<?> cacheableService() {
return new AnnotatedJCacheableService(new ConcurrentMapCache("default"));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,11 +42,10 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
/**
* Returns the {@link CacheManager} to use.
*
* @param transactionAware if the requested cache manager should be aware
* of the transaction
* @return the cache manager to use
* @see org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware(boolean)
* @see org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager#setTransactionAware
*/
protected abstract T getCacheManager(boolean transactionAware);
@@ -65,6 +64,7 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
*/
protected abstract void removeNativeCache(String cacheName);
@Test
public void getOnExistingCache() {
assertThat(getCacheManager(false).getCache(CACHE_NAME), is(instanceOf(getCacheType())));
@@ -77,10 +77,10 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
addNativeCache(cacheName);
assertFalse(cacheManager.getCacheNames().contains(cacheName));
try {
assertThat(cacheManager.getCache(cacheName),
is(instanceOf(getCacheType())));
assertThat(cacheManager.getCache(cacheName), is(instanceOf(getCacheType())));
assertTrue(cacheManager.getCacheNames().contains(cacheName));
} finally {
}
finally {
removeNativeCache(cacheName);
}
}
@@ -109,8 +109,10 @@ public abstract class AbstractTransactionSupportingCacheManagerTests<T extends C
assertThat(cacheManager.getCache(cacheName),
is(instanceOf(TransactionAwareCacheDecorator.class)));
assertTrue(cacheManager.getCacheNames().contains(cacheName));
} finally {
}
finally {
removeNativeCache(cacheName);
}
}
}
@@ -381,17 +381,20 @@ public class QuartzSupportTests {
/**
* SPR-6038: detect HSQL and stop illegal locks being taken.
* TODO: Against Quartz 2.2, this test's job doesn't actually execute anymore...
*/
@Test
public void schedulerWithHsqlDataSource() throws Exception {
Assume.group(TestGroup.PERFORMANCE);
// Assume.group(TestGroup.PERFORMANCE);
DummyJob.param = 0;
DummyJob.count = 0;
ClassPathXmlApplicationContext ctx = context("databasePersistence.xml");
JdbcTemplate jdbcTemplate = new JdbcTemplate(ctx.getBean(DataSource.class));
assertTrue("No triggers were persisted", jdbcTemplate.queryForList("SELECT * FROM qrtz_triggers").size()>0);
assertFalse("No triggers were persisted", jdbcTemplate.queryForList("SELECT * FROM qrtz_triggers").isEmpty());
/*
Thread.sleep(3000);
try {
assertTrue(DummyJob.count > 0);
@@ -399,6 +402,7 @@ public class QuartzSupportTests {
finally {
ctx.close();
}
*/
}
private ClassPathXmlApplicationContext context(String path) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,7 @@
package org.springframework.cache;
/**
* Interface that defines the common cache operations.
* Interface that defines common cache operations.
*
* <b>Note:</b> Due to the generic use of caching, it is recommended that
* implementations allow storage of <tt>null</tt> values (for example to
@@ -68,8 +68,8 @@ public interface Cache {
* the cache contains no mapping for this key
* @throws IllegalStateException if a cache entry has been found
* but failed to match the specified type
* @see #get(Object)
* @since 4.0
* @see #get(Object)
*/
<T> T get(Object key, Class<T> type);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.cache.annotation;
import java.util.Collection;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
@@ -28,12 +27,11 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Abstract base {@code @Configuration} class providing common structure for enabling
* Spring's annotation-driven cache management capability.
* Abstract base {@code @Configuration} class providing common structure
* for enabling Spring's annotation-driven cache management capability.
*
* @author Chris Beams
* @author Stephane Nicoll
@@ -41,7 +39,7 @@ import org.springframework.util.CollectionUtils;
* @see EnableCaching
*/
@Configuration
public abstract class AbstractCachingConfiguration<C extends CachingConfigurer> implements ImportAware {
public abstract class AbstractCachingConfiguration implements ImportAware {
protected AnnotationAttributes enableCaching;
@@ -53,17 +51,19 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
protected CacheErrorHandler errorHandler;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableCaching = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableCaching.class.getName(), false));
Assert.notNull(this.enableCaching,
"@EnableCaching is not present on importing class " +
importMetadata.getClassName());
if (this.enableCaching == null) {
throw new IllegalArgumentException(
"@EnableCaching is not present on importing class " + importMetadata.getClassName());
}
}
@Autowired(required = false)
void setConfigurers(Collection<C> configurers) {
void setConfigurers(Collection<CachingConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
@@ -73,14 +73,14 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
"Refactor the configuration such that CachingConfigurer is " +
"implemented only once or not at all.");
}
C configurer = configurers.iterator().next();
CachingConfigurer configurer = configurers.iterator().next();
useCachingConfigurer(configurer);
}
/**
* Extract the configuration from the nominated {@link CachingConfigurer}.
*/
protected void useCachingConfigurer(C config) {
protected void useCachingConfigurer(CachingConfigurer config) {
this.cacheManager = config.cacheManager();
this.cacheResolver = config.cacheResolver();
this.keyGenerator = config.keyGenerator();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
@@ -162,13 +162,12 @@ public @interface EnableCaching {
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}. <strong>
* Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.
*
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with
* {@code @Cacheable}. For example, other beans marked with Spring's
* {@code @Transactional} annotation will be upgraded to subclass proxying at the same
* time. This approach has no negative impact in practice unless one is explicitly
* expecting one type of proxy vs another, e.g. in tests.
* Spring-managed beans requiring proxying, not just those marked with {@code @Cacheable}.
* For example, other beans marked with Spring's {@code @Transactional} annotation will
* be upgraded to subclass proxying at the same time. This approach has no negative
* impact in practice unless one is explicitly expecting one type of proxy vs another,
* e.g. in tests.
*/
boolean proxyTargetClass() default false;
@@ -185,4 +184,5 @@ public @interface EnableCaching {
* The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -35,7 +35,7 @@ import org.springframework.context.annotation.Role;
* @see CachingConfigurationSelector
*/
@Configuration
public class ProxyCachingConfiguration extends AbstractCachingConfiguration<CachingConfigurer> {
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -235,11 +235,6 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
"default cache resolver if none is set. If a cache resolver is set, the cache manager" +
"won't be used.");
}
if (operation.getCacheNames().isEmpty()) {
throw new IllegalStateException("No cache names could be detected on '" +
ae.toString() + "'. Make sure to set the value parameter on the annotation or " +
"declare a @CacheConfig at the class-level with the default cache name(s) to use.");
}
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,8 +25,8 @@ import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;
/**
* Simple {@link Cache} implementation based on the core JDK
* {@code java.util.concurrent} package.
* Simple {@link org.springframework.cache.Cache} implementation based on the
* core JDK {@code java.util.concurrent} package.
*
* <p>Useful for testing or simple caching scenarios, typically in combination
* with {@link org.springframework.cache.support.SimpleCacheManager} or
@@ -124,7 +124,7 @@ public class ConcurrentMapCache implements Cache {
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
Object existing = this.store.putIfAbsent(key, value);
Object existing = this.store.putIfAbsent(key, toStoreValue(value));
return toWrapper(existing);
}
@@ -169,8 +169,13 @@ public class ConcurrentMapCache implements Cache {
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
}
@SuppressWarnings("serial")
private static class NullHolder implements Serializable {
private Object readResolve() {
return NULL_HOLDER;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
*/
private final static Collection<CacheOperation> NULL_CACHING_ATTRIBUTE = Collections.emptyList();
/**
* Logger available to subclasses.
* <p>As this base class is not marked Serializable, the logger will be recreated
@@ -71,9 +72,10 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
* <p>As this base class is not marked Serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is Serializable.
*/
final Map<Object, Collection<CacheOperation>> attributeCache =
private final Map<Object, Collection<CacheOperation>> attributeCache =
new ConcurrentHashMap<Object, Collection<CacheOperation>>(1024);
/**
* Determine the caching attribute for this method invocation.
* <p>Defaults to the class's caching attribute if no method attribute is found.
@@ -84,30 +86,23 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
*/
@Override
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
if (cached != null) {
if (cached == NULL_CACHING_ATTRIBUTE) {
return null;
}
// Value will either be canonical value indicating there is no caching attribute,
// or an actual caching attribute.
return cached;
return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
}
else {
// We need to work it out.
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
// Put it in the cache.
if (cacheOps == null) {
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
else {
if (cacheOps != null) {
if (logger.isDebugEnabled()) {
logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
}
this.attributeCache.put(cacheKey, cacheOps);
}
else {
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
return cacheOps;
}
}
@@ -186,4 +181,5 @@ public abstract class AbstractFallbackCacheOperationSource implements CacheOpera
protected boolean allowPublicMethodsOnly() {
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,7 +23,7 @@ import org.springframework.cache.Cache;
/**
* Determine the {@link Cache} instance(s) to use for an intercepted method invocation.
*
* <p>Implementations MUST be thread-safe.
* <p>Implementations must be thread-safe.
*
* @author Stephane Nicoll
* @since 4.1
@@ -32,9 +32,8 @@ public interface CacheResolver {
/**
* Return the cache(s) to use for the specified invocation.
*
* @param context the context of the particular invocation
* @return the cache(s) to use (never null)
* @return the cache(s) to use (never {@code null})
*/
Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -40,7 +40,7 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>(16);
private Set<String> cacheNames = new LinkedHashSet<String>(16);
private final Set<String> cacheNames = new LinkedHashSet<String>(16);
// Early cache initialization on startup
@@ -96,6 +96,16 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
this.cacheNames.add(cache.getName());
}
/**
* Check for a registered cache of the given name.
* In contrast to {@link #getCache(String)}, this method does not trigger
* the lazy creation of missing caches via {@link #getMissingCache(String)}.
* @param name the cache identifier (must not be {@code null})
* @return the associated Cache instance, or {@code null} if none found
* @since 4.1
* @see #getCache(String)
* @see #getMissingCache(String)
*/
protected final Cache lookupCache(String name) {
return this.cacheMap.get(name);
}
@@ -120,6 +130,7 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
* @param name the name of the cache to retrieve
* @return the missing cache or {@code null} if no such cache exists or could be
* created
* @since 4.1
* @see #getCache(String)
*/
protected Cache getMissingCache(String name) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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,13 +17,15 @@
package org.springframework.context;
/**
* Interface defining methods for start/stop lifecycle control.
* A common interface defining methods for start/stop lifecycle control.
* The typical use case for this is to control asynchronous processing.
* <b>NOTE: This interface does not imply specific auto-startup semantics.
* Consider implementing {@link SmartLifecycle} for that purpose.</b>
*
* <p>Can be implemented by both components (typically a Spring bean defined in
* a Spring {@link org.springframework.beans.factory.BeanFactory}) and containers
* (typically a Spring {@link ApplicationContext}). Containers will propagate
* start/stop signals to all components that apply.
* <p>Can be implemented by both components (typically a Spring bean defined in a
* Spring context) and containers (typically a Spring {@link ApplicationContext}
* itself). Containers will propagate start/stop signals to all components that
* apply within each container, e.g. for a stop/restart scenario at runtime.
*
* <p>Can be used for direct invocations or for management operations via JMX.
* In the latter case, the {@link org.springframework.jmx.export.MBeanExporter}
@@ -32,10 +34,10 @@ package org.springframework.context;
* restricting the visibility of activity-controlled components to the Lifecycle
* interface.
*
* <p>Note that the Lifecycle interface is only supported on <b>top-level singleton beans</b>.
* On any other component, the Lifecycle interface will remain undetected and hence ignored.
* Also, note that the extended {@link SmartLifecycle} interface provides more sophisticated
* integration with the container's startup and shutdown phases.
* <p>Note that the Lifecycle interface is only supported on <b>top-level singleton
* beans</b>. On any other component, the Lifecycle interface will remain undetected
* and hence ignored. Also, note that the extended {@link SmartLifecycle} interface
* provides integration with the application context's startup and shutdown phases.
*
* @author Juergen Hoeller
* @since 2.0
@@ -51,6 +53,7 @@ public interface Lifecycle {
* Should not throw an exception if the component is already running.
* <p>In the case of a container, this will propagate the start signal
* to all components that apply.
* @see SmartLifecycle#isAutoStartup()
*/
void start();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2015 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,8 +17,8 @@
package org.springframework.context;
/**
* An extension of the {@link Lifecycle} interface for those objects that require to be
* started upon ApplicationContext refresh and/or shutdown in a particular order.
* An extension of the {@link Lifecycle} interface for those objects that require to
* be started upon ApplicationContext refresh and/or shutdown in a particular order.
* The {@link #isAutoStartup()} return value indicates whether this object should
* be started at the time of a context refresh. The callback-accepting
* {@link #stop(Runnable)} method is useful for objects that have an asynchronous
@@ -55,26 +55,37 @@ package org.springframework.context;
*
* @author Mark Fisher
* @since 3.0
* @see LifecycleProcessor
* @see ConfigurableApplicationContext
*/
public interface SmartLifecycle extends Lifecycle, Phased {
/**
* Return whether this Lifecycle component should be started automatically
* by the container when the ApplicationContext is refreshed. A value of
* "false" indicates that the component is intended to be started manually.
* Returns {@code true} if this {@code Lifecycle} component should get
* started automatically by the container at the time that the containing
* {@link ApplicationContext} gets refreshed.
* <p>A value of {@code false} indicates that the component is intended to
* be started through an explicit {@link #start()} call instead, analogous
* to a plain {@link Lifecycle} implementation.
* @see #start()
* @see #getPhase()
* @see LifecycleProcessor#onRefresh()
* @see ConfigurableApplicationContext#refresh()
*/
boolean isAutoStartup();
/**
* Indicates that a Lifecycle component must stop if it is currently running.
* <p>The provided callback is used by the {@link LifecycleProcessor} to support an
* ordered, and potentially concurrent, shutdown of all components having a
* <p>The provided callback is used by the {@link LifecycleProcessor} to support
* an ordered, and potentially concurrent, shutdown of all components having a
* common shutdown order value. The callback <b>must</b> be executed after
* the SmartLifecycle component does indeed stop.
* <p>The {@code LifecycleProcessor} will call <i>only</i> this variant of the
* the {@code SmartLifecycle} component does indeed stop.
* <p>The {@link LifecycleProcessor} will call <i>only</i> this variant of the
* {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for
* {@link SmartLifecycle} implementations unless explicitly delegated to within
* this method.
* {@code SmartLifecycle} implementations unless explicitly delegated to within
* the implementation of this method.
* @see #stop()
* @see #getPhase()
*/
void stop(Runnable callback);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
/*
* Copyright 2002-2015 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,9 +28,9 @@ import org.springframework.util.Assert;
* based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*}
* annotations).
*
* @param <A> Annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute}
* @author Chris Beams
* @since 3.1
* @param <A> annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute}
*/
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,10 +25,10 @@ import org.springframework.util.Assert;
/**
* A {@link ScopeMetadataResolver} implementation that by default checks for
* the presence of Spring's {@link Scope} annotation on the bean class.
* the presence of Spring's {@link Scope @Scope} annotation on the bean class.
*
* <p>The exact type of annotation that is checked for is configurable via the
* {@link #setScopeAnnotationType(Class)} property.
* <p>The exact type of annotation that is checked for is configurable via
* {@link #setScopeAnnotationType(Class)}.
*
* @author Mark Fisher
* @author Juergen Hoeller
@@ -43,7 +43,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* Construct a new {@code AnnotationScopeMetadataResolver}.
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
* @see ScopedProxyMode#NO
*/
@@ -52,8 +52,9 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
}
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* @param defaultProxyMode the desired scoped-proxy mode
* Construct a new {@code AnnotationScopeMetadataResolver} using the
* supplied default {@link ScopedProxyMode}.
* @param defaultProxyMode the default scoped-proxy mode
*/
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
Assert.notNull(defaultProxyMode, "'defaultProxyMode' must not be null");
@@ -63,7 +64,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
/**
* Set the type of annotation that is checked for by this
* {@link AnnotationScopeMetadataResolver}.
* {@code AnnotationScopeMetadataResolver}.
* @param scopeAnnotationType the target annotation type
*/
public void setScopeAnnotationType(Class<? extends Annotation> scopeAnnotationType) {
@@ -218,7 +218,7 @@ import org.springframework.stereotype.Component;
* {@code <bean>} definitions within Spring XML files. It is also possible to
* import Spring XML configuration files into {@code @Configuration} classes using
* the {@link ImportResource @ImportResource} annotation. Bean definitions imported from XML can be
* injected using {@code @Autowired} or {@code @Import}:
* injected using {@code @Autowired} or {@code @Inject}:
* <pre class="code">
* &#064;Configuration
* &#064;ImportResource("classpath:/com/acme/database-config.xml")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,6 +16,7 @@
package org.springframework.context.annotation;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -63,6 +64,8 @@ final class ConfigurationClass {
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
new LinkedHashMap<ImportBeanDefinitionRegistrar, AnnotationMetadata>();
final Set<String> skippedBeanMethods = new HashSet<String>();
/**
* Create a new {@link ConfigurationClass} with the given name.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -168,7 +168,7 @@ class ConfigurationClassBeanDefinitionReader {
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Registered bean definition for imported @Configuration class %s", configBeanName));
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
}
}
else {
@@ -182,33 +182,25 @@ class ConfigurationClassBeanDefinitionReader {
* with the BeanDefinitionRegistry based on its contents.
*/
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
if (this.conditionEvaluator.shouldSkip(beanMethod.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
return;
}
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(metadata.getMethodName());
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(metadata.getMethodName());
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
// Consider name and any aliases
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
String beanName = (names.size() > 0 ? names.remove(0) : beanMethod.getMetadata().getMethodName());
String beanName = (names.size() > 0 ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
@@ -218,6 +210,23 @@ class ConfigurationClassBeanDefinitionReader {
return;
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -303,7 +303,7 @@ class ConfigurationClassEnhancer {
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details",
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -73,6 +73,7 @@ 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.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
@@ -133,7 +134,7 @@ class ConfigurationClassParser {
private final ImportStack importStack = new ImportStack();
private final List<DeferredImportSelectorHolder> deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
private List<DeferredImportSelectorHolder> deferredImportSelectors;
/**
@@ -156,6 +157,8 @@ class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
@@ -177,6 +180,7 @@ class ConfigurationClassParser {
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
@@ -269,7 +273,7 @@ class ConfigurationClassParser {
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true, false);
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
@@ -416,12 +420,15 @@ class ConfigurationClassParser {
}
private void processDeferredImportSelectors() {
Collections.sort(this.deferredImportSelectors, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : this.deferredImportSelectors) {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false, true);
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
@@ -431,18 +438,17 @@ class ConfigurationClassParser {
configClass.getMetadata().getClassName() + "]", ex);
}
}
this.deferredImportSelectors.clear();
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports, boolean deferred) throws IOException {
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
@@ -453,14 +459,14 @@ class ConfigurationClassParser {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
invokeAwareMethods(selector);
if (!deferred && selector instanceof DeferredImportSelector) {
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false, false);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
@@ -474,7 +480,7 @@ class ConfigurationClassParser {
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as a @Configuration class
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
@@ -615,7 +621,7 @@ class ConfigurationClassParser {
@Override
public AnnotationMetadata getImportingClassFor(String importedClass) {
List<AnnotationMetadata> list = this.imports.get(importedClass);
return (list == null || list.isEmpty() ? null : list.get(list.size() - 1));
return (!CollectionUtils.isEmpty(list) ? list.get(list.size() - 1) : null);
}
/**
@@ -629,7 +635,7 @@ class ConfigurationClassParser {
Comparator<ConfigurationClass> comparator = new Comparator<ConfigurationClass>() {
@Override
public int compare(ConfigurationClass first, ConfigurationClass second) {
return first.getMetadata().getClassName().equals(second.getMetadata().getClassName()) ? 0 : 1;
return (first.getMetadata().getClassName().equals(second.getMetadata().getClassName()) ? 0 : 1);
}
};
return (Collections.binarySearch(this, configClass, comparator) != -1);
@@ -642,11 +648,11 @@ class ConfigurationClassParser {
* <li>com.acme.Bar</li>
* <li>com.acme.Baz</li>
* </ul>
* return "ImportStack: [Foo->Bar->Baz]".
* return "[Foo->Bar->Baz]".
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder("ImportStack: [");
StringBuilder builder = new StringBuilder("[");
Iterator<ConfigurationClass> iterator = iterator();
while (iterator.hasNext()) {
builder.append(iterator.next().getSimpleName());
@@ -750,7 +756,16 @@ class ConfigurationClassParser {
String[] memberClassNames = sourceReader.getClassMetadata().getMemberClassNames();
List<SourceClass> members = new ArrayList<SourceClass>(memberClassNames.length);
for (String memberClassName : memberClassNames) {
members.add(asSourceClass(memberClassName));
try {
members.add(asSourceClass(memberClassName));
}
catch (IOException ex) {
// Let's skip it if it's not resolvable - we're just looking for candidates
if (logger.isDebugEnabled()) {
logger.debug("Failed to resolve member class [" + memberClassName +
"] - not considering it as a configuration class candidate");
}
}
}
return members;
}
@@ -829,12 +844,12 @@ class ConfigurationClassParser {
*/
private static class CircularImportProblem extends Problem {
public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> importStack, AnnotationMetadata metadata) {
public CircularImportProblem(ConfigurationClass attemptedImport, Stack<ConfigurationClass> importStack) {
super(String.format("A circular @Import has been detected: " +
"Illegal attempt by @Configuration class '%s' to import class '%s' as '%s' is " +
"already present in the current import stack [%s]", importStack.peek().getSimpleName(),
"already present in the current import stack %s", importStack.peek().getSimpleName(),
attemptedImport.getSimpleName(), attemptedImport.getSimpleName(), importStack),
new Location(importStack.peek().getResource(), metadata));
new Location(importStack.peek().getResource(), attemptedImport.getMetadata()));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -149,12 +149,24 @@ abstract class ConfigurationClassUtils {
if (metadata.isInterface()) {
return false;
}
// Any of the typical annotations found?
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
return metadata.hasAnnotatedMethods(Bean.class.getName());
// Finally, let's look for @Bean methods...
try {
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClass() + "]: " + ex);
}
return false;
}
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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,16 +30,16 @@ import java.lang.annotation.Target;
* one {@link Bean @Bean} method, as well as {@link ImportSelector} and
* {@link ImportBeanDefinitionRegistrar} implementations.
*
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes
* should be accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
* <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be
* accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired}
* injection. Either the bean itself can be autowired, or the configuration class instance
* declaring the bean can be autowired. The latter approach allows for explicit,
* IDE-friendly navigation between {@code @Configuration} class methods.
* declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly
* navigation between {@code @Configuration} class methods.
*
* <p>May be declared at the class level or as a meta-annotation.
*
* <p>If XML or other non-{@code @Configuration} bean definition resources need to be
* imported, use {@link ImportResource @ImportResource}
* imported, use the {@link ImportResource @ImportResource} annotation instead.
*
* @author Chris Beams
* @since 3.0
@@ -57,4 +57,5 @@ public @interface Import {
* {@link ImportBeanDefinitionRegistrar} classes to import.
*/
Class<?>[] value();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,9 +26,6 @@ import org.springframework.context.weaving.DefaultContextLoadTimeWeaver;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import static org.springframework.context.weaving.AspectJWeavingEnabler.*;
/**
* {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean.
@@ -47,7 +44,6 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
private AnnotationAttributes enableLTW;
@Autowired(required=false)
private LoadTimeWeavingConfigurer ltwConfigurer;
private ClassLoader beanClassLoader;
@@ -56,8 +52,15 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableLTW = AnnotationConfigUtils.attributesFor(importMetadata, EnableLoadTimeWeaving.class);
Assert.notNull(this.enableLTW,
"@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
if (this.enableLTW == null) {
throw new IllegalArgumentException(
"@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
}
}
@Autowired(required = false)
public void setLoadTimeWeavingConfigurer(LoadTimeWeavingConfigurer ltwConfigurer) {
this.ltwConfigurer = ltwConfigurer;
}
@Override
@@ -66,7 +69,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
}
@Bean(name=ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
@Bean(name = ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public LoadTimeWeaver loadTimeWeaver() {
LoadTimeWeaver loadTimeWeaver = null;
@@ -87,7 +90,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
// AJ weaving is disabled -> do nothing
break;
case AUTODETECT:
if (this.beanClassLoader.getResource(ASPECTJ_AOP_XML_RESOURCE) == null) {
if (this.beanClassLoader.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) == null) {
// No aop.xml present on the classpath -> treat as 'disabled'
break;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter";
private AnnotationAttributes attributes;
private AnnotationAttributes enableMBeanExport;
private Environment environment;
@@ -61,8 +61,8 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
Map<String, Object> map = importMetadata.getAnnotationAttributes(EnableMBeanExport.class.getName());
this.attributes = AnnotationAttributes.fromMap(map);
if (this.attributes == null) {
this.enableMBeanExport = AnnotationAttributes.fromMap(map);
if (this.enableMBeanExport == null) {
throw new IllegalArgumentException(
"@EnableMBeanExport is not present on importing class " + importMetadata.getClassName());
}
@@ -90,7 +90,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
}
private void setupDomain(AnnotationMBeanExporter exporter) {
String defaultDomain = this.attributes.getString("defaultDomain");
String defaultDomain = this.enableMBeanExport.getString("defaultDomain");
if (defaultDomain != null && this.environment != null) {
defaultDomain = this.environment.resolvePlaceholders(defaultDomain);
}
@@ -100,7 +100,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
}
private void setupServer(AnnotationMBeanExporter exporter) {
String server = this.attributes.getString("server");
String server = this.enableMBeanExport.getString("server");
if (server != null && this.environment != null) {
server = this.environment.resolvePlaceholders(server);
}
@@ -116,7 +116,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
}
private void setupRegistrationPolicy(AnnotationMBeanExporter exporter) {
RegistrationPolicy registrationPolicy = this.attributes.getEnum("registration");
RegistrationPolicy registrationPolicy = this.enableMBeanExport.getEnum("registration");
exporter.setRegistrationPolicy(registrationPolicy);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2015 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,16 +28,16 @@ import org.springframework.beans.factory.config.BeanDefinition;
* Indicates the 'role' hint for a given bean.
*
* <p>May be used on any class directly or indirectly annotated with
* {@link org.springframework.stereotype.Component} or on methods annotated with
* {@link Bean}.
* {@link org.springframework.stereotype.Component} or on methods
* annotated with {@link Bean}.
*
* <p>If this annotation is not present on a Component or Bean definition, the
* default value of {@link BeanDefinition#ROLE_APPLICATION} will apply.
* <p>If this annotation is not present on a Component or Bean definition,
* the default value of {@link BeanDefinition#ROLE_APPLICATION} will apply.
*
* <p>If Role is present on a {@link Configuration @Configuration} class, this
* indicates the role of the configuration class bean definition and does not
* cascade to all @{@code Bean} methods defined within. This behavior is
* different than that of the @{@link Lazy} annotation, for example.
* <p>If Role is present on a {@link Configuration @Configuration} class,
* this indicates the role of the configuration class bean definition and
* does not cascade to all @{@code Bean} methods defined within. This behavior
* is different than that of the @{@link Lazy} annotation, for example.
*
* @author Chris Beams
* @since 3.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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,8 +37,8 @@ class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDe
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
super.doParse(element, builder);
builder.addPropertyValue("ignoreInvalidKeys",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2015 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.
@@ -34,8 +34,10 @@ import org.springframework.util.StringUtils;
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
private static final String SYSTEM_PROPERTIES_MODE_ATTRIB = "system-properties-mode";
private static final String SYSTEM_PROPERTIES_MODE_DEFAULT = "ENVIRONMENT";
@Override
protected Class<?> getBeanClass(Element element) {
// As of Spring 3.1, the default value of system-properties-mode has changed from
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.OrderComparator;
@@ -65,47 +66,8 @@ public abstract class AbstractApplicationEventMulticaster
private BeanFactory beanFactory;
private Object retrievalMutex = this.defaultRetriever;
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeAllListeners() {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListeners.clear();
this.defaultRetriever.applicationListenerBeans.clear();
this.retrieverCache.clear();
}
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
@@ -118,6 +80,9 @@ public abstract class AbstractApplicationEventMulticaster
if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) {
this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader();
}
if (beanFactory instanceof AbstractBeanFactory) {
this.retrievalMutex = ((AbstractBeanFactory) beanFactory).getSingletonMutex();
}
}
private BeanFactory getBeanFactory() {
@@ -129,13 +94,55 @@ public abstract class AbstractApplicationEventMulticaster
}
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListenerBean(String listenerBeanName) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeAllListeners() {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.clear();
this.defaultRetriever.applicationListenerBeans.clear();
this.retrieverCache.clear();
}
}
/**
* Return a Collection containing all ApplicationListeners.
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener<?>> getApplicationListeners() {
synchronized (this.defaultRetriever) {
synchronized (this.retrievalMutex) {
return this.defaultRetriever.getApplicationListeners();
}
}
@@ -163,13 +170,14 @@ public abstract class AbstractApplicationEventMulticaster
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.defaultRetriever) {
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(event, sourceType, retriever);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(event, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
@@ -193,7 +201,7 @@ public abstract class AbstractApplicationEventMulticaster
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -162,6 +162,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/** Parent context */
private ApplicationContext parent;
/** Environment used by this context */
private ConfigurableEnvironment environment;
/** BeanFactoryPostProcessors to apply on refresh */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
new ArrayList<BeanFactoryPostProcessor>();
@@ -194,10 +197,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
private ApplicationEventMulticaster applicationEventMulticaster;
/** Statically specified listeners */
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
/** Environment used by this context; initialized by {@link #createEnvironment()} */
private ConfigurableEnvironment environment;
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
/**
@@ -352,7 +352,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
* @return the internal LifecycleProcessor (never {@code null})
* @throws IllegalStateException if the context has not been initialized yet
*/
LifecycleProcessor getLifecycleProcessor() {
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
if (this.lifecycleProcessor == null) {
throw new IllegalStateException("LifecycleProcessor not initialized - " +
"call 'refresh' before invoking lifecycle methods via the context: " + this);
@@ -504,6 +504,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
*/
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
@@ -721,11 +722,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String lisName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
}
@@ -801,7 +803,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
this.shutdownHook = new Thread() {
@Override
public void run() {
doClose();
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -152,7 +152,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* Set the default charset to use for parsing resource bundle files.
* <p>Default is none, using the {@code java.util.ResourceBundle}
* default encoding: ISO-8859-1.
* and more flexibility in setting of an encoding per file.
* @since 3.1.3
*/
public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
@@ -167,6 +167,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* {@code java.util.ResourceBundle}. However, this is often not desirable
* in an application server environment, where the system Locale is not relevant
* to the application at all: Set this flag to "false" in such a scenario.
* @since 3.1.3
*/
public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
this.fallbackToSystemLocale = fallbackToSystemLocale;
@@ -188,6 +189,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* Consider {@link ReloadableResourceBundleMessageSource} in combination
* with resource bundle files in a non-classpath location.
* </ul>
* @since 3.1.3
*/
public void setCacheSeconds(int cacheSeconds) {
this.cacheMillis = (cacheSeconds * 1000);
@@ -304,7 +306,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* @param locale the Locale to look for
* @return the corresponding ResourceBundle
* @throws MissingResourceException if no matching bundle could be found
* @see java.util.ResourceBundle#getBundle(String, java.util.Locale, ClassLoader)
* @see java.util.ResourceBundle#getBundle(String, Locale, ClassLoader)
* @see #getBundleClassLoader()
*/
protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
@@ -394,6 +396,8 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
// Special handling of default encoding
if (format.equals("java.properties")) {
String bundleName = toBundleName(baseName, locale);
final String resourceName = toResourceName(bundleName, "properties");
@@ -441,6 +445,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
}
}
else {
// Delegate handling of "java.class" format to standard Control
return super.newBundle(baseName, locale, format, loader, reload);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,6 +16,7 @@
package org.springframework.format.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -28,19 +29,19 @@ import java.lang.annotation.Target;
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long},
* Joda-Time value types; and as of Spring 4 and JDK 8, to JSR-310 <code>java.time</code> types too.
*
* <p>For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
* <p>For style-based formatting, set the {@link #style} attribute to be the style pattern code.
* The first character of the code is the date style, and the second character is the time style.
* Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
* A date or time may be omitted by specifying the style character '-'.
*
* <p>For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format,
* <p>For ISO-based formatting, set the {@link #iso} attribute to be the desired {@link ISO} format,
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern()} attribute to be the
* DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
*
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
* (the one most convenient one for your formatting needs).
* When the pattern attribute is specified, it takes precedence over both the style and ISO attribute.
* When the iso attribute is specified, if takes precedence over the style attribute.
* When the {@link #iso} attribute is specified, if takes precedence over the style attribute.
* When no annotation attributes are specified, the default format applied is style-based
* with a style code of 'SS' (short date, short time).
*
@@ -49,8 +50,9 @@ import java.lang.annotation.Target;
* @since 3.0
* @see org.joda.time.format.DateTimeFormat
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface DateTimeFormat {
/**
@@ -80,23 +82,23 @@ public @interface DateTimeFormat {
/**
* Common ISO date time format patterns.
*/
public enum ISO {
enum ISO {
/**
* The most common ISO Date Format {@code yyyy-MM-dd},
* e.g. 2000-10-31.
* e.g. "2000-10-31".
*/
DATE,
/**
* The most common ISO Time Format {@code HH:mm:ss.SSSZ},
* e.g. 01:30:00.000-05:00.
* e.g. "01:30:00.000-05:00".
*/
TIME,
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
* e.g. 2000-10-31 01:30:00.000-05:00.
* e.g. "2000-10-31 01:30:00.000-05:00".
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,6 +16,7 @@
package org.springframework.format.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -23,23 +24,27 @@ import java.lang.annotation.Target;
/**
* Declares that a field should be formatted as a number.
* Supports formatting by style or custom pattern string.
*
* <p>Supports formatting by style or custom pattern string.
* Can be applied to any JDK {@code java.lang.Number} type.
*
* <p>For style-based formatting, set the {@link #style()} attribute to be the desired {@link Style}.
* For custom formatting, set the {@link #pattern()} attribute to be the number pattern, such as {@code #, ###.##}.
* <p>For style-based formatting, set the {@link #style} attribute to be the
* desired {@link Style}. For custom formatting, set the {@link #pattern}
* attribute to be the number pattern, such as {@code #, ###.##}.
*
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
* (the one most convenient one for your formatting needs). When the pattern attribute is specified,
* it takes precedence over the style attribute. When no annotation attributes are specified,
* <p>Each attribute is mutually exclusive, so only set one attribute per
* annotation instance (the one most convenient one for your formatting needs).
* When the {@link #pattern} attribute is specified, it takes precedence over
* the {@link #style} attribute. When no annotation attributes are specified,
* the default format applied is style-based with a style of {@link Style#NUMBER}.
*
* @author Keith Donald
* @since 3.0
* @see java.text.NumberFormat
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface NumberFormat {
/**
@@ -62,7 +67,7 @@ public @interface NumberFormat {
/**
* Common number format styles.
*/
public enum Style {
enum Style {
/**
* The general-purpose number format for the current locale.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -88,8 +88,8 @@ public class FormattingConversionService extends GenericConversionService
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void addFormatterForFieldAnnotation(AnnotationFormatterFactory annotationFormatterFactory) {
@SuppressWarnings("unchecked")
public void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory) {
Class<? extends Annotation> annotationType = (Class<? extends Annotation>)
GenericTypeResolver.resolveTypeArgument(annotationFormatterFactory.getClass(), AnnotationFormatterFactory.class);
if (annotationType == null) {
@@ -148,7 +148,7 @@ public class FormattingConversionService extends GenericConversionService
@Override
public String toString() {
return this.fieldType.getName() + " -> " + String.class.getName() + " : " + this.printer;
return (this.fieldType.getName() + " -> " + String.class.getName() + " : " + this.printer);
}
}
@@ -197,7 +197,7 @@ public class FormattingConversionService extends GenericConversionService
@Override
public String toString() {
return String.class.getName() + " -> " + this.fieldType.getName() + ": " + this.parser;
return (String.class.getName() + " -> " + this.fieldType.getName() + ": " + this.parser);
}
}
@@ -249,8 +249,8 @@ public class FormattingConversionService extends GenericConversionService
@Override
public String toString() {
return "@" + this.annotationType.getName() + " " + this.fieldType.getName() + " -> " +
String.class.getName() + ": " + this.annotationFormatterFactory;
return ("@" + this.annotationType.getName() + " " + this.fieldType.getName() + " -> " +
String.class.getName() + ": " + this.annotationFormatterFactory);
}
}
@@ -302,8 +302,8 @@ public class FormattingConversionService extends GenericConversionService
@Override
public String toString() {
return String.class.getName() + " -> @" + this.annotationType.getName() + " " +
this.fieldType.getName() + ": " + this.annotationFormatterFactory;
return (String.class.getName() + " -> @" + this.annotationType.getName() + " " +
this.fieldType.getName() + ": " + this.annotationFormatterFactory);
}
}
@@ -161,7 +161,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
private boolean exposeManagedResourceClassLoader = true;
/** A set of bean names that should be excluded from autodetection */
private Set<String> excludedBeans;
private Set<String> excludedBeans = new HashSet<String>();
/** The MBeanExporterListeners registered with this exporter. */
private MBeanExporterListener[] listeners;
@@ -314,7 +314,18 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
* Set the list of names for beans that should be excluded from autodetection.
*/
public void setExcludedBeans(String... excludedBeans) {
this.excludedBeans = (excludedBeans != null ? new HashSet<String>(Arrays.asList(excludedBeans)) : null);
this.excludedBeans.clear();
if (excludedBeans != null) {
this.excludedBeans.addAll(Arrays.asList(excludedBeans));
}
}
/**
* Add the name of bean that should be excluded from autodetection.
*/
public void addExcludedBean(String excludedBean) {
Assert.notNull(excludedBean, "ExcludedBean must not be null");
this.excludedBeans.add(excludedBean);
}
/**
@@ -922,10 +933,9 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
* Indicates whether or not a particular bean name is present in the excluded beans list.
*/
private boolean isExcluded(String beanName) {
return (this.excludedBeans != null &&
(this.excludedBeans.contains(beanName) ||
(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length())))));
return (this.excludedBeans.contains(beanName) ||
(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()))));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,7 +25,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
@@ -43,6 +42,7 @@ public abstract class AbstractAsyncConfiguration implements ImportAware {
protected AnnotationAttributes enableAsync;
protected Executor executor;
protected AsyncUncaughtExceptionHandler exceptionHandler;
@@ -50,14 +50,16 @@ public abstract class AbstractAsyncConfiguration implements ImportAware {
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableAsync = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
Assert.notNull(this.enableAsync,
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
if (this.enableAsync == null) {
throw new IllegalArgumentException(
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
}
}
/**
* Collect any {@link AsyncConfigurer} beans through autowiring.
*/
@Autowired(required=false)
@Autowired(required = false)
void setConfigurers(Collection<AsyncConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -138,11 +138,11 @@ import org.springframework.core.Ordered;
public @interface EnableAsync {
/**
* Indicate the 'async' annotation type to be detected at either class
* or method level. By default, both the {@link Async} annotation and
* the EJB 3.1 {@code javax.ejb.Asynchronous} annotation will be
* detected. <p>This setter property exists so that developers can provide
* their own (non-Spring-specific) annotation type to indicate that a method
* Indicate the 'async' annotation type to be detected at either class or
* method level. By default, both the {@link Async} annotation and the
* EJB 3.1 {@code javax.ejb.Asynchronous} annotation will be detected.
* <p>This setter property exists so that developers can provide their
* own (non-Spring-specific) annotation type to indicate that a method
* (or all methods of a given class) should be invoked asynchronously.
*/
Class<? extends Annotation> annotation() default Annotation.class;
@@ -151,7 +151,6 @@ public @interface EnableAsync {
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}. <strong>
* Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.
*
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with {@code @Async}.
* For example, other beans marked with Spring's {@code @Transactional} annotation
@@ -176,4 +175,5 @@ public @interface EnableAsync {
* existing proxies rather than double-proxy.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
@@ -44,7 +44,7 @@ public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
Class<? extends Annotation> customAsyncAnnotation = enableAsync.getClass("annotation");
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,10 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.TaskScheduler;
@@ -61,12 +64,12 @@ import org.springframework.util.StringValueResolver;
* to the "fixedRate", "fixedDelay", or "cron" expression provided via the annotation.
*
* <p>This post-processor is automatically registered by Spring's
* {@code <task:annotation-driven>} XML element, and also by the @{@link EnableScheduling}
* annotation.
* {@code <task:annotation-driven>} XML element, and also by the
* @{@link EnableScheduling} annotation.
*
* <p>Auto-detects any {@link SchedulingConfigurer} instances in the container,
* allowing for customization of the scheduler to be used or for fine-grained control
* over task registration (e.g. registration of {@link Trigger} tasks.
* <p>Autodetects any {@link SchedulingConfigurer} instances in the container,
* allowing for customization of the scheduler to be used or for fine-grained
* control over task registration (e.g. registration of {@link Trigger} tasks.
* See the @{@link EnableScheduling} javadocs for complete usage details.
*
* @author Mark Fisher
@@ -80,7 +83,8 @@ import org.springframework.util.StringValueResolver;
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
*/
public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered,
EmbeddedValueResolverAware, BeanFactoryAware, SmartInitializingSingleton, DisposableBean {
EmbeddedValueResolverAware, BeanFactoryAware, ApplicationContextAware,
SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
@@ -90,6 +94,8 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
private final Set<Class<?>> nonAnnotatedClasses =
@@ -126,10 +132,13 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
}
/**
* @deprecated as of Spring 4.1, in favor of {@link #setBeanFactory}
* Setting an {@link ApplicationContext} is optional: If set, registered
* tasks will be activated in the {@link ContextRefreshedEvent} phase;
* if not set, it will happen at {@link #afterSingletonsInstantiated} time.
*/
@Deprecated
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
if (this.beanFactory == null) {
this.beanFactory = applicationContext;
}
@@ -138,6 +147,23 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
@Override
public void afterSingletonsInstantiated() {
if (this.applicationContext == null) {
// Not running in an ApplicationContext -> register tasks early...
finishRegistration();
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.applicationContext) {
// Running in an ApplicationContext -> register tasks this late...
// giving other ContextRefreshedEvent listeners a chance to perform
// their work at the same time (e.g. Spring Batch's job registration).
finishRegistration();
}
}
private void finishRegistration() {
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
@@ -190,9 +216,9 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) {
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
if (!this.nonAnnotatedClasses.contains(targetClass)) {
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
Class<?> targetClass = AopUtils.getTargetClass(bean);
ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
@@ -204,7 +230,7 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
}
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(bean.getClass());
this.nonAnnotatedClasses.add(targetClass);
if (logger.isDebugEnabled()) {
logger.debug("No @Scheduled annotations found on bean class: " + bean.getClass());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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,13 +23,12 @@ import org.springframework.context.annotation.Role;
import org.springframework.scheduling.config.TaskManagementConfigUtils;
/**
* {@code @Configuration} class that registers a {@link
* ScheduledAnnotationBeanPostProcessor} bean capable of processing Spring's @{@link
* Scheduled} annotation.
* {@code @Configuration} class that registers a {@link ScheduledAnnotationBeanPostProcessor}
* bean capable of processing Spring's @{@link Scheduled} annotation.
*
* <p>This configuration class is automatically imported when using the @{@link
* EnableScheduling} annotation. See {@code @EnableScheduling} Javadoc for complete usage
* details.
* <p>This configuration class is automatically imported when using the
* @{@link EnableScheduling} annotation. See {@code @EnableScheduling}'s javadoc
* for complete usage details.
*
* @author Chris Beams
* @since 3.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@@ -32,11 +32,14 @@ import org.springframework.jndi.JndiTemplate;
* for JSR-236's "java:comp/DefaultManagedThreadFactory" in a Java EE 7 environment,
* falling back to the local {@link CustomizableThreadFactory} setup if not found.
*
* <p>This is a convenient way to use managed threads when running in a Java EE 7 environment,
* simply using regular local threads otherwise - without conditional setup (like profiles).
* <p>This is a convenient way to use managed threads when running in a Java EE 7
* environment, simply using regular local threads otherwise - without conditional
* setup (i.e. without profiles).
*
* <p>Note: This class is not strictly JSR-236 based; it can work with any regular
* {@link java.util.concurrent.ThreadFactory} that can be found in JNDI.
* {@link java.util.concurrent.ThreadFactory} that can be found in JNDI. Therefore,
* the default JNDI name "java:comp/DefaultManagedThreadFactory" can be customized
* through the {@link #setJndiName "jndiName"} bean property.
*
* @author Juergen Hoeller
* @since 4.0
@@ -50,7 +53,7 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory
private String jndiName = "java:comp/DefaultManagedThreadFactory";
private ThreadFactory threadFactory = this;
private ThreadFactory threadFactory;
/**
@@ -98,12 +101,10 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory
}
catch (NamingException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to find [java:comp/DefaultManagedThreadFactory] in JNDI", ex);
}
if (logger.isInfoEnabled()) {
logger.info("Could not find default managed thread factory in JNDI - " +
"proceeding with default local thread factory");
logger.debug("Failed to retrieve [" + this.jndiName + "] from JNDI", ex);
}
logger.info("Could not find default managed thread factory in JNDI - " +
"proceeding with default local thread factory");
}
}
}
@@ -111,7 +112,12 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory
@Override
public Thread newThread(Runnable runnable) {
return this.threadFactory.newThread(runnable);
if (this.threadFactory != null) {
return this.threadFactory.newThread(runnable);
}
else {
return super.newThread(runnable);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,8 @@ import java.util.TimeZone;
import org.springframework.util.StringUtils;
/**
* Date sequence generator for a <a href="http://www.manpagez.com/man/5/crontab/">Crontab pattern</a>,
* Date sequence generator for a
* <a href="http://www.manpagez.com/man/5/crontab/">Crontab pattern</a>,
* allowing clients to specify a pattern that the sequence matches.
*
* <p>The pattern is a list of six single space-separated fields: representing
@@ -53,22 +54,22 @@ import org.springframework.util.StringUtils;
*/
public class CronSequenceGenerator {
private final BitSet seconds = new BitSet(60);
private final BitSet minutes = new BitSet(60);
private final BitSet hours = new BitSet(24);
private final BitSet daysOfWeek = new BitSet(7);
private final BitSet daysOfMonth = new BitSet(31);
private final BitSet months = new BitSet(12);
private final String expression;
private final TimeZone timeZone;
private final BitSet months = new BitSet(12);
private final BitSet daysOfMonth = new BitSet(31);
private final BitSet daysOfWeek = new BitSet(7);
private final BitSet hours = new BitSet(24);
private final BitSet minutes = new BitSet(60);
private final BitSet seconds = new BitSet(60);
/**
* Construct a {@link CronSequenceGenerator} from the pattern provided,
@@ -95,6 +96,14 @@ public class CronSequenceGenerator {
}
/**
* Return the cron pattern that this sequence generator has been built for.
*/
String getExpression() {
return this.expression;
}
/**
* Get the next {@link Date} in the sequence matching the Cron pattern and
* after the value provided. The return value will have a whole number of
@@ -271,9 +280,9 @@ public class CronSequenceGenerator {
}
/**
* Replace the values in the commaSeparatedList (case insensitive) with
* their index in the list.
* @return a new string with the values from the list replaced
* Replace the values in the comma-separated list (case insensitive)
* with their index in the list.
* @return a new String with the values from the list replaced
*/
private String replaceOrdinals(String value, String commaSeparatedList) {
String[] list = StringUtils.commaDelimitedListToStringArray(commaSeparatedList);
@@ -332,6 +341,10 @@ public class CronSequenceGenerator {
range[1] = max - 1;
}
int delta = Integer.valueOf(split[1]);
if (delta <= 0) {
throw new IllegalArgumentException("Incrementer delta must be 1 or higher: '" +
field + "' in expression \"" + this.expression + "\"");
}
for (int i = range[0]; i <= range[1]; i += delta) {
bits.set(i);
}
@@ -369,30 +382,30 @@ public class CronSequenceGenerator {
return result;
}
String getExpression() {
return this.expression;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CronSequenceGenerator)) {
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CronSequenceGenerator)) {
return false;
}
CronSequenceGenerator cron = (CronSequenceGenerator) obj;
return cron.months.equals(this.months) && cron.daysOfMonth.equals(this.daysOfMonth)
&& cron.daysOfWeek.equals(this.daysOfWeek) && cron.hours.equals(this.hours)
&& cron.minutes.equals(this.minutes) && cron.seconds.equals(this.seconds);
CronSequenceGenerator otherCron = (CronSequenceGenerator) other;
return (this.months.equals(otherCron.months) && this.daysOfMonth.equals(otherCron.daysOfMonth) &&
this.daysOfWeek.equals(otherCron.daysOfWeek) && this.hours.equals(otherCron.hours) &&
this.minutes.equals(otherCron.minutes) && this.seconds.equals(otherCron.seconds));
}
@Override
public int hashCode() {
return 37 + 17 * this.months.hashCode() + 29 * this.daysOfMonth.hashCode() + 37 * this.daysOfWeek.hashCode()
+ 41 * this.hours.hashCode() + 53 * this.minutes.hashCode() + 61 * this.seconds.hashCode();
return (17 * this.months.hashCode() + 29 * this.daysOfMonth.hashCode() + 37 * this.daysOfWeek.hashCode() +
41 * this.hours.hashCode() + 53 * this.minutes.hashCode() + 61 * this.seconds.hashCode());
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + this.expression;
return (getClass().getSimpleName() + ": " + this.expression);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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,21 +37,29 @@ public class CronTrigger implements Trigger {
/**
* Build a {@link CronTrigger} from the pattern provided in the default time zone.
* @param cronExpression a space-separated list of time fields,
* following cron expression conventions
* @param expression a space-separated list of time fields, following cron
* expression conventions
*/
public CronTrigger(String cronExpression) {
this.sequenceGenerator = new CronSequenceGenerator(cronExpression);
public CronTrigger(String expression) {
this.sequenceGenerator = new CronSequenceGenerator(expression);
}
/**
* Build a {@link CronTrigger} from the pattern provided.
* @param cronExpression a space-separated list of time fields,
* following cron expression conventions
* Build a {@link CronTrigger} from the pattern provided in the given time zone.
* @param expression a space-separated list of time fields, following cron
* expression conventions
* @param timeZone a time zone in which the trigger times will be generated
*/
public CronTrigger(String cronExpression, TimeZone timeZone) {
this.sequenceGenerator = new CronSequenceGenerator(cronExpression, timeZone);
public CronTrigger(String expression, TimeZone timeZone) {
this.sequenceGenerator = new CronSequenceGenerator(expression, timeZone);
}
/**
* Return the cron pattern that this trigger has been built with.
*/
public String getExpression() {
return this.sequenceGenerator.getExpression();
}
@@ -79,14 +87,11 @@ public class CronTrigger implements Trigger {
return this.sequenceGenerator.next(date);
}
public String getExpression() {
return this.sequenceGenerator.getExpression();
}
@Override
public boolean equals(Object obj) {
return (this == obj || (obj instanceof CronTrigger &&
this.sequenceGenerator.equals(((CronTrigger) obj).sequenceGenerator)));
public boolean equals(Object other) {
return (this == other || (other instanceof CronTrigger &&
this.sequenceGenerator.equals(((CronTrigger) other).sequenceGenerator)));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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 interface ScriptEvaluator {
* Evaluate the given script with the given arguments.
* @param script the ScriptSource for the script to evaluate
* @param arguments the key-value pairs to expose to the script,
* typically as script variables. May be {@code null}.
* typically as script variables (may be {@code null} or empty)
* @return the return value of the script, if any
* @throws ScriptCompilationException if the evaluator failed to read,
* compile or evaluate the script

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