Compare commits

...

352 Commits

Author SHA1 Message Date
Sam Brannen 11fc10282d Merge branch 'spring-operator-polish-urls-build-4.1.x' into 4.1.x 2019-03-12 14:34:12 +01:00
Sam Brannen 91df01115d Manual URL Cleanup
Closes gh-22518
2019-03-12 14:33:52 +01:00
Spring Operator 412cd83c3a URL Cleanup
This commit updates URLs to prefer the https protocol. Redirects are not followed to avoid accidentally expanding intentionally shortened URLs (i.e. if using a URL shortener).

# HTTP URLs that Could Not Be Fixed
These URLs were unable to be fixed. Please review them to see if they can be manually resolved.

* http://aopalliance.sourceforge.net/doc/ (200) migrated to:
  http://aopalliance.sourceforge.net/doc/ ([https](https://aopalliance.sourceforge.net/doc/) result AnnotatedConnectException).

# Fixed URLs

## Fixed But Review Recommended
These URLs were fixed, but the https status was not OK. However, the https status was the same as the http request or http redirected to an https URL, so they were migrated. Your review is recommended.

* http://jira.codehaus.org/browse/JIBX-465 (UnknownHostException) migrated to:
  https://jira.codehaus.org/browse/JIBX-465 ([https](https://jira.codehaus.org/browse/JIBX-465) result UnknownHostException).
* http://quartz-scheduler.org/api/2.2.0/ (301) migrated to:
  https://www.quartz-scheduler.org/api/2.2.0/ ([https](https://quartz-scheduler.org/api/2.2.0/) result 404).

## Fixed Success
These URLs were fixed successfully.

* http://commons.apache.org/proper/commons-codec/apidocs/ migrated to:
  https://commons.apache.org/proper/commons-codec/apidocs/ ([https](https://commons.apache.org/proper/commons-codec/apidocs/) result 200).
* http://commons.apache.org/proper/commons-dbcp/apidocs/ migrated to:
  https://commons.apache.org/proper/commons-dbcp/apidocs/ ([https](https://commons.apache.org/proper/commons-dbcp/apidocs/) result 200).
* http://commons.apache.org/proper/commons-lang/javadocs/api-2.5/ migrated to:
  https://commons.apache.org/proper/commons-lang/javadocs/api-2.5/ ([https](https://commons.apache.org/proper/commons-lang/javadocs/api-2.5/) result 200).
* http://dist.springsource.com/snapshot/STS/nightly-distributions.html migrated to:
  https://dist.springsource.com/snapshot/STS/nightly-distributions.html ([https](https://dist.springsource.com/snapshot/STS/nightly-distributions.html) result 200).
* http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/ migrated to:
  https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/ ([https](https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/) result 200).
* http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/ migrated to:
  https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/ ([https](https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/) result 200).
* http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/ migrated to:
  https://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/ ([https](https://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/) result 200).
* http://docs.oracle.com/javaee/7/api/ migrated to:
  https://docs.oracle.com/javaee/7/api/ ([https](https://docs.oracle.com/javaee/7/api/) result 200).
* http://docs.oracle.com/javase/8/docs/api/ migrated to:
  https://docs.oracle.com/javase/8/docs/api/ ([https](https://docs.oracle.com/javase/8/docs/api/) result 200).
* http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/ migrated to:
  https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/ ([https](https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/) result 200).
* http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/ migrated to:
  https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/ ([https](https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/) result 200).
* http://issues.gradle.org/browse/GRADLE-1116 migrated to:
  https://issues.gradle.org/browse/GRADLE-1116 ([https](https://issues.gradle.org/browse/GRADLE-1116) result 200).
* http://portals.apache.org/pluto/portlet-2.0-apidocs/ migrated to:
  https://portals.apache.org/pluto/portlet-2.0-apidocs/ ([https](https://portals.apache.org/pluto/portlet-2.0-apidocs/) result 200).
* http://tiles.apache.org/framework/apidocs/ migrated to:
  https://tiles.apache.org/framework/apidocs/ ([https](https://tiles.apache.org/framework/apidocs/) result 200).
* http://tiles.apache.org/tiles-request/apidocs/ migrated to:
  https://tiles.apache.org/tiles-request/apidocs/ ([https](https://tiles.apache.org/tiles-request/apidocs/) result 200).
* http://www.apache.org/licenses/LICENSE-2.0.txt migrated to:
  https://www.apache.org/licenses/LICENSE-2.0.txt ([https](https://www.apache.org/licenses/LICENSE-2.0.txt) result 200).
* http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/ migrated to:
  https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/ ([https](https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/) result 200).
* http://ehcache.org/apidocs/ (301) migrated to:
  https://www.ehcache.org/apidocs/ ([https](https://ehcache.org/apidocs/) result 200).
* http://static.springframework.org/spring-framework/docs (301) migrated to:
  https://docs.spring.io/spring-framework/docs ([https](https://static.springframework.org/spring-framework/docs) result 301).
* http://download.eclipse.org/eclipse/downloads migrated to:
  https://download.eclipse.org/eclipse/downloads ([https](https://download.eclipse.org/eclipse/downloads) result 301).
* http://fasterxml.github.com/jackson-core/javadoc/2.3.0/ migrated to:
  https://fasterxml.github.com/jackson-core/javadoc/2.3.0/ ([https](https://fasterxml.github.com/jackson-core/javadoc/2.3.0/) result 301).
* http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/ migrated to:
  https://fasterxml.github.com/jackson-databind/javadoc/2.3.0/ ([https](https://fasterxml.github.com/jackson-databind/javadoc/2.3.0/) result 301).
* http://glassfish.java.net/nonav/docs/v3/api/ migrated to:
  https://glassfish.java.net/nonav/docs/v3/api/ ([https](https://glassfish.java.net/nonav/docs/v3/api/) result 301).
* http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/ migrated to:
  https://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/ ([https](https://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/) result 301).
* http://projects.spring.io/spring-framework migrated to:
  https://projects.spring.io/spring-framework ([https](https://projects.spring.io/spring-framework) result 301).
* http://springframework.org/schema migrated to:
  https://springframework.org/schema ([https](https://springframework.org/schema) result 301).
* http://spring.io/tools/sts/all migrated to:
  https://spring.io/tools/sts/all ([https](https://spring.io/tools/sts/all) result 302).
2019-03-05 21:56:12 -06:00
Rossen Stoyanchev c0fd92c131 Remove section on spring-framework-contrib group 2016-04-08 15:44:36 -04:00
Spring Buildmaster 94f17f3e4b Next Development Version 2015-12-17 00:51:54 -08:00
Juergen Hoeller 9652430f01 Polishing 2015-12-16 21:20:06 +01:00
Juergen Hoeller 581b2b0b88 Consistent static final logger declarations
(cherry picked from commit 753347e)
2015-12-16 21:19:54 +01:00
Juergen Hoeller 4fa4886e70 Consistent trace log messages and general polishing
(cherry picked from commit 5626384)
2015-12-16 17:38:08 +01:00
Brian Clozel 46016d090b Use LinkedHashmap to preserve insert order
In several places in the spring-webmvc module, URL patterns / objects
relationships are kept in `HashMap`s. When matching with actual URLs,
the algorithm uses a pattern comparator to sort the matching patterns
and select the most specific. But the underlying collection
implementation does not keep the original order which can lead to
inconsistencies.

This commit changes the underlying collection implementation to
`LinkedHashmap`s, in order to keep the insert order if the comparator
does not reorder entries.

Issue: SPR-13798
(cherry picked from commit 3be35c0)
2015-12-16 17:34:34 +01:00
Juergen Hoeller 241dfbf855 Polishing
(cherry picked from commit 9e03e0e)
2015-12-15 12:55:02 +01:00
Juergen Hoeller bc492b9251 Defensive error reporting when StandardAnnotationMetadata introspects declared methods
Issue: SPR-13791
(cherry picked from commit a36c0a5)
2015-12-14 15:57:45 +01:00
Juergen Hoeller 8c8380715d Polishing (backported from master) 2015-12-14 00:47:33 +01:00
Andy Clement b64d752906 Fix SpEL compilation of static method/property/field operations
Before this change the compilation of a method reference or property/field
access was not properly cleaning up the stack if compilation meant
calling a static method or accessing a static field. In these cases there
is no need for a target object on the stack and it should be removed if
present. For a simple expression it is harmless since the end result of
the expression is the thing on the top of the stack, but for nested
expressions if the inner expression suffered this issue, the outer
expression can find itself operating on the wrong element.

The particular issue covered the case of a static field access but this
fix (and associated tests) cover static method, property and field access.

Issue: SPR-13781
(cherry picked from commit a28fc76)
2015-12-14 00:41:39 +01:00
Juergen Hoeller 1d0c2f6f0e Polishing
(cherry picked from commit ca9a078)
2015-12-10 00:57:06 +01:00
Juergen Hoeller 4b27a6ddee SimpAnnotationMethodMessageHandler ignores empty marker annotations
Issue: SPR-13704
(cherry picked from commit f119962)
2015-12-10 00:55:52 +01:00
Juergen Hoeller 3403e8d843 Jdbc4SqlXmlHandler returns null as documented (instead of throwing NPE)
Issue: SPR-13782
(cherry picked from commit 78dad4c)
2015-12-09 16:19:27 +01:00
Juergen Hoeller d573bbc6b8 Polishing 2015-12-09 15:00:35 +01:00
Stephane Nicoll f7492348ba Polish cache javadoc
Issue: SPR-13746
(cherry picked from commit 34b596c)
2015-12-09 14:52:28 +01:00
Juergen Hoeller e4faaa3786 Reset BytesMessage after payload extraction
Issue: SPR-13769
(cherry picked from commit 8346eed)
2015-12-09 14:50:56 +01:00
Juergen Hoeller d04f785094 Introduced createMethodJmsListenerEndpoint template method
Issue: SPR-13774
(cherry picked from commit 9589749)
2015-12-09 14:50:32 +01:00
Juergen Hoeller e37b75b165 Upgrade to Tomcat 8.0.30 2015-12-07 21:35:00 +01:00
Juergen Hoeller f54aac1003 Polishing 2015-12-07 19:44:07 +01:00
Juergen Hoeller c2fed6e7f1 StatementCreatorUtils detects Microsoft SQL Server driver 4.0 as well
Issue: SPR-13772
(cherry picked from commit d2ad2c3)
2015-12-07 19:20:04 +01:00
Juergen Hoeller 242acda970 Javadoc fixes
Issue: SPR-13765
2015-12-07 19:19:33 +01:00
Juergen Hoeller 66c44524d7 AbstractRequestLoggingFilter unwraps request to find ContentCachingRequestWrapper
Issue: SPR-13764
(cherry picked from commit b1ef6ec)
2015-12-07 19:17:01 +01:00
Juergen Hoeller 0230c49a82 AnnotationConfigWebApplicationContext allows for custom AnnotatedBeanDefinitionReader/ClassPathBeanDefinitionScanner
Issue: SPR-9324
(cherry picked from commit 20beace)
2015-12-07 19:15:39 +01:00
Rossen Stoyanchev f7f801c501 Configure view controllers with ApplicationContext
Issue: SPR-13762
2015-12-04 13:21:38 -05:00
Juergen Hoeller 83c9ec43da Efficient and consistent setAllowedOrigins collection type
Issue: SPR-13761
(cherry picked from commit 3d1ae9c)
2015-12-04 18:51:02 +01:00
Juergen Hoeller d03d8cb456 WebSocket namespace consistently applies resolvable allowed-origins value
Issue: SPR-13760
(cherry picked from commit cd4ce87)
2015-12-04 17:05:20 +01:00
Juergen Hoeller 6963e27c7a ControllerAdviceBean accepts bean types without @ControllerAdvice annotation (as in 3.2)
Issue: SPR-13759
(cherry picked from commit d64ac32)
2015-12-04 17:03:28 +01:00
Juergen Hoeller 7a7877040f Polishing 2015-12-03 21:18:58 +01:00
Juergen Hoeller e38cea610c Polishing 2015-12-03 13:35:13 +01:00
Juergen Hoeller 57d980130e Avoid mismatch between cached top-level versus nested parameter type
Issue: SPR-13755
(cherry picked from commit c909789)
2015-12-03 13:35:06 +01:00
Rossen Stoyanchev ff8bbc93f3 lastSessionCheckTime updated after session check
Issue: SPR-13745
2015-12-02 15:29:23 -05:00
Juergen Hoeller 6f11d4f06c Backported fix for lower-case media type lookups
Issue: SPR-13747
2015-12-02 14:42:40 +01:00
Brian Clozel f53d01b00a Do not rewrite relative links with FixedVersionStrategy
Prior to this change, the resource handling FixedVersionStrategy would
be applied on all links that match the configured pattern. This is
problematic for relative links and can lead to rewritten links such as
"/fixedversion/../css/main.css" which breaks.

This commit prevents that Strategy from being applied to such links.
Of course, one should avoid to use that VersionStrategy with relative
links, but this change aims at not breaking existing links even if it
means not prefixing the version as expected.

Issue: SPR-13727
(cherry picked from commit c226753)
2015-12-02 14:29:07 +01:00
Juergen Hoeller b3eefa2ae0 Documented units for send-time limit and buffer-size limit
Issue: SPR-13753
(cherry picked from commit 747863d)
2015-12-02 14:09:29 +01:00
Juergen Hoeller 5ac42bf9f8 Fixed formatting in AOP documentation
Issue: SPR-13750
2015-12-02 14:08:16 +01:00
Juergen Hoeller 79ded1ca72 MockHttpServletResponse.setIntHeader supports 'Content-Length' header as well
Issue: SPR-13752
(cherry picked from commit a4f5c46)
2015-12-02 14:07:15 +01:00
Juergen Hoeller fad0c9589d Latest applicable dependency updates (JOpt Simple 4.9, C3P0 0.9.5.1, H2 1.4.190, HSQLDB 2.3.3) 2015-12-01 21:03:55 +01:00
Juergen Hoeller 85863a5442 Polishing 2015-12-01 19:16:16 +01:00
Juergen Hoeller 948ab21f43 Aligned class name quoting with ConversionFailedException
(cherry picked from commit 7589c1f)
2015-12-01 19:16:11 +01:00
Juergen Hoeller c56d1a6677 Document destruction callback behavior for inner beans in case of scope mismatch
Issue: SPR-13739
(cherry picked from commit 998da2f)
2015-11-30 22:16:18 +01:00
Juergen Hoeller e6d3c28ec2 Avoid instantiation of non-selected beans in BeanFactoryAnnotationUtils.qualifiedBeanOfType
Issue: SPR-13741
(cherry picked from commit 8ed2c47)
2015-11-30 22:03:25 +01:00
Juergen Hoeller a730b6e1aa Backported exception message refinements from 4.2.x 2015-11-30 12:24:38 +01:00
Juergen Hoeller 6c4f0a4d9f Backported conversion service test updates from 4.2.x 2015-11-30 12:18:56 +01:00
Juergen Hoeller 3bc2a97776 Unit tests for @Value Resource resolution
Issue: SPR-13731
(cherry picked from commit def1034)
2015-11-30 12:11:15 +01:00
Juergen Hoeller ce315b223e Upgrade to Tomcat 8.0.29 and SLF4J 1.7.13 2015-11-27 13:52:20 +01:00
Juergen Hoeller 5bfa82db12 Javadoc fixes
(cherry picked from commit 9bb72e8)
2015-11-27 13:51:51 +01:00
Juergen Hoeller 97148ce889 Polishing 2015-11-26 01:10:31 +01:00
Andy Clement e410129aaf Ensure cast correctly included for OpPlus compilation
When the plus operator is used between strings in a SpEL
expression and that expression is compiled, it is
important to include a cast if computation of any of
the operands isn't obviously leaving strings on the
stack. Likewise if the stack contents are known to
be strings, a cast should not be included.

Issue: SPR-12426
(cherry picked from commit 58756b0)
2015-11-26 01:10:04 +01:00
Juergen Hoeller 55494362ef SimpAnnotationMethodMessageHandler skips template variable check in case of no pattern
Issue: SPR-13704
(cherry picked from commit e8417ea)
2015-11-26 01:09:57 +01:00
Juergen Hoeller 393e36c29e Latest applicable server engine updates (Jetty 9.2.14, Netty 4.0.33, Undertow 1.1.9) 2015-11-15 00:25:20 +01:00
Juergen Hoeller 5a95156dcc Fixed class name in debug log message 2015-11-14 23:58:27 +01:00
Juergen Hoeller 71fc2ba174 Polishing 2015-11-14 23:32:36 +01:00
Juergen Hoeller 48838d48d2 Fixed various code examples in documentation
Issue: SPR-13666
Issue: SPR-13485
Issue: SPR-10474
2015-11-14 23:32:07 +01:00
Juergen Hoeller 5d6aab34cb Reduced warn log entry without stacktrace for startup exceptions
Also, AbstractApplicationContext.isRunning avoids IllegalStateException now.

Issue: SPR-13663
Issue: SPR-13667
2015-11-14 23:27:20 +01:00
Juergen Hoeller 90a288513c MethodInvokeTypeProvider lazily invokes target method (avoiding deserialization exploits)
Issue: SPR-13656
(cherry picked from commit ea2843e)
2015-11-14 23:25:35 +01:00
Juergen Hoeller df49b11758 CommonsMultipartFile removes mixed separator paths from original filename
Issue: SPR-13662
(cherry picked from commit 5d9d88c)
2015-11-14 23:16:13 +01:00
Juergen Hoeller d1f5ee2643 Avoid NPE for anonymous SqlParameter in CallMetaDataContext
Issue: SPR-13628
(cherry picked from commit 6685c78)
2015-11-14 23:15:06 +01:00
Juergen Hoeller 0f4e4fcca6 Declared JDBC operation compiled flag as volatile
Issue: SPR-13617
(cherry picked from commit 81342f1)
2015-11-14 23:12:46 +01:00
Rossen Stoyanchev a8c7220fc7 Fix failing tests 2015-11-11 18:04:28 -05:00
Rossen Stoyanchev 92ca537d61 Switch "attachment" to "inline" on Content-Disposition
Issue: SPR-13587, SPR-13643
2015-11-11 17:47:34 -05:00
Rossen Stoyanchev f5f57e9544 Expand range of whitelisted extensions by media type
This commit expands the range of whitelisted extensions by checking
if an extension can be resolved to image/*, audio/*, video/*, as well
as any content type that ends with +xml.

Issue: SPR-13643
2015-11-11 17:46:36 -05:00
Rossen Stoyanchev cde4431c80 Add containsKey to ServletResponseHttpHeaders
Issue: SPR-13668
2015-11-11 14:28:34 -05:00
Rossen Stoyanchev d500d523e7 Whitelist extension if present in the request mapping
We know skip the Content-Disposition header for any extension if the
chosen request mapping explicitly contains the URl extension.

Issue: SPR-13629
2015-11-06 12:45:40 -05:00
Rossen Stoyanchev 71a9eb7102 Add section on RFD + whitelist yml/properties/csv
Issue: SPR-13643
2015-11-05 19:42:30 -05:00
Rossen Stoyanchev e190f26669 No Content-Disposition if HTML in the request mapping
Issue: SPR-13629
2015-11-02 13:13:37 -05:00
Rossen Stoyanchev 0f1897d376 Further improve Detect custom CNVR
Refine the approach of having <mvc:view-resolvers> detect and use the
ContentNegotiationManager instance registered with
<mvc:annotation-driven> introduced in the last commit.

Issue: SPR-13559
2015-10-29 20:53:36 -04:00
Rossen Stoyanchev 563a120280 Detect custom ContentNegotiationViewResolver
The <mvc:annotation-driven> element now adds an alias when a
ContentNegotiationManager bean is registered with a custom name.
This helps <mvc:view-resolvers> to more reliably find such a custom
ContentNegotiationManager.

Issue: SPR-13559
2015-10-29 18:06:45 -04:00
Brian Clozel 78fc5bbecc Don't throw NPE when serving webjar directories
Prior to this change, serving resources with ResourceHttpRequestHandler
could result in NPE when requesting an existing folder located in a JAR.

This commit swallows those exceptions, as it is not possible to foresee
those cases without reading the actual resource. This result in a HTTP
200 response with a zero Content-Length instead of a HTTP 500 internal
exception.

Issue: SPR-13620
2015-10-29 16:48:55 +01:00
Rossen Stoyanchev a879897063 Skip Content-Disposition header if status != 2xx
Issue: SPR-13588
2015-10-26 16:11:20 -04:00
Spring Buildmaster 0016752ad8 Next Development Version 2015-10-15 02:40:06 -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
707 changed files with 15386 additions and 9056 deletions
-8
View File
@@ -22,14 +22,6 @@ do not find something similar, please create a new JIRA issue before submitting
a pull request unless the change is truly trivial -- for example: typo fixes,
removing compiler warnings, etc.
### Discuss non-trivial contribution ideas with committers
If you're considering anything more than correcting a typo or fixing a minor
bug, please discuss it on the [spring-framework-contrib][] mailing list before
submitting a pull request. We're happy to provide guidance, but please spend an
hour or two researching the subject on your own, including searching the mailing
list for prior discussions.
### Sign the Contributor License Agreement
If you have not previously done so, please fill out and submit the
+72 -70
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.hsqldbVersion = "2.3.3"
ext.jackson2Version = "2.4.6"
ext.jasperReportsVersion = "6.0.4"
ext.jettyVersion = "9.2.14.v20151106"
ext.jodaVersion = "2.8.2"
ext.junitVersion = "4.12"
ext.nettyVersion = "4.0.24.Final"
ext.nettyVersion = "4.0.33.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.13"
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.30"
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
ext.undertowVersion = "1.1.1.Final"
ext.undertowVersion = "1.1.9.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(
@@ -164,27 +163,27 @@ configure(allprojects) { project ->
}
ext.javadocLinks = [
"http://docs.oracle.com/javase/8/docs/api/",
"http://docs.oracle.com/javaee/7/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"http://glassfish.java.net/nonav/docs/v3/api/",
"http://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
"http://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
"http://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
"http://commons.apache.org/proper/commons-codec/apidocs/",
"http://commons.apache.org/proper/commons-dbcp/apidocs/",
"http://portals.apache.org/pluto/portlet-2.0-apidocs/",
"http://tiles.apache.org/tiles-request/apidocs/",
"http://tiles.apache.org/framework/apidocs/",
"https://docs.oracle.com/javase/8/docs/api/",
"https://docs.oracle.com/javaee/7/api/",
"https://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"https://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"https://glassfish.java.net/nonav/docs/v3/api/",
"https://docs.jboss.org/jbossas/javadoc/4.0.5/connector/",
"https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/",
"https://commons.apache.org/proper/commons-lang/javadocs/api-2.5/",
"https://commons.apache.org/proper/commons-codec/apidocs/",
"https://commons.apache.org/proper/commons-dbcp/apidocs/",
"https://portals.apache.org/pluto/portlet-2.0-apidocs/",
"https://tiles.apache.org/tiles-request/apidocs/",
"https://tiles.apache.org/framework/apidocs/",
"http://aopalliance.sourceforge.net/doc/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://ehcache.org/apidocs/",
"http://quartz-scheduler.org/api/2.2.0/",
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
"http://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/",
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
"https://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"https://www.ehcache.org/apidocs/${ehcacheVersion}/",
"https://www.quartz-scheduler.org/api/2.2.2/",
"https://fasterxml.github.io/jackson-core/javadoc/2.3.0/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.3.0/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.3.0/",
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/"
] as String[]
}
@@ -331,10 +330,10 @@ project("spring-core") {
compile("commons-logging:commons-logging:1.2")
optional("commons-codec:commons-codec:1.10")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("net.sf.jopt-simple:jopt-simple:4.8")
optional("net.sf.jopt-simple:jopt-simple:4.9")
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}")
@@ -533,9 +532,9 @@ 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
// see https://jira.codehaus.org/browse/JIBX-465
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'
@@ -593,9 +592,9 @@ project("spring-jdbc") {
compile(project(":spring-tx"))
optional(project(":spring-context")) // for JndiDataSourceLookup
optional("javax.transaction:javax.transaction-api:1.2")
optional("com.mchange:c3p0:0.9.2.1")
optional("com.mchange:c3p0:0.9.5.1")
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
optional("com.h2database:h2:1.4.182")
optional("com.h2database:h2:1.4.190")
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"
@@ -1206,7 +1208,7 @@ configure(rootProject) {
baseName = "spring-framework"
classifier = "docs"
description = "Builds -${classifier} archive containing api and reference " +
"for deployment at http://static.springframework.org/spring-framework/docs."
"for deployment at https://docs.spring.io/spring-framework/docs."
from("src/dist") {
include "changelog.txt"
@@ -1226,7 +1228,7 @@ configure(rootProject) {
baseName = "spring-framework"
classifier = "schema"
description = "Builds -${classifier} archive containing all " +
"XSDs for deployment at http://springframework.org/schema."
"XSDs for deployment at https://springframework.org/schema."
duplicatesStrategy 'exclude'
moduleProjects.each { subproject ->
def Properties schemas = new Properties();
+1 -1
View File
@@ -1 +1 @@
version=4.1.4.BUILD-SNAPSHOT
version=4.1.10.BUILD-SNAPSHOT
+1 -1
View File
@@ -11,7 +11,7 @@ eclipse.jdt {
}
// Replace classpath entries with project dependencies (GRADLE-1116)
// http://issues.gradle.org/browse/GRADLE-1116
// https://issues.gradle.org/browse/GRADLE-1116
eclipse.classpath.file.whenMerged { classpath ->
def regexp = /.*?\/([^\/]+)\/build\/[^\/]+\/(?:main|test)/ // only match those that end in main or test (avoids removing necessary entries like build/classes/jaxb)
def projectOutputDependencies = classpath.entries.findAll { entry -> entry.path =~ regexp }
+2 -2
View File
@@ -25,12 +25,12 @@ def customizePom(pom, gradleProject) {
url = "https://github.com/spring-projects/spring-framework"
organization {
name = "Spring IO"
url = "http://projects.spring.io/spring-framework"
url = "https://projects.spring.io/spring-framework"
}
licenses {
license {
name "The Apache Software License, Version 2.0"
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
url "https://www.apache.org/licenses/LICENSE-2.0.txt"
distribution "repo"
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ echo been tested against STS %STS_TEST_VERSION%), but at the minimum you will
echo need Eclipse + AJDT.
echo.
echo If you need to download and install STS, please do that now by
echo visiting http://spring.io/tools/sts/all
echo visiting https://spring.io/tools/sts/all
echo.
echo Otherwise, press enter and we'll begin.
+3 -3
View File
@@ -19,9 +19,9 @@ This script has been tested against:
If you need to download and install Eclipse or STS, please do that now
by visiting one of the following sites:
- Eclipse downloads: http://download.eclipse.org/eclipse/downloads
- STS downloads: http://spring.io/tools/sts/all
- STS nightly builds: http://dist.springsource.com/snapshot/STS/nightly-distributions.html
- Eclipse downloads: https://download.eclipse.org/eclipse/downloads
- STS downloads: https://spring.io/tools/sts/all
- STS nightly builds: https://dist.springsource.com/snapshot/STS/nightly-distributions.html
If you need to install a recent CI build for AJDT (i.e., so that the
spring-aspects module properly compiles in Eclipse/STS), click on the
@@ -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.
@@ -243,6 +243,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
private String toString(boolean includeModifier, boolean includeReturnTypeAndArgs,
boolean useLongReturnAndArgumentTypeName, boolean useLongTypeName) {
StringBuilder sb = new StringBuilder();
if (includeModifier) {
sb.append(Modifier.toString(getModifiers()));
@@ -262,8 +263,9 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
return sb.toString();
}
private void appendTypes(StringBuilder sb, Class<?>[] types,
boolean includeArgs, boolean useLongReturnAndArgumentTypeName) {
private void appendTypes(StringBuilder sb, Class<?>[] types, boolean includeArgs,
boolean useLongReturnAndArgumentTypeName) {
if (includeArgs) {
for (int size = types.length, i = 0; i < size; i++) {
appendType(sb, types[i], useLongReturnAndArgumentTypeName);
@@ -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.
@@ -93,7 +93,7 @@ class CglibAopProxy implements AopProxy, Serializable {
/** Logger available to subclasses; static to optimize serialization */
protected final static Log logger = LogFactory.getLog(CglibAopProxy.class);
protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);
/** Keeps track of the Classes that we have validated for final methods */
private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<Class<?>, Boolean>();
@@ -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;
@@ -304,13 +304,13 @@ class CglibAopProxy implements AopProxy, Serializable {
Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
Callback[] mainCallbacks = new Callback[]{
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
@@ -702,6 +702,7 @@ class CglibAopProxy implements AopProxy, Serializable {
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
this.methodProxy = methodProxy;
this.publicMethod = Modifier.isPublic(method.getModifiers());
@@ -821,8 +822,7 @@ class CglibAopProxy implements AopProxy, Serializable {
if (logger.isDebugEnabled()) {
logger.debug("Method has advice and optimisations are enabled: " + method);
}
// We know that we are optimising so we can use the
// FixedStaticChainInterceptors.
// We know that we are optimising so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(key);
return (index + this.fixedInterceptorOffset);
}
@@ -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-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.
@@ -57,10 +57,10 @@ public class TypeMismatchException extends PropertyAccessException {
*/
public TypeMismatchException(PropertyChangeEvent propertyChangeEvent, Class<?> requiredType, Throwable cause) {
super(propertyChangeEvent,
"Failed to convert property value of type '" +
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "'" +
"Failed to convert property value of type [" +
ClassUtils.getDescriptiveType(propertyChangeEvent.getNewValue()) + "]" +
(requiredType != null ?
" to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : "") +
" to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : "") +
(propertyChangeEvent.getPropertyName() != null ?
" for property '" + propertyChangeEvent.getPropertyName() + "'" : ""),
cause);
@@ -84,8 +84,8 @@ public class TypeMismatchException extends PropertyAccessException {
* @param cause the root cause (may be {@code null})
*/
public TypeMismatchException(Object value, Class<?> requiredType, Throwable cause) {
super("Failed to convert value of type '" + ClassUtils.getDescriptiveType(value) + "'" +
(requiredType != null ? " to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" : ""),
super("Failed to convert value of type [" + ClassUtils.getDescriptiveType(value) + "]" +
(requiredType != null ? " to required type [" + ClassUtils.getQualifiedName(requiredType) + "]" : ""),
cause);
this.value = value;
this.requiredType = requiredType;
@@ -93,7 +93,7 @@ public class TypeMismatchException extends PropertyAccessException {
/**
* Return the offending value (may be {@code null})
* Return the offending value (may be {@code null}).
*/
@Override
public Object getValue() {
@@ -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.
@@ -17,7 +17,6 @@
package org.springframework.beans.factory.annotation;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
@@ -77,20 +76,19 @@ public class BeanFactoryAnnotationUtils {
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
*/
private static <T> T qualifiedBeanOfType(ConfigurableListableBeanFactory bf, Class<T> beanType, String qualifier) {
Map<String, T> candidateBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, beanType);
T matchingBean = null;
for (Map.Entry<String, T> entry : candidateBeans.entrySet()) {
String beanName = entry.getKey();
String[] candidateBeans = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(bf, beanType);
String matchingBean = null;
for (String beanName : candidateBeans) {
if (isQualifierMatch(qualifier, beanName, bf)) {
if (matchingBean != null) {
throw new NoSuchBeanDefinitionException(qualifier, "No unique " + beanType.getSimpleName() +
" bean found for qualifier '" + qualifier + "'");
}
matchingBean = entry.getValue();
matchingBean = beanName;
}
}
if (matchingBean != null) {
return matchingBean;
return bf.getBean(matchingBean, beanType);
}
else if (bf.containsBean(qualifier)) {
// Fallback: target bean at least found by bean name - probably a manually registered singleton.
@@ -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-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.
@@ -48,8 +48,8 @@ public interface BeanPostProcessor {
* The returned bean instance may be a wrapper around the original.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one; if
* {@code null}, no subsequent BeanPostProcessors will be invoked
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
*/
@@ -69,8 +69,8 @@ public interface BeanPostProcessor {
* in contrast to all other BeanPostProcessor callbacks.
* @param bean the new bean instance
* @param beanName the name of the bean
* @return the bean instance to use, either the original or a wrapped one; if
* {@code null}, no subsequent BeanPostProcessors will be invoked
* @return the bean instance to use, either the original or a wrapped one;
* if {@code null}, no subsequent BeanPostProcessors will be invoked
* @throws org.springframework.beans.BeansException in case of errors
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.FactoryBean
@@ -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);
if (logger.isDebugEnabled()) {
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) {
@@ -157,13 +163,13 @@ public abstract class YamlProcessor {
}
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") +
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " document" + (count > 1 ? "s" : "") +
" from YAML resource: " + resource);
}
}
finally {
stream.close();
reader.close();
}
}
catch (IOException ex) {
@@ -177,8 +183,8 @@ public abstract class YamlProcessor {
this.resolutionMethod != ResolutionMethod.OVERRIDE_AND_IGNORE) {
throw new IllegalStateException(ex);
}
if (this.logger.isWarnEnabled()) {
this.logger.warn("Could not load map from " + resource + ": " + ex.getMessage());
if (logger.isWarnEnabled()) {
logger.warn("Could not load map from " + resource + ": " + ex.getMessage());
}
}
@@ -215,8 +221,8 @@ public abstract class YamlProcessor {
properties.putAll(getFlattenedMap(map));
if (this.documentMatchers.isEmpty()) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Merging document (no matchers set)" + map);
if (logger.isDebugEnabled()) {
logger.debug("Merging document (no matchers set): " + map);
}
callback.process(properties, map);
return true;
@@ -227,8 +233,8 @@ public abstract class YamlProcessor {
MatchStatus match = matcher.matches(properties);
result = MatchStatus.getMostSpecific(match, result);
if (match == MatchStatus.FOUND) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Matched document with document matcher: " + properties);
if (logger.isDebugEnabled()) {
logger.debug("Matched document with document matcher: " + properties);
}
callback.process(properties, map);
return true;
@@ -236,14 +242,16 @@ public abstract class YamlProcessor {
}
if (result == MatchStatus.ABSTAIN && this.matchDefault) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Matched document with default matcher: " + map);
if (logger.isDebugEnabled()) {
logger.debug("Matched document with default matcher: " + map);
}
callback.process(properties, map);
return true;
}
this.logger.debug("Unmatched document");
if (logger.isDebugEnabled()) {
logger.debug("Unmatched document: " + map);
}
return false;
}
@@ -294,7 +302,7 @@ public abstract class YamlProcessor {
}
}
else {
result.put(key, value == null ? "" : value);
result.put(key, value != null ? value : "");
}
}
}
@@ -322,7 +330,7 @@ public abstract class YamlProcessor {
/**
* Test if the given properties match.
* @param properties the properties to test
* @return the status of the match.
* @return the status of the match
*/
MatchStatus matches(Properties properties);
}
@@ -331,7 +339,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 +368,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 +390,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 +401,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 +415,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 +425,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.
@@ -331,7 +331,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@@ -350,8 +350,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
@@ -1055,7 +1055,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
String scopeName = mbd.getScope();
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope SPI registered for scope '" + scopeName + "'");
throw new IllegalStateException("No Scope SPI registered for scope name '" + scopeName + "'");
}
Object bean = scope.remove(beanName);
if (bean != null) {
@@ -1334,6 +1334,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
private Class<?> doResolveBeanClass(RootBeanDefinition mbd, Class<?>... typesToMatch) throws ClassNotFoundException {
if (!ObjectUtils.isEmpty(typesToMatch)) {
// When just doing type checks (i.e. not creating an actual instance yet),
// use the specified temporary class loader (e.g. in a weaving scenario).
ClassLoader tempClassLoader = getTempClassLoader();
if (tempClassLoader != null) {
if (tempClassLoader instanceof DecoratingClassLoader) {
@@ -1422,9 +1424,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;
@@ -1570,7 +1578,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// A bean with a custom scope...
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + mbd.getScope() + "'");
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
@@ -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-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.
@@ -37,11 +37,12 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
/**
* Adapter that implements the {@link DisposableBean} and {@link Runnable} interfaces
* performing various destruction steps on a given bean instance:
* Adapter that implements the {@link DisposableBean} and {@link Runnable}
* interfaces performing various destruction steps on a given bean instance:
* <ul>
* <li>DestructionAwareBeanPostProcessors;
* <li>the bean implementing DisposableBean itself;
@@ -175,8 +176,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
/**
* If the current value of the given beanDefinition's "destroyMethodName" property is
* {@link AbstractBeanDefinition#INFER_METHOD}, then attempt to infer a destroy method.
* Candidate methods are currently limited to public, no-arg methods named "close"
* (whether declared locally or inherited). The given BeanDefinition's
* Candidate methods are currently limited to public, no-arg methods named "close" or
* "shutdown" (whether declared locally or inherited). The given BeanDefinition's
* "destroyMethodName" is updated to be null if no such method is found, otherwise set
* to the name of the inferred method. This constant serves as the default for the
* {@code @Bean#destroyMethod} attribute and the value of the constant may also be
@@ -215,7 +216,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
*/
private List<DestructionAwareBeanPostProcessor> filterPostProcessors(List<BeanPostProcessor> postProcessors) {
List<DestructionAwareBeanPostProcessor> filteredPostProcessors = null;
if (postProcessors != null && !postProcessors.isEmpty()) {
if (!CollectionUtils.isEmpty(postProcessors)) {
filteredPostProcessors = new ArrayList<DestructionAwareBeanPostProcessor>(postProcessors.size());
for (BeanPostProcessor postProcessor : postProcessors) {
if (postProcessor instanceof DestructionAwareBeanPostProcessor) {
@@ -234,7 +235,7 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
@Override
public void destroy() {
if (this.beanPostProcessors != null && !this.beanPostProcessors.isEmpty()) {
if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
processor.postProcessBeforeDestruction(this.bean, this.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.
@@ -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 {
@@ -31,8 +31,8 @@
(or an ancestor factory).
As alternative to bean references, "inner bean definitions" can be used.
Singleton flags of such inner bean definitions are effectively ignored:
inner beans are typically anonymous prototypes.
Such inner beans do not have an independent lifecycle; they are typically
anonymous nested objects that share the scope of their containing bean.
There is also support for lists, sets, maps, and java.util.Properties
as bean property types or constructor argument types.
@@ -113,16 +113,19 @@
<xsd:annotation>
<xsd:documentation><![CDATA[
The default 'lazy-init' value; see the documentation for the
'lazy-init' attribute of the 'bean' element.
'lazy-init' attribute of the 'bean' element. The default is "default",
indicating inheritance from outer 'beans' sections in case of nesting,
otherwise falling back to "false".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="default-merge" default="default" type="defaultable-boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
The default 'merge' value; see the documentation for the
'merge' attribute of the various collection elements. The default
is 'false'.
The default 'merge' value; see the documentation for the 'merge'
attribute of the various collection elements. The default is "default",
indicating inheritance from outer 'beans' sections in case of nesting,
otherwise falling back to "false".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -130,7 +133,9 @@
<xsd:annotation>
<xsd:documentation><![CDATA[
The default 'autowire' value; see the documentation for the
'autowire' attribute of the 'bean' element. The default is 'default'.
'autowire' attribute of the 'bean' element. The default is "default",
indicating inheritance from outer 'beans' sections in case of nesting,
otherwise falling back to "no" (i.e. no externally driven autowiring).
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
@@ -305,10 +310,10 @@
service objects. Further scopes, such as "request" or "session", might
be supported by extended bean factories (e.g. in a web environment).
Inner bean definitions inherit the singleton status of their containing
bean definition, unless explicitly specified: The inner bean will be a
Inner bean definitions inherit the scope of their containing bean
definition, unless explicitly specified: The inner bean will be a
singleton if the containing bean is a singleton, and a prototype if
the containing bean has any other scope.
the containing bean is a prototype, etc.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -328,13 +333,15 @@
<xsd:attribute name="lazy-init" default="default" type="defaultable-boolean">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether or not this bean is to be lazily initialized.
If false, it will be instantiated on startup by bean factories
that perform eager initialization of singletons. The default is
"false".
Indicates whether this bean is to be lazily initialized. If "false",
it will be instantiated on startup by bean factories that perform eager
initialization of singletons. The effective default is "false".
Note: This attribute will not be inherited by child bean definitions.
Hence, it needs to be specified per concrete bean definition.
Hence, it needs to be specified per concrete bean definition. It can be
shared through the 'default-lazy-init' attribute at the 'beans' level
and potentially inherited from outer 'beans' defaults in case of nested
'beans' sections (e.g. with different profiles).
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -344,7 +351,7 @@
Controls whether bean properties are "autowired".
This is an automagical process in which bean references don't need
to be coded explicitly in the XML bean definition file, but rather the
Spring container works out dependencies.
Spring container works out dependencies. The effective default is "no".
There are 4 modes:
@@ -379,7 +386,10 @@
elements, always override autowiring.
Note: This attribute will not be inherited by child bean definitions.
Hence, it needs to be specified per concrete bean definition.
Hence, it needs to be specified per concrete bean definition. It can be
shared through the 'default-autowire' attribute at the 'beans' level
and potentially inherited from outer 'beans' defaults in case of nested
'beans' sections (e.g. with different profiles).
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
@@ -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());
@@ -713,7 +713,7 @@ public class DefaultListableBeanFactoryTests {
RootBeanDefinition parentDefinition = new RootBeanDefinition(TestBean.class);
parentDefinition.setAbstract(true);
parentDefinition.getPropertyValues().add("name", EXPECTED_NAME);
parentDefinition.getPropertyValues().add("age", new Integer(EXPECTED_AGE));
parentDefinition.getPropertyValues().add("age", EXPECTED_AGE);
ChildBeanDefinition childDefinition = new ChildBeanDefinition("alias");
@@ -1201,7 +1201,7 @@ public class DefaultListableBeanFactoryTests {
RootBeanDefinition rbd = new RootBeanDefinition(PropertiesFactoryBean.class);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("locations", new String[] {"#{foo}"});
pvs.add("locations", new String[]{"#{foo}"});
rbd.setPropertyValues(pvs);
bf.registerBeanDefinition("myProperties", rbd);
Properties properties = (Properties) bf.getBean("myProperties");
@@ -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"));
}
}
@@ -2245,32 +2264,6 @@ public class DefaultListableBeanFactoryTests {
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
}
/**
* @Test
* public void testPrototypeCreationWithConstructorArgumentsIsFastEnough2() throws Exception {
* if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
* // Skip this test: Trace logging blows the time limit.
* return;
* }
* DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
* Constructor<TestBean> ctor = TestBean.class.getConstructor(String.class, int.class);
* Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class);
* Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class);
* StopWatch sw = new StopWatch();
* sw.start("prototype");
* for (int i = 0; i < 100000; i++) {
* TestBean tb = ctor.newInstance("juergen", 99);
* setBeanNameMethod.invoke(tb, "test");
* setBeanFactoryMethod.invoke(tb, lbf);
* assertEquals("juergen", tb.getName());
* assertEquals(99, tb.getAge());
* }
* sw.stop();
* // System.out.println(sw.getTotalTimeMillis());
* assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 1500);
* }
*/
@Test
public void testPrototypeCreationWithResolvedConstructorArgumentsIsFastEnough() {
Assume.group(TestGroup.PERFORMANCE);
@@ -2315,31 +2308,6 @@ public class DefaultListableBeanFactoryTests {
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
}
/**
* public void testPrototypeCreationWithPropertiesIsFastEnough2() throws Exception {
* if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
* // Skip this test: Trace logging blows the time limit.
* return;
* }
* DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
* StopWatch sw = new StopWatch();
* Method setBeanNameMethod = TestBean.class.getMethod("setBeanName", String.class);
* Method setBeanFactoryMethod = TestBean.class.getMethod("setBeanFactory", BeanFactory.class);
* Method setNameMethod = TestBean.class.getMethod("setName", String.class);
* Method setAgeMethod = TestBean.class.getMethod("setAge", int.class);
* sw.start("prototype");
* for (int i = 0; i < 100000; i++) {
* TestBean tb = TestBean.class.newInstance();
* setBeanNameMethod.invoke(tb, "test");
* setBeanFactoryMethod.invoke(tb, lbf);
* setNameMethod.invoke(tb, "juergen");
* setAgeMethod.invoke(tb, 99);
* }
* sw.stop();
* // System.out.println(sw.getTotalTimeMillis());
* assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 750);
* }
*/
@Test
public void testPrototypeCreationWithResolvedPropertiesIsFastEnough() {
Assume.group(TestGroup.PERFORMANCE);
@@ -2420,10 +2388,41 @@ public class DefaultListableBeanFactoryTests {
return bean;
}
});
BeanWithDestroyMethod.closed = false;
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
assertTrue("Destroy method invoked", BeanWithDestroyMethod.closed);
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
}
@Test
public void testDestroyMethodOnInnerBean() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
innerBd.setDestroyMethodName("close");
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
bd.setDestroyMethodName("close");
bd.getPropertyValues().add("inner", innerBd);
lbf.registerBeanDefinition("test", bd);
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
assertEquals("Destroy methods invoked", 2, BeanWithDestroyMethod.closeCount);
}
@Test
public void testDestroyMethodOnInnerBeanAsPrototype() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition innerBd = new RootBeanDefinition(BeanWithDestroyMethod.class);
innerBd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
innerBd.setDestroyMethodName("close");
RootBeanDefinition bd = new RootBeanDefinition(BeanWithDestroyMethod.class);
bd.setDestroyMethodName("close");
bd.getPropertyValues().add("inner", innerBd);
lbf.registerBeanDefinition("test", bd);
BeanWithDestroyMethod.closeCount = 0;
lbf.preInstantiateSingletons();
lbf.destroySingletons();
assertEquals("Destroy methods invoked", 1, BeanWithDestroyMethod.closeCount);
}
@Test
@@ -2518,7 +2517,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();
@@ -2660,10 +2659,6 @@ public class DefaultListableBeanFactoryTests {
verify(r3, never()).resolveStringValue(isNull(String.class));
}
static class A { }
static class B { }
/**
* Test that by-type bean lookup caching is working effectively by searching for a
* bean of type B 10K times within a container having 1K additional beans of type A.
@@ -2674,24 +2669,29 @@ public class DefaultListableBeanFactoryTests {
* under the 1000 ms timeout, usually ~= 300ms. With caching removed and on the same
* hardware the method will take ~13000 ms. See SPR-6870.
*/
@Test(timeout=1000)
@Test(timeout = 1000)
public void testByTypeLookupIsFastEnough() {
Assume.group(TestGroup.PERFORMANCE);
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
for (int i = 0; i < 1000; i++) {
bf.registerBeanDefinition("a"+i, new RootBeanDefinition(A.class));
bf.registerBeanDefinition("a" + i, new RootBeanDefinition(A.class));
}
bf.registerBeanDefinition("b", new RootBeanDefinition(B.class));
bf.freezeConfiguration();
for (int i=0; i<10000; i++) {
for (int i = 0; i < 10000; i++) {
bf.getBean(B.class);
}
}
static class A { }
static class B { }
public static class NoDependencies {
private NoDependencies() {
@@ -2797,10 +2797,16 @@ public class DefaultListableBeanFactoryTests {
public static class BeanWithDestroyMethod {
private static boolean closed;
private static int closeCount = 0;
private BeanWithDestroyMethod inner;
public void setInner(BeanWithDestroyMethod inner) {
this.inner = inner;
}
public void close() {
closed = true;
closeCount++;
}
}
@@ -2962,7 +2968,6 @@ public class DefaultListableBeanFactoryTests {
private FactoryBean<?> factoryBean;
public final FactoryBean<?> getFactoryBean() {
return this.factoryBean;
}
@@ -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-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,8 +24,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation indicating that a method (or all methods on a class) trigger(s)
* a cache invalidate operation.
* Annotation indicating that a method (or all methods on a class) triggers a
* {@link org.springframework.cache.Cache#evict(Object) cache evict} operation.
*
* @author Costin Leau
* @author Stephane Nicoll
@@ -39,22 +39,39 @@ import java.lang.annotation.Target;
public @interface CacheEvict {
/**
* Qualifier value for the specified cached operation.
* <p>May be used to determine the target cache (or caches), matching the qualifier
* value (or the bean name(s)) of (a) specific bean definition.
* Names of the caches to use for the cache eviction operation.
* <p>Names may be used to determine the target cache (or caches), matching
* the qualifier value or bean name of a specific bean definition.
* @see CacheConfig#cacheNames
*/
String[] value() default {};
/**
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
* <p>Default is "", meaning all method parameters are considered as a key, unless
* a custom {@link #keyGenerator()} has been set.
* Spring Expression Language (SpEL) expression for computing the key dynamically.
* <p>Default is {@code ""}, meaning all method parameters are considered as a key,
* unless a custom {@link #keyGenerator} has been set.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation, which
* can only be used if {@link #beforeInvocation()} is {@code false}.</li>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
String key() default "";
/**
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator} to use.
* <p>Mutually exclusive with the {@link #key()} attribute.
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator}
* to use.
* <p>Mutually exclusive with the {@link #key} attribute.
* @see CacheConfig#keyGenerator
*/
String keyGenerator() default "";
@@ -62,34 +79,55 @@ public @interface CacheEvict {
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
* is set already.
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
* <p>Mutually exclusive with the {@link #cacheResolver} attribute.
* @see org.springframework.cache.interceptor.SimpleCacheResolver
* @see CacheConfig#cacheManager
*/
String cacheManager() default "";
/**
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
* to use.
* @see CacheConfig#cacheResolver
*/
String cacheResolver() default "";
/**
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
* <p>Default is "", meaning the method is always cached.
* Spring Expression Language (SpEL) expression used for making the cache
* eviction operation conditional.
* <p>Default is {@code ""}, meaning the cache eviction is always performed.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
String condition() default "";
/**
* Whether or not all the entries inside the cache(s) are removed or not. By
* default, only the value under the associated key is removed.
* <p>Note that setting this parameter to {@code true} and specifying a {@link #key()}
* is not allowed.
* Whether all the entries inside the cache(s) are removed.
* <p>By default, only the value under the associated key is removed.
* <p>Note that setting this parameter to {@code true} and specifying a
* {@link #key} is not allowed.
*/
boolean allEntries() default false;
/**
* Whether the eviction should occur after the method is successfully invoked (default)
* or before. The latter causes the eviction to occur irrespective of the method outcome (whether
* it threw an exception or not) while the former does not.
* Whether the eviction should occur before the method is invoked.
* <p>Setting this attribute to {@code true}, causes the eviction to
* occur irrespective of the method outcome (i.e., whether it threw an
* exception or not).
* <p>Defaults to {@code false}, meaning that the cache eviction operation
* will occur <em>after</em> the advised method is invoked successfully (i.e.,
* only if the invocation did not throw an exception).
*/
boolean beforeInvocation() default 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,13 +23,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cache.Cache;
/**
* Annotation indicating that a method (or all methods on a class) trigger(s)
* a {@link Cache#put(Object, Object)} operation. As opposed to {@link Cacheable} annotation,
* this annotation does not cause the target method to be skipped - rather it
* always causes the method to be invoked and its result to be placed into the cache.
* Annotation indicating that a method (or all methods on a class) triggers a
* {@link org.springframework.cache.Cache#put(Object, Object) cache put} operation.
*
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
* does not cause the advised method to be skipped. Rather, it always causes the
* method to be invoked and its result to be stored in the associated cache.
*
* @author Costin Leau
* @author Phillip Webb
@@ -37,29 +37,45 @@ import org.springframework.cache.Cache;
* @since 3.1
* @see CacheConfig
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
/**
* Name of the caches in which the update takes place.
* <p>May be used to determine the target cache (or caches), matching the
* qualifier value (or the bean name(s)) of (a) specific bean definition.
* Names of the caches to use for the cache put operation.
* <p>Names may be used to determine the target cache (or caches), matching
* the qualifier value or bean name of a specific bean definition.
* @see CacheConfig#cacheNames
*/
String[] value() default {};
/**
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
* <p>Default is "", meaning all method parameters are considered as a key, unless
* a custom {@link #keyGenerator()} has been set.
* Spring Expression Language (SpEL) expression for computing the key dynamically.
* <p>Default is {@code ""}, meaning all method parameters are considered as a key,
* unless a custom {@link #keyGenerator} has been set.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation.</li>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
String key() default "";
/**
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator} to use.
* <p>Mutually exclusive with the {@link #key()} attribute.
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator}
* to use.
* <p>Mutually exclusive with the {@link #key} attribute.
* @see CacheConfig#keyGenerator
*/
String keyGenerator() default "";
@@ -67,28 +83,58 @@ public @interface CachePut {
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
* is set already.
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
* <p>Mutually exclusive with the {@link #cacheResolver} attribute.
* @see org.springframework.cache.interceptor.SimpleCacheResolver
* @see CacheConfig#cacheManager
*/
String cacheManager() default "";
/**
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
* to use.
* @see CacheConfig#cacheResolver
*/
String cacheResolver() default "";
/**
* Spring Expression Language (SpEL) attribute used for conditioning the cache update.
* <p>Default is "", meaning the method result is always cached.
* Spring Expression Language (SpEL) expression used for making the cache
* put operation conditional.
* <p>Default is {@code ""}, meaning the method result is always cached.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
String condition() default "";
/**
* Spring Expression Language (SpEL) attribute used to veto the cache update.
* <p>Unlike {@link #condition()}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}. Default is "",
* meaning that caching is never vetoed.
* Spring Expression Language (SpEL) expression used to veto the cache put operation.
* <p>Unlike {@link #condition}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}.
* <p>Default is {@code ""}, meaning that caching is never vetoed.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation.</li>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
* @since 3.2
*/
String unless() 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.
@@ -24,17 +24,18 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation indicating that a method (or all the methods on a class) can be cached.
* Annotation indicating that the result of invoking a method (or all methods
* in a class) can be cached.
*
* <p>Each time a targeted method is invoked, a caching behavior will be applied,
* checking whether the method has been already executed for the given arguments. A
* sensible default simply uses the method parameters to compute the key but a SpEL
* expression can be provided ({@link #key()}) or a custom
* {@link org.springframework.cache.interceptor.KeyGenerator KeyGenerator} implementation
* can replace the default one ({@link #keyGenerator()}).
* <p>Each time an advised method is invoked, caching behavior will be applied,
* checking whether the method has been already invoked for the given arguments.
* A sensible default simply uses the method parameters to compute the key, but
* a SpEL expression can be provided via the {@link #key} attribute, or a custom
* {@link org.springframework.cache.interceptor.KeyGenerator} implementation can
* replace the default one (see {@link #keyGenerator}).
*
* <p>If no value is found in the cache for the computed key, the method is executed
* and the returned instance is used as the cache value.
* <p>If no value is found in the cache for the computed key, the target method
* will be invoked and the returned value stored in the associated cache.
*
* @author Costin Leau
* @author Phillip Webb
@@ -49,22 +50,37 @@ import java.lang.annotation.Target;
public @interface Cacheable {
/**
* Name of the caches in which the update takes place.
* <p>May be used to determine the target cache (or caches), matching the
* qualifier value (or the bean name(s)) of (a) specific bean definition.
* Names of the caches in which method invocation results are stored.
* <p>Names may be used to determine the target cache (or caches), matching
* the qualifier value or bean name of a specific bean definition.
* @see CacheConfig#cacheNames
*/
String[] value() default {};
/**
* Spring Expression Language (SpEL) attribute for computing the key dynamically.
* <p>Default is "", meaning all method parameters are considered as a key, unless
* a custom {@link #keyGenerator()} has been set.
* Spring Expression Language (SpEL) expression for computing the key dynamically.
* <p>Default is {@code ""}, meaning all method parameters are considered as a key,
* unless a custom {@link #keyGenerator} has been configured.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
String key() default "";
/**
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator} to use.
* <p>Mutually exclusive with the {@link #key()} attribute.
* The bean name of the custom {@link org.springframework.cache.interceptor.KeyGenerator}
* to use.
* <p>Mutually exclusive with the {@link #key} attribute.
* @see CacheConfig#keyGenerator
*/
String keyGenerator() default "";
@@ -72,28 +88,58 @@ public @interface Cacheable {
* The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
* create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
* is set already.
* <p>Mutually exclusive with the {@link #cacheResolver()} attribute.
* <p>Mutually exclusive with the {@link #cacheResolver} attribute.
* @see org.springframework.cache.interceptor.SimpleCacheResolver
* @see CacheConfig#cacheManager
*/
String cacheManager() default "";
/**
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver} to use.
* The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
* to use.
* @see CacheConfig#cacheResolver
*/
String cacheResolver() default "";
/**
* Spring Expression Language (SpEL) attribute used for conditioning the method caching.
* <p>Default is "", meaning the method is always cached.
* Spring Expression Language (SpEL) expression used for making the method
* caching conditional.
* <p>Default is {@code ""}, meaning the method result is always cached.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
String condition() default "";
/**
* Spring Expression Language (SpEL) attribute used to veto method caching.
* <p>Unlike {@link #condition()}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}. Default is "",
* meaning that caching is never vetoed.
* Spring Expression Language (SpEL) expression used to veto method caching.
* <p>Unlike {@link #condition}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}.
* <p>Default is {@code ""}, meaning that caching is never vetoed.
* <p>The SpEL expression evaluates again a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation.</li>
* <li>{@code #root.method}, {@code #root.target} and {@code #root.caches} for a
* reference to the {@link java.lang.reflect.Method method}, target object and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be access via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
* @since 3.2
*/
String unless() default "";
}
@@ -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.getClassName() + "]: " + 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);
@@ -484,7 +484,10 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
@@ -504,6 +507,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 +725,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 +806,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
this.shutdownHook = new Thread() {
@Override
public void run() {
doClose();
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
@@ -1178,7 +1185,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
@Override
public boolean isRunning() {
return getLifecycleProcessor().isRunning();
return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
}

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