Compare commits

..

215 Commits

Author SHA1 Message Date
Spring Buildmaster 58587159f0 Release version 3.2.9 2014-05-20 04:49:35 -07:00
Phillip Webb 69b9d00179 Add 3.2.9 issues to the changelog 2014-05-20 11:40:13 +01:00
Juergen Hoeller 8aabc43dad Servlet 3 multipart request implements getParameterMap defensively as well
Issue: SPR-11074
(cherry picked from commit c7d1c49)
2014-05-20 11:28:57 +02:00
Juergen Hoeller 4d3aa59028 Polishing
(cherry picked from commit 6fef8b9)
2014-05-20 11:27:55 +02:00
Rossen Stoyanchev c6503ebbf7 Disable URL resolution in DTD declarations
Issue: SPR-11768
2014-05-19 22:43:14 -04:00
Juergen Hoeller f42f2231a4 Minor UriComponentsBuilder javadoc revision
(cherry picked from commit 545c28f)
2014-05-20 01:06:01 +02:00
Juergen Hoeller 0313222bc7 Consistent use of IllegalStateException instead of InternalError for UnsupportedEncodingException cause
(cherry picked from commit d9b39ad)
2014-05-20 01:05:55 +02:00
Juergen Hoeller f524a5abe4 StringUtils.parseLocaleString parses variant correctly when variant contains country code
This commit also includes a JUnit 4 style revision of StringUtilsTests and ObjectUtilsTests.

Issue: SPR-11806
(cherry picked from commit 295a6ae)
2014-05-19 23:05:47 +02:00
Juergen Hoeller f053ce52ea Consistently log Class.getName() instead of Class.toString(), avoiding double class term in log message
Issue: SPR-11804
(cherry picked from commit 1120680)
2014-05-19 21:03:29 +02:00
Juergen Hoeller 5e05a84d81 Refined check for NoClassDefFoundError in getTestExecutionListeners()
Issue: SPR-11804
(cherry picked from commit a2ef2c9)
2014-05-19 17:55:58 +02:00
Juergen Hoeller c7b2ac7bac Backported proper updateAccessedAttributes test
Issue: SPR-11738
(cherry picked from commit 1bbc032)
2014-05-19 17:40:11 +02:00
Juergen Hoeller cbff8b01bb Javadoc fixes 2014-05-18 23:55:57 +02:00
Juergen Hoeller dc50001620 Additional tests for configuration class importing via ASM
Issue: SPR-11647
(cherry picked from commit 8c9116f)
2014-05-18 23:55:12 +02:00
Juergen Hoeller faaf43677d Servlet 3 multipart request implements getParameterNames defensively (for WebLogic 12 compatibility)
This commit also includes lazy resolution support for StandardServletMultipartResolver, along the lines of existing lazy mode in CommonsMultipartResolver.

Issue: SPR-11074
Issue: SPR-11730
(cherry picked from commit 82336c3)
2014-05-18 20:51:39 +02:00
Rossen Stoyanchev f6fddeb6eb Improve StringUtils.cleanPath
Issue: SPR-11793
2014-05-16 11:28:53 -04:00
Juergen Hoeller c3ba0a2c5b JmsResourceHolder checks for nested DataSource transactions as well (for Oracle AQ compatibility)
Issue: SPR-11791
(cherry picked from commit 5faacd5)
2014-05-16 16:55:10 +02:00
Juergen Hoeller 8fed2f0c6c Minor 3.2.x build polishing (including Tiles 3.0.4 upgrade) 2014-05-16 16:54:50 +02:00
Juergen Hoeller b0f7184f3f Polishing 2014-05-15 15:19:17 +02:00
Juergen Hoeller 3ae6c0f401 ResultSetWrappingSqlRowSet preserves first matching column per name (as defined in ResultSet's javadoc)
Issue: SPR-11786
(cherry picked from commit 0728e32)
2014-05-15 15:10:12 +02:00
Juergen Hoeller bc43f2e72a IdToEntityConverter defensively handles access to getDeclaredMethods
Issue: SPR-11758
(cherry picked from commit 381ccde)
2014-05-09 23:17:01 +02:00
Juergen Hoeller 759bb33665 Upgraded to propdeps plugin 0.0.6 and backported several build script refinements 2014-05-01 00:49:29 +02:00
Juergen Hoeller a139670286 Fixed invalid code tag in javadoc 2014-05-01 00:49:22 +02:00
Juergen Hoeller 1fe477a273 Upgraded to Gradle 1.12 and updated selected dependencies
(cherry picked from commit e84f61b)
2014-04-30 20:48:57 +02:00
Juergen Hoeller 0e710769c2 JRubyScriptUtils defensively handles null Nodes in findClassNode (fails against JRuby 1.7.12 otherwise)
Issue: SPR-11747
(cherry picked from commit adb616b)
2014-04-30 20:47:59 +02:00
Juergen Hoeller a5606a6c46 Polishing 2014-04-29 23:39:17 +02:00
Juergen Hoeller 3cb1cb5d2f ConfigurationClassParser considers EnvironmentAware on ImportBeanDefinitionRegistrars
Issue: SPR-11744
2014-04-29 22:02:18 +02:00
Juergen Hoeller 79820e449b ConfigurationClassEnhancer consistently uses registerStaticCallbacks in order to prevent memory leaks
Issue: SPR-9274
2014-04-29 21:59:12 +02:00
Juergen Hoeller 2f5d378d82 AbstractAdvisingBeanPostProcessor uses target class check for existing proxy but checks against actual exposed object otherwise (catching introductions)
Issue: SPR-11725
(cherry picked from commit a0658c5)
2014-04-29 21:49:09 +02:00
Juergen Hoeller 228a586efb AspectJExpressionPointcut defensively handles fallback expression parsing
Issue: SPR-9335
(cherry picked from commit ce4912b)
2014-04-29 21:45:19 +02:00
Juergen Hoeller b13c5b2378 GenericBeanDefinition's toString() takes parent definition into account
Issue: SPR-9671
(cherry picked from commit 0ef29b2)
2014-04-29 21:42:19 +02:00
Juergen Hoeller 779a6b79eb Polishing 2014-04-27 22:52:51 +02:00
Juergen Hoeller 9e2060707a General defensiveness about the bootstrap ClassLoader (i.e. null ClassLoader)
Issue: SPR-11721
2014-04-27 22:29:08 +02:00
Juergen Hoeller 2c1203dc9f AnnotationTypeFilter prevents ASM-based loading of java.* and javax.* interfaces as well
Issue: SPR-11719
2014-04-27 22:28:56 +02:00
Juergen Hoeller 6ee0596c3a SpringProperties falls back to ClassLoader.getSystemResource when loaded in bootstrap ClassLoader
Issue: SPR-11721
(cherry picked from commit 9cb5f48)
2014-04-27 22:28:08 +02:00
Juergen Hoeller 93d13cfcb1 AbstractMarshaller avoids SAXSource workaround when processExternalEntities=true
Issue: SPR-11737
2014-04-27 22:27:46 +02:00
Juergen Hoeller de80cd9b3b ASM 5.0.2 for correct Java 7 stack map frame computations
Issue: SPR-11656
2014-04-25 23:50:02 +02:00
Juergen Hoeller 470e9c8558 Configuration class processing explicitly skips java.* classes since we'll never find @Bean annotations there anyway
Issue: SPR-11718
2014-04-25 23:39:50 +02:00
Juergen Hoeller dc934064a2 @Bean processing explicitly ignores bridge methods (for method overrides with return type narrowing on JDK 8)
Issue: SPR-11718
2014-04-25 23:37:37 +02:00
Juergen Hoeller 5d5f70473a checkNotModified leniently handles IE-10-style If-Modified-Since values and silently proceeds if header value cannot be parsed at all
Issue: SPR-11727
(cherry picked from commit 794e859)
2014-04-25 23:33:10 +02:00
HejiaHo ac85eab372 Fix ConcurrentReferenceHashMap max constraints
Update calculateShift to respect the maximum upper bound as well as the
minimum value.

Issue: SPR-11720

(cherry picked from commit 16410cad)
2014-04-22 15:01:51 +01:00
Juergen Hoeller ffaac0ecf3 Polishing 2014-04-18 13:23:05 +02:00
Juergen Hoeller 5aa93674a3 Consistent documentation for both 'close' and 'shutdown' as inferred destroy methods
Issue: SPR-11680
(cherry picked from commit 14f9dbf)
2014-04-18 12:09:27 +02:00
Phillip Webb 62941b7937 Fixup .mailmap file
Fix a few issues with the `.mailmap` file.

(cherry picked from commit 3a5de00c)
2014-04-18 11:01:38 +01:00
Graham Lea 5fac6614b6 Added a Git .mailmap file
(cherry picked from commit a5e1932c)
2014-04-18 09:50:43 +01:00
Sam Brannen a169c0e727 Ensure Gradle does not execute inner classes as tests 2014-04-10 16:56:56 +02:00
Juergen Hoeller 94caaedf84 Polishing 2014-04-09 20:31:15 +02:00
Juergen Hoeller be6b54fe8b JBoss "vfszip" resources need to be treated as jar URLs
Issue: SPR-11676
2014-04-09 20:30:50 +02:00
Juergen Hoeller 9ac46a965f Java 8 bytecode compatibility for Spring 3.2.x
Issue: SPR-11656
2014-04-09 20:29:17 +02:00
Juergen Hoeller d8a0f7578d Commons Logging resolution failure with JasperReports 2.0.5 -> easiest way out: upgrade to JasperReports 3.7.6 (which in turn requires POI 3.6) 2014-04-02 22:59:42 +02:00
Juergen Hoeller 99a3e9cacb Revised ByteArrayOutputStream handling in MarshallingView and co
Issue: SPR-11646
(cherry picked from commit 8006696)
2014-04-02 22:56:34 +02:00
Juergen Hoeller f93bfa8f84 ResourceHttpRequestHandler explicitly closes a Resource's InputStream
Issue: SPR-11644
(cherry picked from commit 3a96f16)
2014-04-02 22:55:52 +02:00
Juergen Hoeller b80dc9d642 Polishing
Issue: SPR-11262
(cherry picked from commit d628025)
2014-04-02 22:55:33 +02:00
Sam Brannen b31750fafb Reinject Servlet mocks between TestNG test methods
Prior to this commit, if multiple test methods were executed in a
subclass of AbstractTestNGSpringContextTests annotated with
@WebAppConfiguration, then injected Servlet API mocks would only
reference the mocks created for the first test method. Subsequent test
methods could therefore never reference the current mocks, and there
was a discrepancy between the state of the injected mocks and the mock
set in the RequestContextHolder.

This commit addresses this issue by ensuring that dependencies
(including updated mocks) are injected into the test instance before
the next test method if the ServletTestExecutionListener resets the
request attributes in RequestContextHolder.

Issue: SPR-11626
(cherry picked from commit c38600762d)
2014-03-29 21:43:42 +01:00
Juergen Hoeller a4a2e80f23 Consider a null ClassLoader (typically the bootstrap CL) as cache-safe
Issue: SPR-11606
2014-03-26 23:48:29 +01:00
Juergen Hoeller e8c06c6d99 Consistent PropertyAccessor method order as declared in the interface
Issue: SPR-11609
(cherry picked from commit b70148c)
2014-03-26 21:57:40 +01:00
Juergen Hoeller d8180e1e20 Correctly resolve accessors for static properties on Class
Issue: SPR-11609
(cherry picked from commit 3af8a32)
2014-03-26 21:57:35 +01:00
Juergen Hoeller 88485dc1a7 Maintenance version updates (aligned with 4.0.3 release) 2014-03-26 21:12:25 +01:00
Juergen Hoeller a25d67770e Added expression test case for constant on Map
Issue: SPR-11609
2014-03-26 21:11:49 +01:00
Juergen Hoeller 5c9fc09852 Added Spring Data oriented conversion test case
Issue: SPR-11608
2014-03-26 20:50:00 +01:00
Juergen Hoeller e1602f7f83 AbstractApplicationEventMulticaster only caches if event type and source type are cache-safe
Issue: SPR-11606
(cherry picked from commit 3388573)
2014-03-26 20:34:55 +01:00
Juergen Hoeller 20228e78c5 CacheAspectSupport checks Cache.get(key) once per invocation only
Issue: SPR-11592
2014-03-26 00:21:39 +01:00
Juergen Hoeller 623b1fc0d5 Polishing 2014-03-25 00:37:01 +01:00
Juergen Hoeller a2bdc284f9 DispatcherServlet logs request URI in encoded form only
Issue: SPR-11591
(cherry picked from commit 465ca24)
2014-03-25 00:36:36 +01:00
Juergen Hoeller dbd5f67498 Consistently applied appropriate ByteArrayOutputStream initial capacities across the codebase
Issue: SPR-11594
(cherry picked from commit dd7f54c)
2014-03-25 00:35:33 +01:00
Juergen Hoeller ab85aa2096 BufferedImageHttpMessageConverter ignores empty MIME types
Issue: SPR-11581
(cherry picked from commit 90e3dbb)
2014-03-25 00:34:53 +01:00
Juergen Hoeller 5c3f6a1571 Revised naming for prototype inner beans to avoid excessive unique name calculation
Restored original singleton-only adaptInnerBeanName behavior, avoiding endless unique name calculation for every single prototype instance. Non-named inner BeanDefinition objects now suffixed with an identity hex code analogous to non-named XML bean definitions, largely avoiding naming collisions to begin with. After SPR-11246, post-processors can deal with unstable classes per bean name, so occasional collisions aren't a hard problem anymore.

Issue: SPR-11545
(cherry picked from commit 5308b3e)
2014-03-25 00:34:41 +01:00
Juergen Hoeller b73a43972e Upgraded to TestNG 6.8.8 and Hibernate 4.2.10 2014-03-11 21:36:44 +01:00
Juergen Hoeller 9585752693 Polishing 2014-03-11 21:36:10 +01:00
Juergen Hoeller 5c0fdb05bd AbstractFlashMapManager needs to decode parameter names
Also includes general alignment with the 4.0.3 versions of AbstractFlashMapManager and FlashMapManagerTests.

Issue: SPR-11504
2014-03-11 21:35:36 +01:00
Juergen Hoeller eeb82c409a SpEL property-not-found message hints at non-public method/field
Issue: SPR-11535
2014-03-11 10:47:53 +01:00
Juergen Hoeller d317b637e0 CollectionToCollectionConverter avoids collection copy for untyped collection when simply returning source anyway
Also uses addAll instead of iteration over untyped collection now, supporting optimized addAll in target collection type, and avoids repeated getElementTypeDescriptor calls.

Issue: SPR-11479
(cherry picked from commit bea94d5)
2014-03-10 18:48:01 +01:00
Stephane Nicoll b1bcc5d6eb Fix double SPeL evaluation of parameter
When a node of an SPeL expression was a call to a bean referenced
 in a method argument, the expression was resolved twice.

 The resolved arguments are now specified to MethodValueRef instead
 of resolving the arguments again in the constructor

 Issue: SPR-11445
(cherry picked from commit 519799e)
2014-03-07 14:59:41 +01:00
Juergen Hoeller f1ba789494 DefaultListableBeanFactory only puts 'cache-safe' Class keys into its by-type cache
Issue: SPR-11520
(cherry picked from commit 93c8b7a)
2014-03-07 14:58:51 +01:00
Juergen Hoeller d642cd21bb SpringBeanELResolver's setValue should not throw PropertyNotWritableException if provided value is identical to current bean instance
Issue: SPR-11502
(cherry picked from commit 7972b31)
2014-03-07 14:58:16 +01:00
Juergen Hoeller 70155e9ff9 KeyGenerators should not return a plain array parameter as raw key but rather always handle that case in a deepHashCode fashion
Issue: SPR-11505
(cherry picked from commit e50cff4)
2014-03-07 14:57:25 +01:00
Juergen Hoeller 7e2a214f32 instantiateUsingFactoryMethod avoids NPE and reports argument types in case of explicitArgs and resolved generic arguments as well
Issue: SPR-11517
(cherry picked from commit ad31777)
2014-03-07 14:56:45 +01:00
Juergen Hoeller 4c9c7634d0 Log4jWebConfigurer does not try to parse empty "log4jRefreshInterval" context-param
Issue: SPR-11507
(cherry picked from commit 9b77157)
2014-03-07 14:55:44 +01:00
Juergen Hoeller 69c54a053c Fixed content length check in XmlValidationModeDetector
Issue: SPR-11477
(cherry picked from commit 1763bfb)
2014-03-07 14:55:11 +01:00
Rossen Stoyanchev 4b9aad8f65 Refactor async result handling in Spring MVC Test
This change removes the use of a CountDownLatch to wait for the
asynchronously computed controller method return value. Instead we
check in a loop every 200 milliseconds if the result has been set.
If the result is not set within the specified amount of time to wait
an IllegalStateException is raised.

Additional changes:
 - Use AtomicReference to hold the async result
 - Remove @Ignore annotations on AsyncTests methods
 - Remove checks for the presence of Servlet 3

Issue: SPR-11516
2014-03-05 14:54:34 -05:00
Spring Buildmaster 5fe436c9a9 Next development version 2014-02-18 21:51:58 -08:00
Phillip Webb 082a564b9b Update changelog for 3.2.8 2014-02-18 20:58:34 -08:00
Rossen Stoyanchev fb0683c066 Add processExternalEntities support to OXM
Update OXM AbstractMarshaller to support processing of external
XML entities. By default external entities will not be processed.

Issue: SPR-11376
2014-02-18 16:01:20 -08:00
Phillip Webb 09c57203bb Fix memory leak in ConcurrentReferenceHashMap
Update ConcurrentReferenceHashMap to protect against references that
have been garbage collected but for some reason do not appear as a
`pollForPurge` result.

Also added purgeUnreferencedEntries() method to allow for programmatic
cleanup.

Issue: SPR-11440
(cherry picked from commit 2b4c81e6)
2014-02-18 15:18:26 -08:00
Juergen Hoeller 4886bf0708 Polishing 2014-02-14 23:46:22 +01:00
Juergen Hoeller 75e08695a0 Mixed polishing along with recent changes
(cherry picked from commit 14e5a02)
2014-02-14 23:27:09 +01:00
Juergen Hoeller 5da79ebca6 Related polishing
Issue. SPR-11428
(cherry picked from commit 9c6df76)
2014-02-14 23:21:29 +01:00
Juergen Hoeller bb7a1372c0 Avoid unnecessary getMappingForMethod repeat (in particular for RequestMappingInfo)
Issue. SPR-11428
(cherry picked from commit f913940)
2014-02-14 22:54:16 +01:00
Juergen Hoeller 7e3c722146 Objects with multi-threaded access should not lazily populate a hash field
Issue. SPR-11428
(cherry picked from commit 72fe7eb)
2014-02-14 22:53:13 +01:00
Juergen Hoeller d7591c6bd7 Clarified CompositeCacheManager's applicability, added convenience constructor with given delegates, and fixed getCacheNames implementation to never return duplicates
Issue: SPR-11427
(cherry picked from commit d550ffb)
2014-02-14 22:51:12 +01:00
Juergen Hoeller 42dec02203 EhCache/JCacheCacheManager needs to re-obtain runtime-added Cache reference for potential decoration
Issue: SPR-11407
(cherry picked from commit ef1748f)
2014-02-14 22:48:23 +01:00
Sam Brannen 27ad1990e3 Fix imports in SourceHttpMessageConverterTests
Replaced static import of org.junit.Assert.* with implicit imports in
order to avoid ambiguity between JUnit's static Assert methods and those
in org.custommonkey.xmlunit.XMLAssert.
2014-02-13 00:45:40 +01:00
Juergen Hoeller 337b5ff5d6 Actually upgraded to Gradle 1.11 2014-02-13 00:42:41 +01:00
Juergen Hoeller b40403cdc9 Polishing
Issue: SPR-11422
(cherry picked from commit 520ef9e)
2014-02-13 00:42:22 +01:00
Juergen Hoeller 0972582880 resolveFactoryMethodIfPossible considers nonPublicAccessAllowed and SecurityManager
Issue: SPR-11422
(cherry picked from commit 603cdea)
2014-02-13 00:42:16 +01:00
Sam Brannen bc879100c4 Test against CGLIB memory leak for method injection
This commit introduces a test in XmlBeanFactoryTests that verifies that
CGLIB generated subclasses for method injected beans are reused across
bean factories for identical bean definitions. In other words, by
verifying that the same CGLIB generated class is reused for identical
bean definitions, we can be certain that Spring is no longer generating
identical, duplicate classes that consume memory in the VM.

Issue: SPR-10785, SPR-11420
(cherry picked from commit f2a4537)
2014-02-13 00:31:13 +01:00
Sam Brannen 9f77ef4102 Exclude overloaded from equals & hashCode in MethodOverride
Prior to this commit, the inclusion of the 'overloaded' flag in the
implementations of equals() and hashCode() in MethodOverride could lead
to adverse effects in the outcome of equals() in AbstractBeanDefinition.

For example, given two bean definitions A and B that represent the
exact same bean definition metadata for a bean that relies on method
injection, if A has been validated and B has not, then A.equals(B) will
potentially return false, which is not acceptable behavior.

This commit addresses this issue by removing the 'overloaded' flag from
the implementations of equals() and hashCode() for MethodOverride.

Issue: SPR-11420
(cherry picked from commit 9534245)
2014-02-12 17:20:43 +01:00
Juergen Hoeller 7f95a27e6d Upgraded to Commons Logging 1.1.3 and Gradle 1.11 2014-02-12 15:15:41 +01:00
Juergen Hoeller 4ac4630b0b Polishing 2014-02-12 15:15:05 +01:00
Juergen Hoeller 29b40b9d0e Revised InvocableHandlerMethod exception handling
Issue: SPR-11281
(cherry picked from commit 1a1c72c)
2014-02-12 15:13:28 +01:00
Juergen Hoeller 85e336e6da Consistently avoid close() call on Servlet OutputStream
Issue: SPR-11413
(cherry picked from commit 5f1592a)
2014-02-12 15:12:43 +01:00
Juergen Hoeller b223e6efec MarshallingView should not close response OutputStream after copying to it
MarshallingView also explicitly skips BindingResult when searching for a model object now, implementing common custom subclass behavior out-of-the-box.

Issue: SPR-11411
Issue: SPR-11417
2014-02-12 15:12:35 +01:00
Juergen Hoeller d55a173e2e Fix issue w/ use of UrlPathHelper's urlDecode property
Before this change the getPathWithinServletMapping method of
UrlPathHelper could not work properly when a default servlet mapping
(i.e. "/") was used in combination with urlDecode=false. The fact that
the getServletPath() method of HttpServletRequest always returns a
decoded path was getting in the way.

Although there is no way to check Servlet mappings through the Servlet
API, this change aims to detect the given scenario and returns the full
path following the context path thus avoiding URL decoding.

Note that the same can be achieved by setting urlDecode=false and
alwaysUseFullPath=true. However this change ensures that urlDecode
works properly without having to know that.

Issue: SPR-11101
(cherry picked from commit 12598f8)
2014-02-12 15:06:00 +01:00
Juergen Hoeller 4d2d223b0c Revised ExcelViewTests 2014-02-09 01:26:26 +01:00
Juergen Hoeller c3d74b4521 Polishing 2014-02-09 00:45:55 +01:00
Juergen Hoeller 61ab40cd7a Upgraded to Commons FileUpload 1.3.1, TestNG 6.8.7, Hibernate 4.2.8, Joda-Time 2.2, Jackson 1.7.9 2014-02-09 00:45:07 +01:00
Juergen Hoeller 3da9a3193c Polishing
(cherry picked from commit 749b65b)
2014-02-07 18:04:14 +01:00
Juergen Hoeller 7e9cb5195a Fixed broken link to jax-ws-commons website
Issue: SPR-11404
2014-02-07 17:46:51 +01:00
Juergen Hoeller 4233d0a99e Removed outdated hibernate3 references across the codebase
Issue: SPR-9028
(cherry picked from commit 09e2e58)
2014-02-06 23:38:30 +01:00
Juergen Hoeller ad91610796 Polishing
(cherry picked from commit 426f52b)
2014-02-06 23:27:46 +01:00
Juergen Hoeller f558396e91 Introduced SpringNamingPolicy for CGLIB
Issue: SPR-11398
(cherry picked from commit 8c4e372)
2014-02-06 23:25:52 +01:00
Sebastien Deleuze a2ec8f864e Fix EvalTagTests with locales other than English
Issue: SPR-11392
(cherry picked from commit edb0b0e)
2014-02-05 23:27:19 +01:00
Sam Brannen 03e243a4ab Fix off-by-one regression in AbstractMethodMockingControl
Issue: SPR-11385, SPR-10885
(cherry picked from commits 69a89b1 and 3a89bc4)
2014-02-04 23:56:04 +01:00
Juergen Hoeller 60b24cffdb Related polishing
Issue: SPR-11386
(cherry picked from commit 6634c19)
2014-02-04 16:53:50 +01:00
Juergen Hoeller 036bd791f0 Introduced "spring.jdbc.getParameterType.ignore" property
Issue: SPR-11386
(cherry picked from commit 60c1905)
2014-02-04 16:53:44 +01:00
Juergen Hoeller a53df0b2c1 Added explicit tests for generic and raw collection converters
Issue: SPR-11369
2014-02-01 19:36:38 +01:00
Juergen Hoeller 1a011616d9 Polishing
Issue: SPR-11369
2014-02-01 12:12:19 +01:00
Juergen Hoeller 3af9d1f29b Consistent iteration over actualValue in Velocity and FreeMarker macros
This requires consistent exposure of an actualValue in BindStatus, even if no BindingResult available.

Issue: SPR-10837
(cherry picked from commit 4f60b98)
2014-02-01 11:09:28 +01:00
Juergen Hoeller b3fb81bf72 Defensively handle ServletRequestAttributes casting in requestDestroyed callback
Issue: SPR-11378
(cherry picked from commit 5f24294)
2014-02-01 11:07:33 +01:00
Juergen Hoeller dd5af764b5 Avoided unnecessary substring creation for field error access with wildcard
Issue: SPR-11374
(cherry picked from commit 5be8301)
2014-01-31 13:20:59 +01:00
Juergen Hoeller 3ffbb24211 Fixed isMatchingFieldError to properly handle empty field name
Issue: SPR-11374
2014-01-30 23:20:41 +01:00
Juergen Hoeller 4c385f0073 Fixed LiveBeansView to not produce invalid JSON if last bean is not eligible
Also introducing overridable isBeanEligible template method.

Issue: SPR-11366
(cherry picked from commit c1eac20)
2014-01-30 12:32:35 +01:00
Spring Buildmaster 7d527f9771 Next development version 2014-01-28 14:38:50 -08:00
Phillip Webb 3ba7ab15ab Update changelog 2014-01-28 13:53:01 -08:00
Juergen Hoeller 36ab65ace7 Dropped explicit paragraph on web.xml version declaration
Issue: SPR-11364
2014-01-28 17:32:08 +01:00
Juergen Hoeller 35753eb54d Backported test for fallback for non-resolvable property type
(cherry picked from commit 8570f60)
2014-01-28 17:25:12 +01:00
Brian Clozel 1cb9b9cf52 Add RestTemplate constructor with custom converters
Prior to this commit, RestTemplate's constructors were all initializing
default HTTPMessageConverters. Its API provides a way to replace
those converters with custom ones, but default converters are already
defined and initialized at that point, which can be an issue in some
cases (performance, classpath...).

This commits adds a new constructor for RestTemplate with a list
of message converters as argument. With this new constructor,
default message converters are never initialized.

Issue: SPR-11351
(cherry picked from commit 425e5a0)
2014-01-28 12:41:36 +01:00
Juergen Hoeller fe4b57c199 Fixed 'globalJobListeners'/'globalTriggerListeners' to work with Quartz 2.0 & 2.1 as well
Issue: SPR-11362
(cherry picked from commit c719c70)
2014-01-28 12:41:29 +01:00
Juergen Hoeller 2a3b29f98e Upgraded to SLF4J 1.6.6 2014-01-28 01:46:41 +01:00
Juergen Hoeller d26a570192 Polishing 2014-01-28 01:46:19 +01:00
Juergen Hoeller ac3c670f70 Fixed type resolution in case of inconsistencies between read and write method
Issue: SPR-11361
2014-01-28 01:20:27 +01:00
Juergen Hoeller 398f91cb74 Polishing 2014-01-27 22:49:14 +01:00
Juergen Hoeller b4115f3202 Downgraded JOpt build dependency to 3.3
Avoiding accidental use of OptionSet.specs(), as introduced in the JOpt 4.x line.
2014-01-27 22:15:54 +01:00
Juergen Hoeller 7e2167fd17 Specific deprecations and consistent setter varargs in Hibernate support
Issue: SPR-11291
2014-01-27 22:11:58 +01:00
Juergen Hoeller 09ad8347be Downgraded Commons Pool dependency to 1.5.7
Commons Pool 1.6 introduced generics in its APIs, leading to either a 1.6 dependency at runtime or a load of raw type warnings in our CommonsPoolTargetSource.
2014-01-26 00:41:59 +01:00
Juergen Hoeller 2ef39a5666 Consistently declare @SuppressWarnings("serial") instead of dummy serialVersionUID
(cherry picked from commit 56b7d7a)
2014-01-26 00:37:09 +01:00
Juergen Hoeller 1a2033eb41 Compatibility with JOpt 4.6
JOpt 4.6 redeclared its nonOptionArguments() method from List<String> to List<?>, requiring us to select String arguments only as we do for regular option values already.

Issue: SPR-11359
(cherry picked from commit 67e76e9)
2014-01-26 00:37:03 +01:00
Juergen Hoeller 6162917b4e Consistently switched optional dependencies to scope 'optional'; consistently grouped dependency scopes; minor dependency version updates 2014-01-25 22:12:16 +01:00
Juergen Hoeller e07ad5a19b Polishing 2014-01-25 00:15:00 +01:00
Juergen Hoeller 5307a87d1a Polishing
Issue: SPR-11357
2014-01-24 19:19:32 +01:00
Juergen Hoeller 87179b075b Optimized Introspector.flushFromCaches calls to skip Object.class
Issue: SPR-11356
2014-01-24 19:18:39 +01:00
Juergen Hoeller 23249cda98 Added test for SpringProperties setFlag method
Issue: SPR-9014
Issue: SPR-11297
2014-01-24 17:48:40 +01:00
Juergen Hoeller 341d645d09 Polishing
Issue: SPR-11357
2014-01-24 17:46:56 +01:00
Juergen Hoeller 9845d9eb21 Allow consolidating config in root context with Java
Issue: SPR-11357
(backported from 4.0.1)
2014-01-24 17:46:31 +01:00
Juergen Hoeller edb660863b Polishing 2014-01-24 16:59:42 +01:00
Juergen Hoeller 866c7847e3 Introduced SpringProperties class and optional "spring.properties" file
This in particular allows for specifying "spring.getenv.ignore" and "spring.beaninfo.ignore" in a local way within the application, in case that JVM-level system properties are locked.

Issue: SPR-9014
Issue: SPR-11297
(cherry picked from commit 8543b91)
2014-01-24 16:58:16 +01:00
Juergen Hoeller fc361844ec Polishing
Issue: SPR-11297
2014-01-22 23:57:48 +01:00
Juergen Hoeller 52d050d21a Factored out "suppressGetenvAccess()" method
Issue: SPR-11297
2014-01-22 23:57:36 +01:00
Sam Brannen c1569d7ecd Handle NoClassDefFoundError consistently for TELs
Prior to this commit, a NoClassDefFoundError caught in
TestContextManager's retrieveTestExecutionListeners() method would be
handled differently for implicit default listeners (i.e., listeners not
declared via @TestExecutionListeners) and listeners explicitly declared
via @TestExecutionListeners. Specifically, a NoClassDefFoundError would
cause a test to fail for an explicitly declared TestExecutionListener
but not for an implicitly declared one.

This commit addresses this issue by:

 - Always swallowing a NoClassDefFoundError for both implicitly and
   explicitly declared TestExecutionListeners.
 - Changing the log level from DEBUG to INFO to make such situations
   more visible to the average end user.

Issue: SPR-11347

Backport-Commit: fb12e234fc
2014-01-22 23:40:56 +01:00
Juergen Hoeller fdd31c0e66 Preserve visitBeanDefinition stacktrace in BeanDefinitionStoreException
Issue: SPR-11346
2014-01-22 22:40:10 +01:00
Juergen Hoeller cfa78a9b25 Quick paragraph on mvc namespace and matrix variables
Issue: SPR-11331
2014-01-22 22:37:22 +01:00
Juergen Hoeller d434ef9713 Polishing
Issue: SPR-11344
2014-01-22 18:23:59 +01:00
Juergen Hoeller c406c56d57 Avoid class loading during AspectJ expression evaluation
Fixed through downcasting to AspectJ's ReflectionType and ReflectionBasedReferenceTypeDelegate, obtaining the myClass field there. We only fall back to regular class loading if we encounter any other kind of type.

Issue: SPR-11344
2014-01-22 18:23:09 +01:00
Juergen Hoeller d9ab6aaf6c Revised RootBeanDefinition's externallyManaged* Sets to rely on postProcessingLock
This allows us to avoid early initialization of footprint-heavy ConcurrentHashMaps, and reuses the existing postProcessingLock which will typically be active already when registerExternallyManaged* calls come in from the bean factory's post-processing phase.

Issue: SPR-11343
(cherry picked from commit a599b57)
2014-01-22 14:48:26 +01:00
Juergen Hoeller aa1babdfde Fixed setDeliveryPersistent javadoc
Issue: SPR-3983
(cherry picked from commit 9cc86a3)
2014-01-21 17:13:33 +01:00
Juergen Hoeller 09c9137b75 Removed accidental backport of StAX code in 3.2.5 (restoring Java 5 compatibility)
Issue: SPR-11341
2014-01-21 17:12:22 +01:00
Sam Brannen 603d79ac9b Include ServletTEL in abstract base test classes
The ServletTestExecutionListener is now prepended to the set of default
listeners in AbstractJUnit4SpringContextTests and
AbstractTestNGSpringContextTests.

Issue: SPR-11340

Backport-Commit: 3370f8b1b1
2014-01-21 15:18:59 +01:00
Sam Brannen fdac4a7d18 Ensure all tests in spring-test are executed
Prior to this commit TestNG tests would only be executed by the Gradle
build if they were located in the “testng” package. Tests in subpackages
would therefore be omitted from the build.

This commit ensures that all TestNG classes in the “testng” package and
any of its subpackages are executed in the Gradle build.

Furthermore, this commit ensures that the JUnit-based
FailingBeforeAndAfterMethodsTests test class is executed along with the
other JUnit tests even though it resides under the “testng” package.

Issue: SPR-11338

Backport-Commit: 098d7c7465
2014-01-21 15:16:55 +01:00
Juergen Hoeller 11ef4308b8 Polishing 2014-01-21 01:55:09 +01:00
Juergen Hoeller e0f9a85955 Locale/ThemeChangeInterceptor alignment and javadoc polishing
Issue: SPR-11128
(cherry picked from commit 5e5add4)
2014-01-21 01:39:02 +01:00
Juergen Hoeller b229d54172 Consistent evaluation of empty theme names to default theme name
Issue: SPR-11128
(cherry picked from commit cc81aae)
2014-01-21 01:38:03 +01:00
Juergen Hoeller c77832ba6d Added info-level logging for default unit detection
Issue: SPR-11333
(cherry picked from commit 88730bd)
2014-01-21 01:36:50 +01:00
Juergen Hoeller 59893d1f13 Fixed assert in setAspectJAdvisorFactory()
Issue: SPR-11330
(cherry picked from commit f15a5fe)
2014-01-21 01:34:47 +01:00
Juergen Hoeller 9aefa0334f Polishing 2014-01-16 18:28:50 +01:00
Juergen Hoeller f532607d4b Introduced customizeConnection callbacks for URLConnection used by exists() / contentLength() / lastModified()
Issue: SPR-11320
(cherry picked from commit 4f45ad5)
2014-01-16 17:54:44 +01:00
Juergen Hoeller 16bf501b30 Polishing 2014-01-16 17:53:26 +01:00
Juergen Hoeller fd13c994c9 Fixed accidental use of String.isEmpty in SimpleCommandLineArgsParser
Issue: SPR-11321
2014-01-16 17:35:49 +01:00
Juergen Hoeller 1f60738431 checkNotModified needs to consider HEAD as well
Issue: SPR-11317
(cherry picked from commit 17cc63e)
2014-01-15 23:47:16 +01:00
Juergen Hoeller 68b1eb1aba Polishing 2014-01-15 23:46:52 +01:00
Juergen Hoeller 5fb2665d1c Introduced "globalInitializerClasses" next to the existing "contextInitializerClasses", applying to FrameworkServlets as well
Issue: SPR-11314
(cherry picked from commit 91881ff)
2014-01-15 23:46:04 +01:00
Juergen Hoeller 52c11eab41 Polishing
(cherry picked from commit e670f4e)
2014-01-15 17:54:37 +01:00
Juergen Hoeller b6362c5016 Introduced "spring.getenv.ignore" system property for preventing System.getenv calls
Issue: SPR-11297
(cherry picked from commit 961f42b)
2014-01-15 17:52:36 +01:00
Juergen Hoeller 6deb597cdf Removed Commons Lang references and refined Java 5+ implementation details 2014-01-15 15:56:03 +01:00
Juergen Hoeller bfecbaf88e Clarified ArgsMatchKind deprecation 2014-01-15 15:46:46 +01:00
Juergen Hoeller 3429a4186c Polishing 2014-01-15 15:16:01 +01:00
Juergen Hoeller f18debb5a3 Fixed getTypeDifferenceWeight algorithm in ReflectionHelper, and deprecated ArgsMatchKind enum (for removal in 4.0)
Issue: SPR-11306
2014-01-15 15:15:39 +01:00
Juergen Hoeller 62fd12c527 Restored Java 5 compatibility through avoiding Collections.newSetFromMap
Issue: SPR-11313
2014-01-15 14:14:50 +01:00
Juergen Hoeller f8f6c5fd89 Polishing 2014-01-13 23:49:39 +01:00
Juergen Hoeller 354917c53d Polishing (backports from 4.0.1) 2014-01-13 23:36:33 +01:00
Juergen Hoeller 1e0bf493cc Backported generics/varargs signature refinements for scripting package 2014-01-13 23:30:21 +01:00
Juergen Hoeller 0ea4f8ecb7 Fixed resolveProxyTargetClass exception message 2014-01-13 23:21:33 +01:00
Juergen Hoeller 139adba96a Removed TestGroup.LONG_RUNNING marker from Groovy and JRuby tests 2014-01-13 23:21:16 +01:00
Juergen Hoeller 7502ecd35e CronTriggerFactoryBean allows 'calendarName' and 'description' to be specified
Also making 'description' available on SimpleTriggerFactoryBean.

Issue: SPR-9771
2014-01-13 23:18:31 +01:00
Juergen Hoeller 477e60f28a Add minor optimization to AbstractErrors
Issue: SPR-11304
2014-01-13 23:15:50 +01:00
Juergen Hoeller 3db6a7f715 Add method for HTTP PATCH in MockMvcRequestBuilders
Issue: SPR-11299
2014-01-13 23:14:52 +01:00
Juergen Hoeller 0606c98277 Polishing (along with the Tiles 2.2.2 upgrade in the Spring 4.0 line)
Issue: SPR-11285
2014-01-06 00:43:41 +01:00
Juergen Hoeller dbfe68a6dc Further polishing
Issue: SPR-10940
2014-01-05 22:08:02 +01:00
Juergen Hoeller ab6c6b104d Consistent support for setStartTime in CronTrigger(Factory)Bean and SimpleTrigger(Factory)Bean, and consistent declaration of varargs in scheduling.quartz package
Issue: SPR-10940
(cherry picked from commit b228a06)
2014-01-05 18:03:54 +01:00
Juergen Hoeller c2459b4a61 Full Quartz 2.2 support, including LocalDataSourceJobStore
While we've had basic Quartz 2.2 support before, a few details were missing:
* LocalDataSourceJobStore's ConnectionProvider adapters need to provide an empty implementation of Quartz 2.2's new initialize method.
* SchedulerFactoryBean's "schedulerContextMap" needs to be explicitly declared with String keys, otherwise it can't be compiled against Quartz 2.2 (forward compatibility once we're dropping Quartz 1.x support). This doesn't hurt against older Quartz versions either, since the keys need to be Strings anyway.

Issue: SPR-11284
(cherry picked from commit 38a8ace)
2014-01-05 18:03:27 +01:00
Juergen Hoeller 4f24643fd3 Upgraded selected build dependencies to early 2013 releases 2014-01-05 02:47:44 +01:00
Juergen Hoeller 1a0a381559 Made findMethodAnnotationOnBridgeMethod compatible with Java 8 2014-01-05 02:30:04 +01:00
Juergen Hoeller 8c8eead667 Removed AbstractAsyncConfiguration's abstract "asyncAdvisor" method for Java 8 compatibility (to avoid method overloading problem for configuration classes) 2014-01-05 02:28:27 +01:00
Juergen Hoeller b35050caf2 Fixed Jackson2ObjectMapperFactoryBean class name in javadoc examples 2014-01-05 02:24:13 +01:00
Juergen Hoeller 72a5737ab9 Polishing 2014-01-05 00:02:54 +01:00
Juergen Hoeller be2d915cc2 Consistent equals/hashCode/toString implementations in AnnotationMatchingPointcut/ClassFilter/MethodMatcher
Issue: SPR-11275
Issue: SPR-11276
(cherry picked from commit 0de307b)
2014-01-05 00:02:47 +01:00
Juergen Hoeller 6045914057 Polishing 2014-01-03 23:02:51 +01:00
Juergen Hoeller 78646f1f32 Activated through rename to *Tests, and added method call interaction tests
Issue: SPR-7831
(cherry picked from commit 3bed6cf)
2014-01-03 23:02:18 +01:00
Juergen Hoeller f88cbda6ef Introduced "spring.beaninfo.ignore" system property for optimized Introspector usage
Issue: SPR-9014
2014-01-03 14:14:10 +01:00
Juergen Hoeller c48da0d9a4 Avoid hard reference to LocalValidatorFactoryBean in <mvc:annotation-driven> parser
Issue: SPR-11272
2014-01-03 12:18:49 +01:00
Juergen Hoeller e3344898cd Support varargs for DomUtils.getChildElementsByTagName
Issue: SPR-11272
2014-01-03 12:18:19 +01:00
Juergen Hoeller 2e123b01e5 Polishing
Issue: SPR-11259
(cherry picked from commit f0d2151)
2014-01-01 19:24:37 +01:00
Juergen Hoeller 57eedf33d6 Refined logging to include target class for each transactional method name
Also simplified cache key 'hashCode' implementation, relying on 'equals' to differentiate between same method on different target classes.

Issue: SPR-11267
(cherry picked from commit 82ea9ec)
2014-01-01 19:18:39 +01:00
Juergen Hoeller f477a024ad EhCacheFactoryBean does not call set(Sampled)StatisticsEnabled on EhCache 2.7/2.8
Issue: SPR-11265
(cherry picked from commit 73d8f06)
2014-01-01 19:18:12 +01:00
Juergen Hoeller 5dddb492b8 Polishing around @Enable processing and @EnableTransactionManagement
Issue: SPR-11251
2013-12-23 23:09:00 +01:00
Juergen Hoeller ecee20f1fe @Enable registrars called with correct metadata when placed on superclass
Issue: SPR-11251
2013-12-23 23:07:59 +01:00
Juergen Hoeller e08f743301 ResourceDatabasePopulator's setScripts takes varargs
(cherry picked from commit e3017c3)
2013-12-23 23:05:34 +01:00
Juergen Hoeller a05c957d0e Polishing
Issue: SPR-11254
(cherry picked from commit 9a39f39)
2013-12-23 23:05:10 +01:00
Juergen Hoeller a2de329db9 Revised XMLEventStreamWriter to allow for empty elements with attributes
Issue: SPR-11254
(cherry picked from commit ee5b7fd)
2013-12-23 23:04:58 +01:00
Juergen Hoeller 551364f668 Polishing 2013-12-20 00:40:14 +01:00
Juergen Hoeller 08aa22ff1f InjectionMetadata caching per bean name needs to refresh when bean class changes
Issue: SPR-11246
2013-12-20 00:15:09 +01:00
Juergen Hoeller a115a7dad5 Revised BeanInfoFactory javadoc
Issue: SPR-9014
2013-12-20 00:09:49 +01:00
Juergen Hoeller f457319965 Consistent non-declaration of serialVersionUID 2013-12-20 00:06:40 +01:00
Juergen Hoeller 7ad6df8c75 Moved AnnotationBeanNameGenerator's String value check right before cast
Issue: SPR-11221
2013-12-20 00:02:27 +01:00
Juergen Hoeller f5d5882f46 Fixed @Bean meta-annotation detection when using ASM
This turned out to be a bug in the ASM-based AnnotationMetadata implementation where has/getAnnotatedMethods didn't consider meta-annotations., in contrast to its StandardAnnotationMetadata sibling.

Issue: SPR-10488
(cherry picked from commit 105e176)
2013-12-16 23:09:07 +01:00
Juergen Hoeller 0a4d28d5d5 Fixed primitive type assignability in BeanUtils.copyProperties
Issue: SPR-11231
(cherry picked from commit 8a3b4c6)
2013-12-16 22:57:50 +01:00
Spring Buildmaster 9002742873 Next development version 2013-12-12 01:07:15 -08:00
441 changed files with 10818 additions and 7243 deletions
+14
View File
@@ -0,0 +1,14 @@
Juergen Hoeller <jhoeller@vmware.com> jhoeller <jhoeller@vmware.com>
<rstoyanchev@gopivotal.com> <rstoyanchev@vmware.com>
<pwebb@gopivotal.com> <pwebb@vmware.com>
<cbeams@gopivotal.com> <cbeams@vmware.com>
<cbeams@gopivotal.com> <cbeams@gmail.com>
<apoutsma@gopivotal.com> <apoutsma@vmware.com>
<apoutsma@gopivotal.com> <poutsma@mac.com>
<ogierke@gopivotal.com> <ogierke@vmware.com>
<dsyer@gopivotal.com> <david_syer@hotmail.com>
<dsyer@gopivotal.com> <dsyer@vmware.com>
<aclement@gopivotal.com> <andrew.clement@gmail.com>
<aclement@gopivotal.com> <aclement@vmware.com>
<dmitry.katsubo@gmail.com> <dmitry.katsubo@gmai.com>
Nick Williams <nicholas@nicholaswilliams.net> Nicholas Williams <nicholas@nicholaswilliams.net>
+196 -184
View File
@@ -3,8 +3,8 @@ buildscript {
maven { url "http://repo.springsource.org/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.4")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.7")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.6")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.8")
}
}
@@ -12,15 +12,10 @@ configure(allprojects) { project ->
group = "org.springframework"
version = qualifyVersionIfNecessary(version)
// The following is a work-around for allowing to build on JDK 8 until the
// Gradle build uses Ant 1.9.x by default. This is necessary to avoid the
// "Class not found: javac1.8" issue with Ant versions prior to 1.9.x
ant.properties["build.compiler"] = "javac1.7"
ext.aspectjVersion = "1.7.2"
ext.aspectjVersion = "1.7.4"
ext.hsqldbVersion = "1.8.0.10"
ext.junitVersion = "4.11"
ext.slf4jVersion = "1.6.1"
ext.slf4jVersion = "1.6.6"
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
apply plugin: "propdeps"
@@ -64,12 +59,16 @@ configure(allprojects) { project ->
systemProperty("java.awt.headless", "true")
systemProperty("testGroups", project.properties.get("testGroups"))
scanForTestClasses = false
include '**/*Tests.*'
exclude '**/*Abstract*.*'
// Do not include "**/*Test.class" since some *Test classes are broken.
include(["**/*Tests.class"])
// Since we set scanForTestClasses to false, we need to filter out inner
// classes with the "$" pattern; otherwise, using -Dtest.single=MyTests to
// run MyTests by itself will fail if MyTests contains any inner classes.
exclude(["**/Abstract*.class", '**/*$*'])
}
repositories {
maven { url "http://repo.springsource.org/libs-release" }
maven { url "http://repo.spring.io/libs-release" }
}
dependencies {
@@ -79,7 +78,7 @@ configure(allprojects) { project ->
}
ext.javadocLinks = [
"http://docs.oracle.com/javase/6/docs/api/",
"http://docs.oracle.com/javase/7/docs/api/",
"http://docs.oracle.com/javaee/6/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
@@ -90,15 +89,17 @@ configure(allprojects) { project ->
"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/",
"http://ibatis.apache.org/docs/java/dev/",
"http://hc.apache.org/httpclient-3.x/apidocs/",
"http://aopalliance.sourceforge.net/doc/",
"http://www.eclipse.org/aspectj/doc/released/aspectj5rt-api/",
"http://ehcache.org/apidocs/",
"http://quartz-scheduler.org/api/2.1.5/",
"http://jackson.codehaus.org/1.4.2/javadoc/",
"http://fasterxml.github.com/jackson-core/javadoc/2.0.1/",
"http://quartz-scheduler.org/api/2.2.0/",
"http://jackson.codehaus.org/1.9.4/javadoc/",
"http://fasterxml.github.com/jackson-core/javadoc/2.3.0/",
"http://fasterxml.github.com/jackson-databind/javadoc/2.3.0/",
"http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs",
"http://ibatis.apache.org/docs/java/dev/"
] as String[]
}
@@ -127,7 +128,7 @@ configure(subprojects - project(":spring-build-src")) { subproject ->
options.author = true
options.header = project.name
options.links(project.ext.javadocLinks)
if(JavaVersion.current().isJava8Compatible()) {
if (JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
@@ -169,14 +170,14 @@ project("spring-build-src") {
project("spring-core") {
description = "Spring Core"
// As of Spring 3.2 spring-core repackages both asm 4.0 and cglib 3.0 and inlines both
// into the spring-core jar. cglib 3.0 itself depends on asm 4.0, and is therefore
// As of Spring 3.2.9, spring-core repackages asm 5.0 and cglib 3.1, inlining both
// into the spring-core jar. cglib 3.1 itself depends on asm 4+, and is therefore
// further transformed by the JarJar task to depend on org.springframework.asm; this
// avoids including two different copies of asm unnecessarily. If however future cglib
// versions drift from the version of asm used by Spring internally, this duplication
// will become necessary.
def asmVersion = "4.0"
def cglibVersion = "3.0"
def asmVersion = "5.0.2"
def cglibVersion = "3.1"
configurations {
jarjar
@@ -233,9 +234,9 @@ project("spring-core") {
compile(files(cglibRepackJar))
compile(files(asmRepackJar))
compile("commons-logging:commons-logging:1.1.1")
compile("commons-logging:commons-logging:1.1.3")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("net.sf.jopt-simple:jopt-simple:3.0")
optional("net.sf.jopt-simple:jopt-simple:3.3")
optional("log4j:log4j:1.2.17")
testCompile("xmlunit:xmlunit:1.3")
testCompile("org.codehaus.woodstox:wstx-asl:3.2.7") {
@@ -262,8 +263,8 @@ project("spring-beans") {
dependencies {
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
provided("javax.el:el-api:1.0")
provided("javax.inject:javax.inject:1")
optional("javax.el:el-api:1.0")
optional("javax.inject:javax.inject:1")
testCompile("log4j:log4j:1.2.17")
}
}
@@ -272,13 +273,13 @@ project("spring-aop") {
description = "Spring AOP"
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
compile(project(":spring-beans"))
compile("aopalliance:aopalliance:1.0")
optional("com.jamonapi:jamon:2.4")
optional("commons-pool:commons-pool:1.5.3")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("commons-pool:commons-pool:1.5.7")
optional("com.jamonapi:jamon:2.4")
}
}
@@ -314,28 +315,27 @@ project("spring-context") {
description = "Spring Context"
dependencies {
optional(project(":spring-instrument"))
compile(project(":spring-aop"))
compile(project(":spring-beans"))
compile(project(":spring-expression"))
compile(project(":spring-core"))
compile(files(project(":spring-core").cglibRepackJar))
optional("backport-util-concurrent:backport-util-concurrent:3.0")
optional("javax.ejb:ejb-api:3.0")
optional(project(":spring-instrument"))
optional("javax.inject:javax.inject:1")
optional("javax.ejb:ejb-api:3.0")
optional("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
optional("backport-util-concurrent:backport-util-concurrent:3.0")
optional("javax.persistence:persistence-api:1.0")
optional("org.beanshell:bsh:2.0b4")
optional("org.codehaus.groovy:groovy-all:1.8.8")
optional("org.jruby:jruby:1.6.5.1")
optional("joda-time:joda-time:2.1")
optional("org.slf4j:slf4j-api:${slf4jVersion}")
optional("javax.validation:validation-api:1.0.0.GA")
optional("org.hibernate:hibernate-validator:4.3.0.Final")
optional("org.hibernate:hibernate-validator:4.3.1.Final")
optional("joda-time:joda-time:2.2")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
testCompile("commons-dbcp:commons-dbcp:1.2.2")
optional("org.codehaus.groovy:groovy-all:1.8.9")
optional("org.beanshell:bsh:2.0b4")
optional("org.jruby:jruby:1.7.12")
testCompile("javax.inject:javax.inject-tck:1")
testCompile("commons-dbcp:commons-dbcp:1.3")
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
}
// pick up RmiInvocationWrapperRTD.xml in src/main
@@ -350,17 +350,17 @@ project("spring-tx") {
description = "Spring Transaction"
dependencies {
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
optional(project(":spring-aop"))
compile(project(":spring-beans"))
compile(project(":spring-core"))
compile("aopalliance:aopalliance:1.0")
provided("com.ibm.websphere:uow:6.0.2.17")
optional("javax.resource:connector-api:1.5")
optional(project(":spring-aop"))
optional(project(":spring-context")) // for JCA, @EnableTransactionManagement
optional("aopalliance:aopalliance:1.0")
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
optional("javax.resource:connector-api:1.5")
optional("javax.ejb:ejb-api:3.0")
testCompile("javax.persistence:persistence-api:1.0")
optional("com.ibm.websphere:uow:6.0.2.17")
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
testCompile("javax.persistence:persistence-api:1.0")
}
}
@@ -378,14 +378,24 @@ project("spring-oxm") {
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional("org.codehaus.castor:castor-xml:1.3.3") {
exclude group: 'stax', module: 'stax-api'
exclude group: "org.springframework", module: "spring-context"
}
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
exclude group: 'stax', module: 'stax-api'
}
optional("com.thoughtworks.xstream:xstream:1.4.7") {
exclude group: 'xpp3', module: 'xpp3_min'
exclude group: 'xmlpull', module: 'xmlpull'
}
optional("org.jibx:jibx-run:1.2.5")
testCompile(project(":spring-context"))
optional("com.thoughtworks.xstream:xstream:1.3.1")
optional("org.jibx:jibx-run:1.2.3")
optional("org.apache.xmlbeans:xmlbeans:2.4.0")
optional("org.codehaus.castor:castor-xml:1.3.2")
testCompile("org.codehaus.jettison:jettison:1.0.1")
testCompile("xmlunit:xmlunit:1.3")
testCompile("xmlpull:xmlpull:1.1.3.4a")
testCompile("org.codehaus.jettison:jettison:1.0.1") {
exclude group: 'stax', module: 'stax-api'
}
testCompile(files(genCastor.classesDir).builtBy(genCastor))
testCompile(files(genJaxb.classesDir).builtBy(genJaxb))
testCompile(files(genXmlbeans.classesDir).builtBy(genXmlbeans))
@@ -401,13 +411,13 @@ project("spring-jms") {
compile(project(":spring-aop"))
compile(project(":spring-context"))
compile(project(":spring-tx"))
optional(project(":spring-oxm"))
compile("aopalliance:aopalliance:1.0")
provided("org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1")
optional(project(":spring-oxm"))
optional("aopalliance:aopalliance:1.0")
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
optional("javax.resource:connector-api:1.5")
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
}
}
@@ -415,16 +425,16 @@ project("spring-jdbc") {
description = "Spring JDBC"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans"))
optional(project(":spring-context")) // for JndiDataSourceLookup
compile(project(":spring-core"))
compile(project(":spring-tx"))
optional(project(":spring-context")) // for JndiDataSourceLookup
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
optional("c3p0:c3p0:0.9.1.2")
optional("hsqldb:hsqldb:${hsqldbVersion}")
optional("com.h2database:h2:1.0.71")
optional("com.h2database:h2:1.0.79")
optional("org.apache.derby:derby:10.5.3.0_1")
optional("org.apache.derby:derbyclient:10.5.3.0_1")
optional("org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1")
}
}
@@ -435,23 +445,23 @@ project("spring-context-support") {
compile(project(":spring-core"))
compile(project(":spring-beans"))
compile(project(":spring-context"))
provided("javax.activation:activation:1.1")
optional(project(":spring-jdbc")) // for Quartz support
optional(project(":spring-tx")) // for Quartz support
optional("javax.mail:mail:1.4")
optional("javax.mail:mail:1.4.7")
optional("javax.cache:cache-api:0.5")
optional("net.sf.ehcache:ehcache-core:2.0.0")
optional("opensymphony:quartz:1.6.2")
optional("net.sf.ehcache:ehcache-core:2.0.1")
optional("org.quartz-scheduler:quartz:1.7.3")
optional("org.codehaus.fabric3.api:commonj:1.1.0")
optional("velocity:velocity:1.5")
optional("org.freemarker:freemarker:2.3.15")
optional("org.freemarker:freemarker:2.3.20")
optional("com.lowagie:itext:2.1.7")
optional("jasperreports:jasperreports:2.0.5")
optional("org.slf4j:slf4j-api:${slf4jVersion}")
provided("javax.activation:activation:1.1")
testCompile("org.apache.poi:poi:3.0.2-FINAL")
optional("net.sf.jasperreports:jasperreports:3.7.6")
testCompile("org.apache.poi:poi:3.6")
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
}
// pick up **/*.types files in src/main
@@ -460,29 +470,30 @@ project("spring-context-support") {
project("spring-web") {
description = "Spring Web"
dependencies {
compile(project(":spring-core"))
compile(project(":spring-beans")) // for MultiPartFilter
compile(project(":spring-aop")) // for JaxWsPortProxyFactoryBean
compile(project(":spring-beans")) // for MultiPartFilter
compile(project(":spring-context"))
compile(project(":spring-core"))
provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.activation:activation:1.1")
optional(project(":spring-oxm")) // for MarshallingHttpMessageConverter
compile("aopalliance:aopalliance:1.0")
optional("javax.servlet.jsp:jsp-api:2.1")
optional("javax.portlet:portlet-api:2.0")
optional("javax.el:el-api:1.0")
optional("javax.faces:jsf-api:1.2_08")
provided("javax.portlet:portlet-api:2.0")
provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.servlet.jsp:jsp-api:2.1")
optional("javax.xml:jaxrpc-api:1.1")
provided("javax.xml.soap:saaj-api:1.3")
provided("javax.activation:activation:1.1")
optional("javax.xml.soap:saaj-api:1.3")
optional("aopalliance:aopalliance:1.0")
optional("com.caucho:hessian:3.2.1")
optional("rome:rome:1.0")
optional("commons-fileupload:commons-fileupload:1.2")
optional("commons-fileupload:commons-fileupload:1.3.1")
optional("commons-io:commons-io:1.3")
optional("commons-httpclient:commons-httpclient:3.1")
optional("org.apache.httpcomponents:httpclient:4.2")
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
optional("org.apache.httpcomponents:httpclient:4.2.6")
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
optional("rome:rome:1.0")
optional("taglibs:standard:1.1.2")
optional("org.eclipse.jetty:jetty-servlet:8.1.5.v20120716") {
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
@@ -503,14 +514,20 @@ project("spring-orm") {
description = "Spring Object/Relational Mapping"
compileTestJava {
// necessary to avoid java.lang.VerifyError on toplink compilation
// TODO: remove this block when we remove toplink
// necessary to avoid java.lang.VerifyError on TopLink compilation
sourceCompatibility=1.6
targetCompatibility=1.6
}
dependencies {
compile("aopalliance:aopalliance:1.0")
compile(project(":spring-beans"))
compile(project(":spring-core"))
compile(project(":spring-jdbc"))
compile(project(":spring-tx"))
optional(project(":spring-aop"))
optional(project(":spring-context"))
optional(project(":spring-web"))
optional("aopalliance:aopalliance:1.0")
optional("javax.persistence:persistence-api:1.0")
optional("org.eclipse.persistence:org.eclipse.persistence.core:1.0.1")
optional("org.eclipse.persistence:org.eclipse.persistence.jpa:1.0.1")
@@ -521,20 +538,13 @@ project("spring-orm") {
optional("toplink.essentials:toplink-essentials:2.0-41b")
optional("javax.jdo:jdo-api:3.0")
optional("org.apache.ibatis:ibatis-sqlmap:2.3.4.726")
provided("javax.servlet:servlet-api:2.5")
optional("javax.servlet:servlet-api:2.5")
testCompile("javax.servlet:javax.servlet-api:3.0.1")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("commons-dbcp:commons-dbcp:1.2.2")
testCompile("org.eclipse.persistence:org.eclipse.persistence.asm:1.0.1")
testCompile("org.eclipse.persistence:org.eclipse.persistence.antlr:1.0.1")
testCompile("commons-dbcp:commons-dbcp:1.3")
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
compile(project(":spring-core"))
compile(project(":spring-beans"))
optional(project(":spring-aop"))
optional(project(":spring-context"))
compile(project(":spring-tx"))
compile(project(":spring-jdbc"))
optional(project(":spring-web"))
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
}
}
@@ -543,11 +553,11 @@ project("spring-orm-hibernate4") {
merge.into = project(":spring-orm")
dependencies {
provided(project(":spring-tx"))
provided(project(":spring-jdbc"))
optional("org.hibernate:hibernate-core:4.1.9.Final")
optional("org.hibernate:hibernate-entitymanager:4.1.9.Final")
provided(project(":spring-tx"))
optional(project(":spring-web"))
optional("org.hibernate:hibernate-core:4.2.12.Final")
optional("org.hibernate:hibernate-entitymanager:4.2.12.Final")
optional("javax.servlet:servlet-api:2.5")
}
}
@@ -556,34 +566,33 @@ project("spring-webmvc") {
description = "Spring Web MVC"
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-context"))
compile(project(":spring-core"))
compile(project(":spring-expression"))
compile(project(":spring-beans"))
compile(project(":spring-web"))
compile(project(":spring-context"))
provided("javax.servlet:javax.servlet-api:3.0.1")
optional(project(":spring-context-support")) // for Velocity support
optional(project(":spring-oxm")) // for MarshallingView
optional("javax.servlet.jsp:jsp-api:2.1")
optional("javax.servlet:jstl:1.2")
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
optional("org.apache.poi:poi:3.6")
optional("velocity:velocity:1.5")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.20")
optional("com.lowagie:itext:2.1.7")
optional("net.sf.jasperreports:jasperreports:3.7.6") {
exclude group: "xml-apis", module: "xml-apis"
}
optional("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.6")
optional("rome:rome:1.0")
optional("org.apache.tiles:tiles-api:2.1.2")
optional("org.apache.tiles:tiles-core:2.1.2")
optional("org.apache.tiles:tiles-jsp:2.1.2")
optional("org.apache.tiles:tiles-servlet:2.1.2")
optional("net.sourceforge.jexcelapi:jxl:2.6.3")
optional("org.apache.poi:poi:3.0.2-FINAL")
optional("com.lowagie:itext:2.1.7")
optional("jasperreports:jasperreports:2.0.5") {
exclude group: "xml-apis", module: "xml-apis"
}
optional("rome:rome:1.0")
optional("velocity:velocity:1.5")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.15")
optional("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
optional("com.fasterxml.jackson.core:jackson-databind:2.0.1")
provided("javax.servlet:jstl:1.2")
provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.servlet.jsp:jsp-api:2.1")
testCompile(project(":spring-aop"))
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("rhino:js:1.7R1")
testCompile("xmlunit:xmlunit:1.3")
testCompile("dom4j:dom4j:1.6.1") {
@@ -601,10 +610,11 @@ project("spring-webmvc") {
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
}
testCompile("javax.validation:validation-api:1.0.0.GA")
testCompile("commons-fileupload:commons-fileupload:1.2")
testCompile("org.hibernate:hibernate-validator:4.3.1.Final")
testCompile("org.apache.httpcomponents:httpclient:4.2.6")
testCompile("commons-fileupload:commons-fileupload:1.3.1")
testCompile("commons-io:commons-io:1.3")
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
testCompile("org.apache.httpcomponents:httpclient:4.2")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
}
// pick up DispatcherServlet.properties in src/main
@@ -618,27 +628,27 @@ project("spring-webmvc-tiles3") {
dependencies {
provided(project(":spring-context"))
provided(project(":spring-web"))
provided("javax.el:el-api:1.0")
provided("javax.servlet:jstl:1.2")
provided("javax.servlet.jsp:jsp-api:2.1")
optional("org.apache.tiles:tiles-request-api:1.0.1")
optional("org.apache.tiles:tiles-api:3.0.1")
optional("org.apache.tiles:tiles-core:3.0.1") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-servlet:3.0.1") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-jsp:3.0.1") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-extras:3.0.1") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-el:3.0.1") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
provided("javax.servlet:javax.servlet-api:3.0.1")
optional("javax.servlet.jsp:jsp-api:2.1")
optional("javax.servlet:jstl:1.2")
optional("javax.el:el-api:1.0")
optional("org.apache.tiles:tiles-api:3.0.4")
optional("org.apache.tiles:tiles-core:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-servlet:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-jsp:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-el:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tiles:tiles-extras:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
exclude group: "org.springframework", module: "spring-web"
}
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
}
}
@@ -647,14 +657,14 @@ project("spring-webmvc-portlet") {
description = "Spring Web Portlet"
dependencies {
provided("javax.servlet:servlet-api:2.5")
provided("javax.portlet:portlet-api:2.0")
compile(project(":spring-core"))
compile(project(":spring-beans"))
compile(project(":spring-context"))
compile(project(":spring-core"))
compile(project(":spring-web"))
compile(project(":spring-webmvc"))
optional("commons-fileupload:commons-fileupload:1.2")
provided("javax.servlet:servlet-api:2.5")
provided("javax.portlet:portlet-api:2.0")
optional("commons-fileupload:commons-fileupload:1.3.1")
}
// pick up DispatcherPortlet.properties in src/main
@@ -666,6 +676,7 @@ project("spring-test") {
dependencies {
compile(project(":spring-core"))
provided("javax.activation:activation:1.1")
optional(project(":spring-beans"))
optional(project(":spring-context"))
optional(project(":spring-jdbc"))
@@ -673,72 +684,73 @@ project("spring-test") {
optional(project(":spring-orm"))
optional(project(":spring-web"))
optional(project(":spring-webmvc"))
optional(project(":spring-webmvc-portlet"), )
optional(project(":spring-webmvc-portlet"))
optional("junit:junit:${junitVersion}")
optional("org.testng:testng:6.5.2")
optional("org.testng:testng:6.8.8")
optional("javax.inject:javax.inject:1")
optional("javax.servlet:servlet-api:2.5")
optional("javax.servlet.jsp:jsp-api:2.1")
optional("javax.servlet:jstl:1.2")
optional("javax.portlet:portlet-api:2.0")
optional("javax.persistence:persistence-api:1.0")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
testCompile("org.hibernate:hibernate-core:3.3.2.GA")
provided("javax.inject:javax.inject:1")
provided("javax.activation:activation:1.1")
provided("javax.servlet:jstl:1.2")
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
testCompile "org.slf4j:slf4j-jcl:${slf4jVersion}"
}
task testNG(type: Test) {
useTestNG()
// forkEvery 1
scanForTestClasses = false
include "**/testng/*.*"
include "**/testng/**/*.*"
exclude "**/FailingBeforeAndAfterMethodsTests.class"
// "TestCase" classes are run by other test classes, not the build.
exclude "**/*TestCase.class"
// Generate TestNG reports alongside JUnit reports.
testReport true
getReports().getHtml().setEnabled(true)
// show standard out and standard error of the test JVM(s) on the console
// testLogging.showStandardStreams = true
}
test {
dependsOn testNG
useJUnit()
exclude "**/testng/*.*"
exclude "**/testng/**/*.*"
include "**/testng/FailingBeforeAndAfterMethodsTests"
// "TestCase" classes are run by other test classes, not the build.
exclude(["**/*TestCase.class", "**/*TestSuite.class"])
}
}
project("spring-test-mvc") {
description = "Spring Test MVC Framework"
merge.into = project(":spring-test")
dependencies {
optional(project(":spring-context"))
provided(project(":spring-webmvc"))
provided("javax.servlet:javax.servlet-api:3.0.1")
provided("javax.activation:activation:1.1")
optional(project(":spring-context"))
optional("org.hamcrest:hamcrest-core:1.3")
optional("com.jayway.jsonpath:json-path:0.8.1")
optional("xmlunit:xmlunit:1.3")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("javax.servlet:jstl:1.2")
testCompile("org.hibernate:hibernate-validator:4.3.0.Final")
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.4.2")
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.1")
testCompile(project(":spring-context-support"))
testCompile(project(":spring-oxm"))
testCompile("com.thoughtworks.xstream:xstream:1.3.1")
testCompile("javax.servlet:jstl:1.2")
testCompile("javax.mail:mail:1.4.7")
testCompile("org.hibernate:hibernate-validator:4.3.1.Final")
testCompile("com.thoughtworks.xstream:xstream:1.4.7")
testCompile("org.codehaus.jackson:jackson-mapper-asl:1.7.9")
testCompile("com.fasterxml.jackson.core:jackson-databind:2.0.6")
testCompile("rome:rome:1.0")
testCompile("javax.activation:activation:1.1")
testCompile("javax.mail:mail:1.4")
testCompile("org.apache.tiles:tiles-request-api:1.0.1")
testCompile("org.apache.tiles:tiles-api:3.0.1")
testCompile("org.apache.tiles:tiles-core:3.0.1") {
testCompile("org.apache.tiles:tiles-api:3.0.4")
testCompile("org.apache.tiles:tiles-core:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
testCompile("org.apache.tiles:tiles-servlet:3.0.1") {
testCompile("org.apache.tiles:tiles-servlet:3.0.4") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
}
}
@@ -763,21 +775,20 @@ project("spring-aspects") {
apply from: "aspects.gradle"
dependencies {
optional(project(":spring-beans")) // for @Configurable support
optional(project(":spring-aop")) // for @Async support
optional(project(":spring-context")) // for @Enable* support
compile(project(":spring-context-support")) // for JavaMail support
optional(project(":spring-tx")) // for JPA, @Transactional support
optional(project(":spring-orm")) // for JPA exception translation support
aspects(project(":spring-orm"))
provided("javax.persistence:persistence-api:1.0")
testCompile("javax.mail:mail:1.4")
ajc("org.aspectj:aspectjtools:${aspectjVersion}")
rt("org.aspectj:aspectjrt:${aspectjVersion}")
compile("org.aspectj:aspectjweaver:${aspectjVersion}")
provided("javax.persistence:persistence-api:1.0")
optional(project(":spring-aop")) // for @Async support
optional(project(":spring-beans")) // for @Configurable support
optional(project(":spring-context")) // for @Enable* support
optional(project(":spring-context-support")) // for JavaMail support
optional(project(":spring-orm")) // for JPA exception translation support
optional(project(":spring-tx")) // for JPA, @Transactional support
testCompile(project(":spring-core")) // for CodeStyleAspect
compile(project(":spring-beans")) // for "p" namespace visibility
testCompile(project(":spring-test"))
testCompile("javax.mail:mail:1.4.7")
}
eclipse.project {
@@ -827,6 +838,7 @@ configure(rootProject) {
apply plugin: "docbook-reference"
apply plugin: "groovy"
// apply plugin: "detect-split-packages"
apply from: "${gradleScriptDir}/jdiff.gradle"
@@ -845,23 +857,23 @@ configure(rootProject) {
configurations.archives.artifacts.clear()
dependencies { // for integration tests
testCompile(project(":spring-core"))
testCompile(project(":spring-beans"))
testCompile(project(":spring-aop"))
testCompile(project(":spring-expression"))
testCompile(project(":spring-beans"))
testCompile(project(":spring-context"))
testCompile(project(":spring-tx"))
testCompile(project(":spring-core"))
testCompile(project(":spring-expression"))
testCompile(project(":spring-jdbc"))
testCompile(project(":spring-orm"))
testCompile(project(":spring-test"))
testCompile(project(":spring-tx"))
testCompile(project(":spring-web"))
testCompile(project(":spring-webmvc-portlet"))
testCompile(project(":spring-orm"))
testCompile("org.hibernate:hibernate-core:4.1.9.Final")
testCompile("javax.servlet:servlet-api:2.5")
testCompile("javax.portlet:portlet-api:2.0")
testCompile("javax.inject:javax.inject:1")
testCompile("javax.resource:connector-api:1.5")
testCompile("org.aspectj:aspectjweaver:${aspectjVersion}")
testCompile("org.hibernate:hibernate-core:4.2.12.Final")
testCompile("hsqldb:hsqldb:${hsqldbVersion}")
}
@@ -882,7 +894,7 @@ configure(rootProject) {
options.stylesheetFile = file("src/api/stylesheet.css")
options.splitIndex = true
options.links(project.ext.javadocLinks)
if(JavaVersion.current().isJava8Compatible()) {
if (JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
@@ -895,7 +907,7 @@ configure(rootProject) {
doFirst {
classpath = files(
// ensure Servlet 3.x and Hibernate 4.x have precedence on the Javadoc
// ensure Servlet 3.x and Hibernate 4.x have precedence on the javadoc
// classpath over their respective 2.5 and 3.x variants
project(":spring-webmvc").sourceSets.main.compileClasspath.files.find { it =~ "servlet-api" },
rootProject.sourceSets.test.compileClasspath.files.find { it =~ "hibernate-core" },
@@ -906,7 +918,7 @@ configure(rootProject) {
}
}
task docsZip(type: Zip) {
task docsZip(type: Zip, dependsOn: 'reference') {
group = "Distribution"
baseName = "spring-framework"
classifier = "docs"
@@ -1032,7 +1044,7 @@ configure(rootProject) {
task wrapper(type: Wrapper) {
description = "Generates gradlew[.bat] scripts"
gradleVersion = "1.6"
gradleVersion = "1.12"
doLast() {
def gradleOpts = "-XX:MaxPermSize=1024m -Xmx1024m"
+1 -1
View File
@@ -1 +1 @@
version=3.2.6.RELEASE
version=3.2.9.RELEASE
Binary file not shown.
+5 -5
View File
@@ -1,6 +1,6 @@
#Tue Jul 30 09:29:28 PDT 2013
zipStoreBase=GRADLE_USER_HOME
distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
#Wed Apr 30 13:06:57 CEST 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,9 @@ package org.springframework.aop;
import java.lang.reflect.Method;
/**
* A specialized type of MethodMatcher that takes into account introductions when
* matching methods. If there are no introductions on the target class, a method
* matcher may be able to optimize matching more effectively for example.
* A specialized type of {@link MethodMatcher} that takes into account introductions
* when matching methods. If there are no introductions on the target class,
* a method matcher may be able to optimize matching more effectively for example.
*
* @author Adrian Colyer
* @since 2.0
@@ -39,6 +39,6 @@ public interface IntroductionAwareMethodMatcher extends MethodMatcher {
* asking is the subject on one or more introductions; {@code false} otherwise
* @return whether or not this method matches statically
*/
boolean matches(Method method, Class targetClass, boolean hasIntroductions);
boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.patterns.NamePattern;
import org.aspectj.weaver.reflect.ReflectionWorld;
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ContextBasedMatcher;
@@ -42,6 +41,7 @@ import org.aspectj.weaver.tools.PointcutParameter;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.ShadowMatch;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAwareMethodMatcher;
import org.springframework.aop.MethodMatcher;
@@ -55,6 +55,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -98,14 +99,16 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
private static final Log logger = LogFactory.getLog(AspectJExpressionPointcut.class);
private Class pointcutDeclarationScope;
private Class<?> pointcutDeclarationScope;
private String[] pointcutParameterNames = new String[0];
private Class[] pointcutParameterTypes = new Class[0];
private Class<?>[] pointcutParameterTypes = new Class<?>[0];
private BeanFactory beanFactory;
private transient ClassLoader pointcutClassLoader;
private transient PointcutExpression pointcutExpression;
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
@@ -123,7 +126,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
* @param paramNames the parameter names for the pointcut
* @param paramTypes the parameter types for the pointcut
*/
public AspectJExpressionPointcut(Class declarationScope, String[] paramNames, Class[] paramTypes) {
public AspectJExpressionPointcut(Class<?> declarationScope, String[] paramNames, Class<?>[] paramTypes) {
this.pointcutDeclarationScope = declarationScope;
if (paramNames.length != paramTypes.length) {
throw new IllegalStateException(
@@ -137,21 +140,21 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
/**
* Set the declaration scope for the pointcut.
*/
public void setPointcutDeclarationScope(Class pointcutDeclarationScope) {
public void setPointcutDeclarationScope(Class<?> pointcutDeclarationScope) {
this.pointcutDeclarationScope = pointcutDeclarationScope;
}
/**
* Set the parameter names for the pointcut.
*/
public void setParameterNames(String[] names) {
public void setParameterNames(String... names) {
this.pointcutParameterNames = names;
}
/**
* Set the parameter types for the pointcut.
*/
public void setParameterTypes(Class[] types) {
public void setParameterTypes(Class<?>... types) {
this.pointcutParameterTypes = types;
}
@@ -180,20 +183,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutExpression = buildPointcutExpression();
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
ClassUtils.getDefaultClassLoader());
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
/**
* Build the underlying AspectJ pointcut expression.
*/
private PointcutExpression buildPointcutExpression() {
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory)
.getBeanClassLoader() : Thread.currentThread()
.getContextClassLoader());
return buildPointcutExpression(cl);
}
/**
* Build the underlying AspectJ pointcut expression.
*/
@@ -202,8 +198,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
PointcutParameter[] pointcutParameters = new PointcutParameter[this.pointcutParameterNames.length];
for (int i = 0; i < pointcutParameters.length; i++) {
pointcutParameters[i] = parser.createPointcutParameter(
this.pointcutParameterNames[i],
this.pointcutParameterTypes[i]);
this.pointcutParameterNames[i], this.pointcutParameterTypes[i]);
}
return parser.parsePointcutExpression(
replaceBooleanOperators(getExpression()),
@@ -244,30 +239,28 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
return this.pointcutExpression;
}
public boolean matches(Class targetClass) {
public boolean matches(Class<?> targetClass) {
checkReadyToMatch();
try {
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
} catch (ReflectionWorldException e) {
logger.debug("PointcutExpression matching rejected target class", e);
try {
// Actually this is still a "maybe" - treat the pointcut as dynamic if we
// don't know enough yet
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
} catch (BCException ex) {
logger.debug(
"Fallback PointcutExpression matching rejected target class",
ex);
return false;
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
catch (ReflectionWorldException ex) {
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
if (fallbackExpression != null) {
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
}
}
}
catch (BCException ex) {
logger.debug("PointcutExpression matching rejected target class", ex);
return false;
}
return false;
}
public boolean matches(Method method, Class targetClass, boolean beanHasIntroductions) {
public boolean matches(Method method, Class<?> targetClass, boolean beanHasIntroductions) {
checkReadyToMatch();
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
@@ -283,11 +276,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
}
else {
// the maybe case
return (beanHasIntroductions || matchesIgnoringSubtypes(shadowMatch) || matchesTarget(shadowMatch, targetClass));
if (beanHasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
// involved in the test (this, target, at_this, at_target, at_annotation) then
// we say this is not a match as in Spring there will never be a different
// runtime subtype.
RuntimeTestWalker walker = getRuntimeTestWalker(shadowMatch);
return (!walker.testsSubtypeSensitiveVars() || walker.testTargetInstanceOfResidue(targetClass));
}
}
public boolean matches(Method method, Class targetClass) {
public boolean matches(Method method, Class<?> targetClass) {
return matches(method, targetClass, false);
}
@@ -296,7 +297,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
return this.pointcutExpression.mayNeedDynamicTest();
}
public boolean matches(Method method, Class targetClass, Object[] args) {
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
checkReadyToMatch();
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
@@ -336,46 +337,37 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false;
}
}
if (joinPointMatch.matches() && pmi != null) {
bindParameters(pmi, joinPointMatch);
if (joinPointMatch.matches()) {
bindParameters(pmi, joinPointMatch);
}
}
return joinPointMatch.matches();
}
protected String getCurrentProxiedBeanName() {
return ProxyCreationContext.getCurrentProxiedBeanName();
}
/**
* Get a new pointcut expression based on a target class's loader, rather
* than the default.
* Get a new pointcut expression based on a target class's loader rather than the default.
*/
private PointcutExpression getFallbackPointcutExpression(
Class<?> targetClass) {
ClassLoader classLoader = targetClass.getClassLoader();
return classLoader == null ? this.pointcutExpression : buildPointcutExpression(classLoader);
}
/**
* A match test returned maybe - if there are any subtype sensitive variables
* involved in the test (this, target, at_this, at_target, at_annotation) then
* we say this is not a match as in Spring there will never be a different
* runtime subtype.
*/
private boolean matchesIgnoringSubtypes(ShadowMatch shadowMatch) {
return !(getRuntimeTestWalker(shadowMatch).testsSubtypeSensitiveVars());
}
private boolean matchesTarget(ShadowMatch shadowMatch, Class targetClass) {
return getRuntimeTestWalker(shadowMatch).testTargetInstanceOfResidue(targetClass);
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
try {
ClassLoader classLoader = targetClass.getClassLoader();
if (classLoader != null && classLoader != this.pointcutClassLoader) {
return buildPointcutExpression(classLoader);
}
}
catch (Throwable ex) {
logger.debug("Failed to create fallback PointcutExpression", ex);
}
return null;
}
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
if (shadowMatch instanceof DefensiveShadowMatch) {
return new RuntimeTestWalker(((DefensiveShadowMatch)shadowMatch).primary);
return new RuntimeTestWalker(((DefensiveShadowMatch) shadowMatch).primary);
}
return new RuntimeTestWalker(shadowMatch);
}
@@ -396,44 +388,51 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
if (shadowMatch == null) {
synchronized (this.shadowMatchCache) {
// Not found - now check again with full lock...
PointcutExpression fallbackExpression = null;
Method methodToMatch = targetMethod;
PointcutExpression fallbackPointcutExpression = null;
shadowMatch = this.shadowMatchCache.get(methodToMatch);
shadowMatch = this.shadowMatchCache.get(targetMethod);
if (shadowMatch == null) {
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorld.ReflectionWorldException ex) {
catch (ReflectionWorldException ex) {
// Failed to introspect target method, probably because it has been loaded
// in a special ClassLoader. Let's try the original method instead...
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
try {
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
} catch (ReflectionWorld.ReflectionWorldException e) {
if (targetMethod == originalMethod) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
if (fallbackExpression != null) {
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
}
else {
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
}
catch (ReflectionWorld.ReflectionWorldException ex2) {
// Could neither introspect the target class nor the proxy class ->
// let's simply consider this method as non-matching.
methodToMatch = originalMethod;
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
try {
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
} catch (ReflectionWorld.ReflectionWorldException e2) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
}
}
catch (ReflectionWorldException ex2) {
fallbackExpression = null;
}
}
if (shadowMatch == null && targetMethod != originalMethod) {
methodToMatch = originalMethod;
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorldException ex3) {
// Could neither introspect the target class nor the proxy class ->
// let's try the original method's declaring class before we give up...
try {
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
if (fallbackExpression != null) {
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
}
}
catch (ReflectionWorldException ex4) {
fallbackExpression = null;
}
}
}
if (shadowMatch.maybeMatches() && fallbackPointcutExpression!=null) {
if (shadowMatch == null) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
}
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
shadowMatch = new DefensiveShadowMatch(shadowMatch,
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
fallbackExpression.matchesMethodExecution(methodToMatch));
}
this.shadowMatchCache.put(targetMethod, shadowMatch);
}
@@ -551,7 +550,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
return false;
}
private FuzzyBoolean contextMatch(Class targetType) {
private FuzzyBoolean contextMatch(Class<?> targetType) {
String advisedBeanName = getCurrentProxiedBeanName();
if (advisedBeanName == null) { // no proxy creation in progress
// abstain; can't return YES, since that will make pointcut with negation fail
@@ -601,9 +600,11 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
this.shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
}
private static class DefensiveShadowMatch implements ShadowMatch {
private final ShadowMatch primary;
private final ShadowMatch other;
public DefensiveShadowMatch(ShadowMatch primary, ShadowMatch other) {
@@ -612,31 +613,30 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
}
public boolean alwaysMatches() {
return primary.alwaysMatches();
return this.primary.alwaysMatches();
}
public boolean maybeMatches() {
return primary.maybeMatches();
return this.primary.maybeMatches();
}
public boolean neverMatches() {
return primary.neverMatches();
return this.primary.neverMatches();
}
public JoinPointMatch matchesJoinPoint(Object thisObject,
Object targetObject, Object[] args) {
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
try {
return primary.matchesJoinPoint(thisObject, targetObject, args);
} catch (ReflectionWorldException e) {
return other.matchesJoinPoint(thisObject, targetObject, args);
return this.primary.matchesJoinPoint(thisObject, targetObject, args);
}
catch (ReflectionWorldException ex) {
return this.other.matchesJoinPoint(thisObject, targetObject, args);
}
}
public void setMatchingContext(MatchingContext aMatchContext) {
primary.setMatchingContext(aMatchContext);
other.setMatchingContext(aMatchContext);
this.primary.setMatchingContext(aMatchContext);
this.other.setMatchingContext(aMatchContext);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package org.springframework.aop.aspectj;
import java.lang.reflect.Field;
import org.aspectj.weaver.ReferenceType;
import org.aspectj.weaver.ReferenceTypeDelegate;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ast.And;
import org.aspectj.weaver.ast.Call;
@@ -30,6 +32,7 @@ import org.aspectj.weaver.ast.Not;
import org.aspectj.weaver.ast.Or;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegate;
import org.aspectj.weaver.reflect.ReflectionVar;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ShadowMatch;
@@ -55,25 +58,36 @@ import org.springframework.util.ReflectionUtils;
*/
class RuntimeTestWalker {
private static final Field residualTestField;
private static final Field varTypeField;
private static final Field myClassField;
static {
try {
residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
varTypeField = ReflectionVar.class.getDeclaredField("varType");
myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
}
catch (NoSuchFieldException ex) {
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
"on the classpath is incompatible with this version of Spring: " + ex);
}
}
private final Test runtimeTest;
public RuntimeTestWalker(ShadowMatch shadowMatch) {
ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch;
try {
Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest");
ReflectionUtils.makeAccessible(testField);
this.runtimeTest = (Test) testField.get(shadowMatch);
ReflectionUtils.makeAccessible(residualTestField);
this.runtimeTest = (Test) residualTestField.get(shadowMatch);
}
catch (NoSuchFieldException noSuchFieldEx) {
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
"on the classpath is incompatible with this version of Spring: Expected field " +
"'runtimeTest' is not present on ShadowMatchImpl class.");
}
catch (IllegalAccessException illegalAccessEx) {
// Famous last words... but I don't see how this can happen given the
// makeAccessible call above
throw new IllegalStateException("Unable to access ShadowMatchImpl.residualTest field");
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
@@ -87,12 +101,12 @@ class RuntimeTestWalker {
new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest));
}
public boolean testThisInstanceOfResidue(Class thisClass) {
public boolean testThisInstanceOfResidue(Class<?> thisClass) {
return (this.runtimeTest != null &&
new ThisInstanceOfResidueTestVisitor(thisClass).thisInstanceOfMatches(this.runtimeTest));
}
public boolean testTargetInstanceOfResidue(Class targetClass) {
public boolean testTargetInstanceOfResidue(Class<?> targetClass) {
return (this.runtimeTest != null &&
new TargetInstanceOfResidueTestVisitor(targetClass).targetInstanceOfMatches(this.runtimeTest));
}
@@ -140,19 +154,11 @@ class RuntimeTestWalker {
protected int getVarType(ReflectionVar v) {
try {
Field varTypeField = ReflectionVar.class.getDeclaredField("varType");
ReflectionUtils.makeAccessible(varTypeField);
return (Integer) varTypeField.get(v);
}
catch (NoSuchFieldException noSuchFieldEx) {
throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " +
"on the classpath is incompatible with this version of Spring:- expected field " +
"'varType' is not present on ReflectionVar class");
}
catch (IllegalAccessException illegalAccessEx) {
// Famous last words... but I don't see how this can happen given the
// makeAccessible call above
throw new IllegalStateException("Unable to access ReflectionVar.varType field");
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
}
@@ -160,11 +166,13 @@ class RuntimeTestWalker {
private static abstract class InstanceOfResidueTestVisitor extends TestVisitorAdapter {
private Class matchClass;
private boolean matches;
private int matchVarType;
private final Class<?> matchClass;
public InstanceOfResidueTestVisitor(Class matchClass, boolean defaultMatches, int matchVarType) {
private boolean matches;
private final int matchVarType;
public InstanceOfResidueTestVisitor(Class<?> matchClass, boolean defaultMatches, int matchVarType) {
this.matchClass = matchClass;
this.matches = defaultMatches;
this.matchVarType = matchVarType;
@@ -172,19 +180,34 @@ class RuntimeTestWalker {
public boolean instanceOfMatches(Test test) {
test.accept(this);
return matches;
return this.matches;
}
@Override
public void visit(Instanceof i) {
ResolvedType type = (ResolvedType) i.getType();
int varType = getVarType((ReflectionVar) i.getVar());
if (varType != this.matchVarType) {
return;
}
Class<?> typeClass = null;
ResolvedType type = (ResolvedType) i.getType();
if (type instanceof ReferenceType) {
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
if (delegate instanceof ReflectionBasedReferenceTypeDelegate) {
try {
ReflectionUtils.makeAccessible(myClassField);
typeClass = (Class<?>) myClassField.get(delegate);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
}
try {
Class typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
// Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins
// Don't use ResolvedType.isAssignableFrom() as it won't be aware of (Spring) mixins
if (typeClass == null) {
typeClass = ClassUtils.forName(type.getName(), this.matchClass.getClassLoader());
}
this.matches = typeClass.isAssignableFrom(this.matchClass);
}
catch (ClassNotFoundException ex) {
@@ -199,7 +222,7 @@ class RuntimeTestWalker {
*/
private static class TargetInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
public TargetInstanceOfResidueTestVisitor(Class targetClass) {
public TargetInstanceOfResidueTestVisitor(Class<?> targetClass) {
super(targetClass, false, TARGET_VAR);
}
@@ -214,7 +237,7 @@ class RuntimeTestWalker {
*/
private static class ThisInstanceOfResidueTestVisitor extends InstanceOfResidueTestVisitor {
public ThisInstanceOfResidueTestVisitor(Class thisClass) {
public ThisInstanceOfResidueTestVisitor(Class<?> thisClass) {
super(thisClass, true, THIS_VAR);
}
@@ -228,8 +251,11 @@ class RuntimeTestWalker {
private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter {
private final Object thisObj = new Object();
private final Object targetObj = new Object();
private final Object[] argsObjs = new Object[0];
private boolean testsSubtypeSensitiveVars = false;
public boolean testsSubtypeSensitiveVars(Test aTest) {
@@ -240,8 +266,8 @@ class RuntimeTestWalker {
@Override
public void visit(Instanceof i) {
ReflectionVar v = (ReflectionVar) i.getVar();
Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs);
if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) {
Object varUnderTest = v.getBindingAtJoinPoint(this.thisObj, this.targetObj, this.argsObjs);
if (varUnderTest == this.thisObj || varUnderTest == this.targetObj) {
this.testsSubtypeSensitiveVars = true;
}
}
@@ -251,7 +277,7 @@ class RuntimeTestWalker {
// If you thought things were bad before, now we sink to new levels of horror...
ReflectionVar v = (ReflectionVar) hasAnn.getVar();
int varType = getVarType(v);
if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) {
if (varType == AT_THIS_VAR || varType == AT_TARGET_VAR || varType == AT_ANNOTATION_VAR) {
this.testsSubtypeSensitiveVars = true;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
}
public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
Assert.notNull(this.aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
}
@@ -89,7 +89,7 @@ public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorA
}
@Override
protected boolean isInfrastructureClass(Class beanClass) {
protected boolean isInfrastructureClass(Class<?> beanClass) {
// Previously we setProxyTargetClass(true) in the constructor, but that has too
// broad an impact. Instead we now override isInfrastructureClass to avoid proxying
// aspects. I'm not entirely happy with that as there is no good reason not
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
*/
private int order = Ordered.LOWEST_PRECEDENCE;
private final Map<Class, Boolean> eligibleBeans = new ConcurrentHashMap<Class, Boolean>(64);
private final Map<Class<?>, Boolean> eligibleBeans = new ConcurrentHashMap<Class<?>, Boolean>(64);
/**
@@ -87,9 +87,11 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (isEligible(bean, beanName)) {
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
@@ -98,32 +100,47 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
}
return bean;
}
else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else {
// No async proxy needed.
return bean;
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = new ProxyFactory(bean);
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
// No async proxy needed.
return bean;
}
/**
* Check whether the given bean is eligible for advising with this
* post-processor's {@link Advisor}.
* <p>Implements caching of {@code canApply} results per bean target class.
* <p>Delegates to {@link #isEligible(Class)} for target class checking.
* Can be overridden e.g. to specifically exclude certain beans by name.
* <p>Note: Only called for regular bean instances but not for existing
* proxy instances which implement {@link Advised} and allow for adding
* the local {@link Advisor} to the existing proxy's {@link Advisor} chain.
* For the latter, {@link #isEligible(Class)} is being called directly,
* with the actual target class behind the existing proxy (as determined
* by {@link AopUtils#getTargetClass(Object)}).
* @param bean the bean instance
* @param beanName the name of the bean
* @see AopUtils#getTargetClass(Object)
* @see AopUtils#canApply(Advisor, Class)
* @see #isEligible(Class)
*/
protected boolean isEligible(Object bean, String beanName) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
return isEligible(bean.getClass());
}
/**
* Check whether the given class is eligible for advising with this
* post-processor's {@link Advisor}.
* <p>Implements caching of {@code canApply} results per bean target class.
* @param targetClass the class to check against
* @see AopUtils#canApply(Advisor, Class)
*/
protected boolean isEligible(Class<?> targetClass) {
Boolean eligible = this.eligibleBeans.get(targetClass);
if (eligible != null) {
return eligible;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +37,7 @@ import org.springframework.aop.RawTargetAccess;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.cglib.core.SpringNamingPolicy;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Dispatcher;
@@ -181,20 +182,20 @@ final class CglibAopProxy implements AopProxy, Serializable {
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
enhancer.setInterceptDuringConstruction(false);
Callback[] callbacks = getCallbacks(rootClass);
enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
Class<?>[] types = new Class[callbacks.length];
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
enhancer.setCallbacks(callbacks);
// Generate the proxy class and create a proxy instance.
Object proxy;
@@ -259,7 +260,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
Modifier.isFinal(method.getModifiers())) {
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
"All calls to this method via a proxy will be routed directly to the proxy.");
"All calls to this method via a proxy will NOT be routed to the target instance.");
}
}
}
@@ -312,8 +313,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);
// TODO: small memory optimisation here (can skip creation for
// methods with no advice)
// TODO: small memory optimisation here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
@@ -340,16 +340,15 @@ final class CglibAopProxy implements AopProxy, Serializable {
*/
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
// Massage return value if necessary
if (retVal != null && retVal == target &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this".
// Note that we can't help if the target sets a reference
// to itself in another returned object.
if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this". Note that we can't help
// if the target sets a reference to itself in another returned object.
retVal = proxy;
}
Class<?> returnType = method.getReturnType();
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
@@ -595,7 +594,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
*/
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private AdvisedSupport advised;
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
@@ -612,8 +611,8 @@ final class CglibAopProxy implements AopProxy, Serializable {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool.
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
@@ -818,8 +817,8 @@ final class CglibAopProxy implements AopProxy, Serializable {
// of the target type. If so we know it never needs to have return type
// massage and can use a dispatcher.
// If the proxy is being exposed, then must use the interceptor the
// correct one is already configured. If the target is not static cannot
// use a Dispatcher because the target can not then be released.
// correct one is already configured. If the target is not static, then
// cannot use a dispatcher because the target cannot be released.
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
@@ -851,7 +850,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
@Override
public boolean equals(Object other) {
if (other == this) {
if (this == other) {
return true;
}
if (!(other instanceof ProxyCallbackFilter)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,7 +19,6 @@ package org.springframework.aop.framework;
import org.aopalliance.intercept.Interceptor;
import org.springframework.aop.TargetSource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
@@ -47,9 +46,8 @@ public class ProxyFactory extends ProxyCreatorSupport {
* @param target the target object to be proxied
*/
public ProxyFactory(Object target) {
Assert.notNull(target, "Target object must not be null");
setInterfaces(ClassUtils.getAllInterfaces(target));
setTarget(target);
setInterfaces(ClassUtils.getAllInterfaces(target));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -21,7 +21,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
@@ -80,7 +79,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
/**
* Set the {@link BeanFactory} to be used when looking up executors by qualifier.
*/
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -62,11 +62,11 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
/**
* Create a new {@code AsyncExecutionInterceptor}.
* @param executor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
* or {@link java.util.concurrent.ExecutorService}) to delegate to.
* @param defaultExecutor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
* or {@link java.util.concurrent.ExecutorService}) to delegate to
*/
public AsyncExecutionInterceptor(Executor executor) {
super(executor);
public AsyncExecutionInterceptor(Executor defaultExecutor) {
super(defaultExecutor);
}
@@ -117,8 +117,8 @@ public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
* Subclasses may override to provide support for extracting qualifier information,
* e.g. via an annotation on the given method.
* @return always {@code null}
* @see #determineAsyncExecutor(Method)
* @since 3.1.2
* @see #determineAsyncExecutor(Method)
*/
@Override
protected String getExecutorQualifier(Method method) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -90,7 +90,7 @@ public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<O
pf.copyFrom(this);
pf.setTargetSource(this.scopedTargetSource);
Class beanType = beanFactory.getType(this.targetBeanName);
Class<?> beanType = beanFactory.getType(this.targetBeanName);
if (beanType == null) {
throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
"': Target type could not be determined at the time of proxy creation.");
@@ -122,10 +122,7 @@ public class ScopedProxyFactoryBean extends ProxyConfig implements FactoryBean<O
if (this.proxy != null) {
return this.proxy.getClass();
}
if (this.scopedTargetSource != null) {
return this.scopedTargetSource.getTargetClass();
}
return null;
return this.scopedTargetSource.getTargetClass();
}
public boolean isSingleton() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,17 +29,16 @@ import org.springframework.util.StringUtils;
* <ul>
* <li>pattern: regular expression for the fully-qualified method names to match.
* The exact regexp syntax will depend on the subclass (e.g. Perl5 regular expressions)
* <li>patterns: alternative property taking a String array of patterns. The result will
* be the union of these patterns.
* <li>patterns: alternative property taking a String array of patterns.
* The result will be the union of these patterns.
* </ul>
*
* <p>Note: the regular expressions must be a match. For example,
* {@code .*get.*} will match com.mycom.Foo.getBar().
* {@code get.*} will not.
*
* <p>This base class is serializable. Subclasses should declare all fields transient
* - the initPatternRepresentation method in this class will be invoked again on the
* client side on deserialization.
* <p>This base class is serializable. Subclasses should declare all fields transient;
* the {@link #initPatternRepresentation} method will be invoked again on deserialization.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -51,10 +50,14 @@ import org.springframework.util.StringUtils;
public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPointcut
implements Serializable {
/** Regular expressions to match */
/**
* Regular expressions to match.
*/
private String[] patterns = new String[0];
/** Regular expressions <strong>not</strong> to match */
/**
* Regular expressions <strong>not</strong> to match.
*/
private String[] excludedPatterns = new String[0];
@@ -64,15 +67,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
* @see #setPatterns
*/
public void setPattern(String pattern) {
setPatterns(new String[] {pattern});
setPatterns(pattern);
}
/**
* Set the regular expressions defining methods to match.
* Matching will be the union of all these; if any match,
* the pointcut matches.
* Matching will be the union of all these; if any match, the pointcut matches.
* @see #setPattern
*/
public void setPatterns(String[] patterns) {
public void setPatterns(String... patterns) {
Assert.notEmpty(patterns, "'patterns' must not be empty");
this.patterns = new String[patterns.length];
for (int i = 0; i < patterns.length; i++) {
@@ -94,15 +97,15 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
* @see #setExcludedPatterns
*/
public void setExcludedPattern(String excludedPattern) {
setExcludedPatterns(new String[] {excludedPattern});
setExcludedPatterns(excludedPattern);
}
/**
* Set the regular expressions defining methods to match for exclusion.
* Matching will be the union of all these; if any match,
* the pointcut matches.
* Matching will be the union of all these; if any match, the pointcut matches.
* @see #setExcludedPattern
*/
public void setExcludedPatterns(String[] excludedPatterns) {
public void setExcludedPatterns(String... excludedPatterns) {
Assert.notEmpty(excludedPatterns, "'excludedPatterns' must not be empty");
this.excludedPatterns = new String[excludedPatterns.length];
for (int i = 0; i < excludedPatterns.length; i++) {
@@ -124,7 +127,7 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
* of the target class as well as against the method's declaring class,
* plus the name of the method.
*/
public boolean matches(Method method, Class targetClass) {
public boolean matches(Method method, Class<?> targetClass) {
return ((targetClass != null && matchesPattern(targetClass.getName() + "." + method.getName())) ||
matchesPattern(method.getDeclaringClass().getName() + "." + method.getName()));
}
@@ -172,18 +175,18 @@ public abstract class AbstractRegexpMethodPointcut extends StaticMethodMatcherPo
protected abstract void initExcludedPatternRepresentation(String[] patterns) throws IllegalArgumentException;
/**
* Does the pattern at the given index match this string?
* @param pattern {@code String} pattern to match
* @param patternIndex index of pattern from 0
* @return {@code true} if there is a match, else {@code false}.
* Does the pattern at the given index match the given String?
* @param pattern the {@code String} pattern to match
* @param patternIndex index of pattern (starting from 0)
* @return {@code true} if there is a match, {@code false} otherwise
*/
protected abstract boolean matches(String pattern, int patternIndex);
/**
* Does the exclusion pattern at the given index match this string?
* @param pattern {@code String} pattern to match.
* @param patternIndex index of pattern starting from 0.
* @return {@code true} if there is a match, else {@code false}.
* Does the exclusion pattern at the given index match the given String?
* @param pattern the {@code String} pattern to match
* @param patternIndex index of pattern (starting from 0)
* @return {@code true} if there is a match, {@code false} otherwise
*/
protected abstract boolean matchesExclusion(String pattern, int patternIndex);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Static utility methods for composing
* {@link org.springframework.aop.ClassFilter ClassFilters}.
* Static utility methods for composing {@link ClassFilter ClassFilters}.
*
* @author Rod Johnson
* @author Rob Harrop
@@ -96,9 +95,9 @@ public abstract class ClassFilters {
this.filters = filters;
}
public boolean matches(Class clazz) {
for (int i = 0; i < this.filters.length; i++) {
if (this.filters[i].matches(clazz)) {
public boolean matches(Class<?> clazz) {
for (ClassFilter filter : this.filters) {
if (filter.matches(clazz)) {
return true;
}
}
@@ -130,9 +129,9 @@ public abstract class ClassFilters {
this.filters = filters;
}
public boolean matches(Class clazz) {
for (int i = 0; i < this.filters.length; i++) {
if (!this.filters[i].matches(clazz)) {
public boolean matches(Class<?> clazz) {
for (ClassFilter filter : this.filters) {
if (!filter.matches(clazz)) {
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -178,7 +178,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
return this.methodMatcher;
}
@Override
public boolean equals(Object other) {
if (this == other) {
@@ -187,7 +186,6 @@ public class ComposablePointcut implements Pointcut, Serializable {
if (!(other instanceof ComposablePointcut)) {
return false;
}
ComposablePointcut that = (ComposablePointcut) other;
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
@@ -207,8 +205,7 @@ public class ComposablePointcut implements Pointcut, Serializable {
@Override
public String toString() {
return "ComposablePointcut: ClassFilter [" + this.classFilter +
"], MethodMatcher [" + this.methodMatcher + "]";
return "ComposablePointcut: " + this.classFilter + ", " +this.methodMatcher;
}
}
@@ -25,12 +25,11 @@ import org.springframework.aop.MethodMatcher;
import org.springframework.util.Assert;
/**
* Static utility methods for composing
* {@link org.springframework.aop.MethodMatcher MethodMatchers}.
* Static utility methods for composing {@link MethodMatcher MethodMatchers}.
*
* <p>A MethodMatcher may be evaluated statically (based on method
* and target class) or need further evaluation dynamically
* (based on arguments at the time of method invocation).
* <p>A MethodMatcher may be evaluated statically (based on method and target
* class) or need further evaluation dynamically (based on arguments at the
* time of method invocation).
*
* @author Rod Johnson
* @author Rob Harrop
@@ -88,7 +87,7 @@ public abstract class MethodMatchers {
* asking is the subject on one or more introductions; {@code false} otherwise
* @return whether or not this method matches statically
*/
public static boolean matches(MethodMatcher mm, Method method, Class targetClass, boolean hasIntroductions) {
public static boolean matches(MethodMatcher mm, Method method, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(mm, "MethodMatcher must not be null");
return ((mm instanceof IntroductionAwareMethodMatcher &&
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) ||
@@ -113,21 +112,21 @@ public abstract class MethodMatchers {
this.mm2 = mm2;
}
public boolean matches(Method method, Class targetClass, boolean hasIntroductions) {
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
return (matchesClass1(targetClass) && MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions)) ||
(matchesClass2(targetClass) && MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions));
}
public boolean matches(Method method, Class targetClass) {
public boolean matches(Method method, Class<?> targetClass) {
return (matchesClass1(targetClass) && this.mm1.matches(method, targetClass)) ||
(matchesClass2(targetClass) && this.mm2.matches(method, targetClass));
}
protected boolean matchesClass1(Class targetClass) {
protected boolean matchesClass1(Class<?> targetClass) {
return true;
}
protected boolean matchesClass2(Class targetClass) {
protected boolean matchesClass2(Class<?> targetClass) {
return true;
}
@@ -135,7 +134,7 @@ public abstract class MethodMatchers {
return this.mm1.isRuntime() || this.mm2.isRuntime();
}
public boolean matches(Method method, Class targetClass, Object[] args) {
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
return this.mm1.matches(method, targetClass, args) || this.mm2.matches(method, targetClass, args);
}
@@ -179,12 +178,12 @@ public abstract class MethodMatchers {
}
@Override
protected boolean matchesClass1(Class targetClass) {
protected boolean matchesClass1(Class<?> targetClass) {
return this.cf1.matches(targetClass);
}
@Override
protected boolean matchesClass2(Class targetClass) {
protected boolean matchesClass2(Class<?> targetClass) {
return this.cf2.matches(targetClass);
}
@@ -225,12 +224,12 @@ public abstract class MethodMatchers {
this.mm2 = mm2;
}
public boolean matches(Method method, Class targetClass, boolean hasIntroductions) {
public boolean matches(Method method, Class<?> targetClass, boolean hasIntroductions) {
return MethodMatchers.matches(this.mm1, method, targetClass, hasIntroductions) &&
MethodMatchers.matches(this.mm2, method, targetClass, hasIntroductions);
}
public boolean matches(Method method, Class targetClass) {
public boolean matches(Method method, Class<?> targetClass) {
return this.mm1.matches(method, targetClass) && this.mm2.matches(method, targetClass);
}
@@ -238,7 +237,7 @@ public abstract class MethodMatchers {
return this.mm1.isRuntime() || this.mm2.isRuntime();
}
public boolean matches(Method method, Class targetClass, Object[] args) {
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
// Because a dynamic intersection may be composed of a static and dynamic part,
// we must avoid calling the 3-arg matches method on a dynamic matcher, as
// it will probably be an unsupported operation.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,10 +59,32 @@ public class AnnotationClassFilter implements ClassFilter {
}
public boolean matches(Class clazz) {
public boolean matches(Class<?> clazz) {
return (this.checkInherited ?
(AnnotationUtils.findAnnotation(clazz, this.annotationType) != null) :
clazz.isAnnotationPresent(this.annotationType));
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AnnotationClassFilter)) {
return false;
}
AnnotationClassFilter otherCf = (AnnotationClassFilter) other;
return (this.annotationType.equals(otherCf.annotationType) && this.checkInherited == otherCf.checkInherited);
}
@Override
public int hashCode() {
return this.annotationType.hashCode();
}
@Override
public String toString() {
return getClass().getName() + ": " + this.annotationType;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Simple Pointcut that looks for a specific Java 5 annotation
@@ -98,6 +99,36 @@ public class AnnotationMatchingPointcut implements Pointcut {
return this.methodMatcher;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AnnotationMatchingPointcut)) {
return false;
}
AnnotationMatchingPointcut that = (AnnotationMatchingPointcut) other;
return ObjectUtils.nullSafeEquals(that.classFilter, this.classFilter) &&
ObjectUtils.nullSafeEquals(that.methodMatcher, this.methodMatcher);
}
@Override
public int hashCode() {
int code = 17;
if (this.classFilter != null) {
code = 37 * code + this.classFilter.hashCode();
}
if (this.methodMatcher != null) {
code = 37 * code + this.methodMatcher.hashCode();
}
return code;
}
@Override
public String toString() {
return "AnnotationMatchingPointcut: " + this.classFilter + ", " +this.methodMatcher;
}
/**
* Factory method for an AnnotationMatchingPointcut that matches
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -73,4 +73,9 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
return this.annotationType.hashCode();
}
@Override
public String toString() {
return getClass().getName() + ": " + this.annotationType;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -50,6 +50,7 @@ import org.springframework.beans.factory.DisposableBean;
* @see #releaseTarget
* @see #destroy
*/
@SuppressWarnings("serial")
public abstract class AbstractPoolingTargetSource extends AbstractPrototypeBasedTargetSource
implements PoolingConfig, DisposableBean {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -43,6 +43,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
* @see ThreadLocalTargetSource
* @see CommonsPoolTargetSource
*/
@SuppressWarnings("serial")
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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 org.springframework.beans.BeansException;
import org.springframework.core.Constants;
/**
* TargetSource implementation that holds objects in a configurable
* Jakarta Commons Pool.
* {@link org.springframework.aop.TargetSource} implementation that holds
* objects in a configurable Apache Commons Pool.
*
* <p>By default, an instance of {@code GenericObjectPool} is created.
* Subclasses may change the type of {@code ObjectPool} used by
@@ -38,10 +38,12 @@ import org.springframework.core.Constants;
* of configuration properties that are relevant to your chosen implementation.
*
* <p>The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle}
* properties are explictly not mirrored because the implementation of
* properties are explicitly not mirrored because the implementation of
* {@code PoolableObjectFactory} used by this class does not implement
* meaningful validation. All exposed Commons Pool properties use the corresponding
* Commons Pool defaults: for example,
* meaningful validation. All exposed Commons Pool properties use the
* corresponding Commons Pool defaults.
*
* <p>Compatible with Apache Commons Pool 1.5.x and 1.6.
*
* @author Rod Johnson
* @author Rob Harrop
@@ -55,10 +57,8 @@ import org.springframework.core.Constants;
* @see #setTimeBetweenEvictionRunsMillis
* @see #setMinEvictableIdleTimeMillis
*/
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource
implements PoolableObjectFactory {
private static final long serialVersionUID = 1L;
@SuppressWarnings("serial")
public class CommonsPoolTargetSource extends AbstractPoolingTargetSource implements PoolableObjectFactory {
private static final Constants constants = new Constants(GenericObjectPool.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,9 +19,11 @@ package org.springframework.aop.target;
import org.springframework.beans.BeansException;
/**
* TargetSource that creates a new instance of the target bean for each
* request, destroying each instance on release (after each request).
* Obtains bean instances from its containing
* {@link org.springframework.aop.TargetSource} implementation that
* creates a new instance of the target bean for each request,
* destroying each instance on release (after each request).
*
* <p>Obtains bean instances from its containing
* {@link org.springframework.beans.factory.BeanFactory}.
*
* @author Rod Johnson
@@ -29,10 +31,9 @@ import org.springframework.beans.BeansException;
* @see #setBeanFactory
* @see #setTargetBeanName
*/
@SuppressWarnings("serial")
public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource {
private static final long serialVersionUID = 1L;
/**
* Obtain a new prototype instance for every call.
* @see #newPrototypeInstance()
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,9 +27,10 @@ import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.NamedThreadLocal;
/**
* Alternative to an object pool. This TargetSource uses a threading model in which
* every thread has its own copy of the target. There's no contention for targets.
* Target object creation is kept to a minimum on the running server.
* Alternative to an object pool. This {@link org.springframework.aop.TargetSource}
* uses a threading model in which every thread has its own copy of the target.
* There's no contention for targets. Target object creation is kept to a minimum
* on the running server.
*
* <p>Application code is written as to a normal pool; callers can't assume they
* will be dealing with the same instance in invocations in different threads.
@@ -47,11 +48,10 @@ import org.springframework.core.NamedThreadLocal;
* @see ThreadLocalTargetSourceStats
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@SuppressWarnings("serial")
public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
implements ThreadLocalTargetSourceStats, DisposableBean {
private static final long serialVersionUID = 1L;
/**
* ThreadLocal holding the target associated with the current
* thread. Unlike most ThreadLocals, which are static, this variable
@@ -80,10 +80,8 @@ public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
Object target = this.targetInThread.get();
if (target == null) {
if (logger.isDebugEnabled()) {
logger.debug("No target for prototype '" + getTargetBeanName() +
"' bound to thread: " +
"creating one and binding it to thread '" +
Thread.currentThread().getName() + "'");
logger.debug("No target for prototype '" + getTargetBeanName() + "' bound to thread: " +
"creating one and binding it to thread '" + Thread.currentThread().getName() + "'");
}
// Associate target with ThreadLocal.
target = newPrototypeInstance();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,16 +18,22 @@ package org.springframework.mock.staticmock;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.springframework.util.ObjectUtils;
/**
* Abstract aspect to enable mocking of methods picked out by a pointcut.
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
* indicate call stacks when mocking should be triggered, and the
* methodToMock() pointcut to pick out a method invocations to mock.
*
* <p>Sub-aspects must define:
* <ul>
* <li>the {@link #mockStaticsTestMethod()} pointcut to indicate call stacks
* when mocking should be triggered
* <li>the {@link #methodToMock()} pointcut to pick out method invocations to mock
* </ul>
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @author Sam Brannen
*/
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
@@ -35,24 +41,34 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
protected abstract pointcut methodToMock();
private boolean recording = true;
static enum CallResponse { nothing, return_, throw_ };
// Represents a list of expected calls to static entity methods
static enum CallResponse {
nothing, return_, throw_
};
/**
* Represents a list of expected calls to methods.
*/
// Public to allow inserted code to access: is this normal??
public class Expectations {
// Represents an expected call to a static entity method
/**
* Represents an expected call to a method.
*/
private class Call {
private final String signature;
private final Object[] args;
private Object responseObject; // return value or throwable
private CallResponse responseType = CallResponse.nothing;
public Call(String name, Object[] args) {
this.signature = name;
public Call(String signature, Object[] args) {
this.signature = signature;
this.args = args;
}
@@ -77,7 +93,7 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
public Object throwException(String lastSig, Object[] args) {
checkSignature(lastSig, args);
throw (RuntimeException)responseObject;
throw (RuntimeException) responseObject;
}
private void checkSignature(String lastSig, Object[] args) {
@@ -88,16 +104,29 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
throw new IllegalArgumentException("Arguments don't match");
}
}
@Override
public String toString() {
return String.format("Call with signature [%s] and arguments %s", this.signature,
ObjectUtils.nullSafeToString(args));
}
}
private List<Call> calls = new LinkedList<Call>();
// Calls already verified
/**
* The list of recorded calls.
*/
private final LinkedList<Call> calls = new LinkedList<Call>();
/**
* The number of calls already verified.
*/
private int verified;
public void verify() {
if (verified != calls.size()) {
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
}
}
@@ -105,31 +134,32 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
* Validate the call and provide the expected return value.
*/
public Object respond(String lastSig, Object[] args) {
Call call = nextCall();
CallResponse responseType = call.responseType;
if (responseType == CallResponse.return_) {
return call.returnValue(lastSig, args);
Call c = nextCall();
switch (c.responseType) {
case return_: {
return c.returnValue(lastSig, args);
}
case throw_: {
return c.throwException(lastSig, args);
}
default: {
throw new IllegalStateException("Behavior of " + c + " not specified");
}
}
else if (responseType == CallResponse.throw_) {
return call.throwException(lastSig, args);
}
else if (responseType == CallResponse.nothing) {
// do nothing
}
throw new IllegalStateException("Behavior of " + call + " not specified");
}
private Call nextCall() {
verified++;
if (verified > calls.size()) {
throw new IllegalStateException("Expected " + calls.size() + " calls, received " + verified);
throw new IllegalStateException("Expected " + calls.size() + " calls, but received " + verified);
}
return calls.get(verified);
// The 'verified' count is 1-based; whereas, 'calls' is 0-based.
return calls.get(verified - 1);
}
public void expectCall(String lastSig, Object lastArgs[]) {
Call call = new Call(lastSig, lastArgs);
calls.add(call);
public void expectCall(String lastSig, Object[] lastArgs) {
calls.add(new Call(lastSig, lastArgs));
}
public boolean hasCalls() {
@@ -137,29 +167,31 @@ public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMeth
}
public void expectReturn(Object retVal) {
Call call = calls.get(calls.size() - 1);
if (call.hasResponseSpecified()) {
throw new IllegalStateException("No static method invoked before setting return value");
Call c = calls.getLast();
if (c.hasResponseSpecified()) {
throw new IllegalStateException("No method invoked before setting return value");
}
call.setReturnVal(retVal);
c.setReturnVal(retVal);
}
public void expectThrow(Throwable throwable) {
Call call = calls.get(calls.size() - 1);
if (call.hasResponseSpecified()) {
throw new IllegalStateException("No static method invoked before setting throwable");
Call c = calls.getLast();
if (c.hasResponseSpecified()) {
throw new IllegalStateException("No method invoked before setting throwable");
}
call.setThrow(throwable);
c.setThrow(throwable);
}
}
private Expectations expectations = new Expectations();
private final Expectations expectations = new Expectations();
after() returning : mockStaticsTestMethod() {
if (recording && (expectations.hasCalls())) {
throw new IllegalStateException(
"Calls recorded, yet playback state never reached: Create expectations then call "
+ this.getClass().getSimpleName() + ".playback()");
"Calls recorded, yet playback state never reached: Create expectations then call "
+ this.getClass().getSimpleName() + ".playback()");
}
expectations.verify();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,50 +17,69 @@
package org.springframework.mock.staticmock;
/**
* Annotation-based aspect to use in test build to enable mocking static methods
* on JPA-annotated {@code @Entity} classes, as used by Roo for finders.
* Annotation-based aspect to use in test builds to enable mocking of static methods
* on JPA-annotated {@code @Entity} classes, as used by Spring Roo for so-called
* <em>finder methods</em>.
*
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
* that is annotated with the @MockStaticEntityMethods annotation.
* <p>Mocking will occur within the call stack of any method in a class (typically a
* test class) that is annotated with {@code @MockStaticEntityMethods}.
*
* <p>Also provides static methods to simplify the programming model for
* entering playback mode and setting expected return values.
* <p>This aspect also provides static methods to simplify the programming model for
* setting expectations and entering playback mode.
*
* <p>Usage:
* <ol>
* <li>Annotate a test class with @MockStaticEntityMethods.
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
* Invoke static methods on Entity classes, with each recording-mode invocation
* being followed by an invocation to the static expectReturn() or expectThrow()
* method on AnnotationDrivenStaticEntityMockingControl.
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
* <li>Call the code you wish to test that uses the static methods. Verification will
* occur automatically.
* <li>Annotate a test class with {@code @MockStaticEntityMethods}.
* <li>In each test method, {@code AnnotationDrivenStaticEntityMockingControl}
* will begin in <em>recording</em> mode.
* <li>Invoke static methods on JPA-annotated {@code @Entity} classes, with each
* recording-mode invocation being followed by an invocation of either the static
* {@link #expectReturn(Object)} method or the static {@link #expectThrow(Throwable)}
* method on {@code AnnotationDrivenStaticEntityMockingControl}.
* <li>Invoke the static {@link #playback()} method.
* <li>Call the code you wish to test that uses the static methods.
* <li>Verification will occur automatically.
* </ol>
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @author Sam Brannen
* @see MockStaticEntityMethods
*/
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
/**
* Stop recording mock calls and enter playback state
* Expect the supplied {@link Object} to be returned by the previous static
* method invocation.
* @see #playback()
*/
public static void playback() {
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
}
public static void expectReturn(Object retVal) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
}
/**
* Expect the supplied {@link Throwable} to be thrown by the previous static
* method invocation.
* @see #playback()
*/
public static void expectThrow(Throwable throwable) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
}
// Only matches directly annotated @Test methods, to allow methods in
// @MockStatics classes to invoke each other without resetting the mocking environment
/**
* Stop recording mock expectations and enter <em>playback</em> mode.
* @see #expectReturn(Object)
* @see #expectThrow(Throwable)
*/
public static void playback() {
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
}
// Apparently, the following pointcut was originally defined to only match
// methods directly annotated with @Test (in order to allow methods in
// @MockStaticEntityMethods classes to invoke each other without resetting
// the mocking environment); however, this is no longer the case. The current
// pointcut applies to all public methods in @MockStaticEntityMethods classes.
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,11 +22,13 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to indicate a test class for whose @Test methods
* static methods on Entity classes should be mocked. See
* {@code AbstractMethodMockingControl}.
* Annotation to indicate a test class for whose {@code @Test} methods
* static methods on JPA-annotated {@code @Entity} classes should be mocked.
*
* <p>See {@link AnnotationDrivenStaticEntityMockingControl} for details.
*
* @author Rod Johnson
* @author Sam Brannen
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,11 +32,11 @@ import org.springframework.scheduling.annotation.EnableAsync;
* @since 3.1
* @see EnableAsync
* @see org.springframework.scheduling.annotation.AsyncConfigurationSelector
* @see org.springframework.scheduling.annotation.ProxyAsyncConfiguration
*/
@Configuration
public class AspectJAsyncConfiguration extends AbstractAsyncConfiguration {
@Override
@Bean(name=AnnotationConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AnnotationAsyncExecutionAspect asyncAdvisor() {
@@ -1,148 +0,0 @@
/*
* Copyright 2002-2012 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.mock.staticmock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectReturn;
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.expectThrow;
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.playback;
import javax.persistence.PersistenceException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Test for static entity mocking framework.
* @author Rod Johnson
* @author Ramnivas Laddad
*
*/
@MockStaticEntityMethods
@RunWith(JUnit4.class)
public class AnnotationDrivenStaticEntityMockingControlTest {
@Test
public void testNoArgIntReturn() {
int expectedCount = 13;
Person.countPeople();
expectReturn(expectedCount);
playback();
assertEquals(expectedCount, Person.countPeople());
}
@Test(expected=PersistenceException.class)
public void testNoArgThrows() {
Person.countPeople();
expectThrow(new PersistenceException());
playback();
Person.countPeople();
}
@Test
public void testArgMethodMatches() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
assertEquals(found, Person.findPerson(id));
}
@Test
public void testLongSeriesOfCalls() {
long id1 = 13;
long id2 = 24;
Person found1 = new Person();
Person.findPerson(id1);
expectReturn(found1);
Person found2 = new Person();
Person.findPerson(id2);
expectReturn(found2);
Person.findPerson(id1);
expectReturn(found1);
Person.countPeople();
expectReturn(0);
playback();
assertEquals(found1, Person.findPerson(id1));
assertEquals(found2, Person.findPerson(id2));
assertEquals(found1, Person.findPerson(id1));
assertEquals(0, Person.countPeople());
}
// Note delegation is used when tests are invalid and should fail, as otherwise
// the failure will occur on the verify() method in the aspect after
// this method returns, failing the test case
@Test
public void testArgMethodNoMatchExpectReturn() {
try {
new Delegate().testArgMethodNoMatchExpectReturn();
fail();
} catch (IllegalArgumentException expected) {
}
}
@Test(expected=IllegalArgumentException.class)
public void testArgMethodNoMatchExpectThrow() {
new Delegate().testArgMethodNoMatchExpectThrow();
}
private void called(Person found, long id) {
assertEquals(found, Person.findPerson(id));
}
@Test
public void testReentrant() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
called(found, id);
}
@Test(expected=IllegalStateException.class)
public void testRejectUnexpectedCall() {
new Delegate().rejectUnexpectedCall();
}
@Test(expected=IllegalStateException.class)
public void testFailTooFewCalls() {
new Delegate().failTooFewCalls();
}
@Test
public void testEmpty() {
// Test that verification check doesn't blow up if no replay() call happened
}
@Test(expected=IllegalStateException.class)
public void testDoesntEverReplay() {
new Delegate().doesntEverReplay();
}
@Test(expected=IllegalStateException.class)
public void testDoesntEverSetReturn() {
new Delegate().doesntEverSetReturn();
}
}
@@ -0,0 +1,170 @@
/*
* Copyright 2002-2014 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.mock.staticmock;
import java.rmi.RemoteException;
import javax.persistence.PersistenceException;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
/**
* Tests for Spring's static entity mocking framework (i.e., @{@link MockStaticEntityMethods}
* and {@link AnnotationDrivenStaticEntityMockingControl}).
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @author Sam Brannen
*/
@MockStaticEntityMethods
public class AnnotationDrivenStaticEntityMockingControlTests {
@Test
public void noArgumentMethodInvocationReturnsInt() {
int expectedCount = 13;
Person.countPeople();
expectReturn(expectedCount);
playback();
assertEquals(expectedCount, Person.countPeople());
}
@Test(expected = PersistenceException.class)
public void noArgumentMethodInvocationThrowsException() {
Person.countPeople();
expectThrow(new PersistenceException());
playback();
Person.countPeople();
}
@Test
public void methodArgumentsMatch() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
assertEquals(found, Person.findPerson(id));
}
@Test
public void longSeriesOfCalls() {
long id1 = 13;
long id2 = 24;
Person found1 = new Person();
Person.findPerson(id1);
expectReturn(found1);
Person found2 = new Person();
Person.findPerson(id2);
expectReturn(found2);
Person.findPerson(id1);
expectReturn(found1);
Person.countPeople();
expectReturn(0);
playback();
assertEquals(found1, Person.findPerson(id1));
assertEquals(found2, Person.findPerson(id2));
assertEquals(found1, Person.findPerson(id1));
assertEquals(0, Person.countPeople());
}
@Test(expected = IllegalArgumentException.class)
public void methodArgumentsDoNotMatchAndReturnsObject() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
AnnotationDrivenStaticEntityMockingControl.playback();
assertEquals(found, Person.findPerson(id + 1));
}
@Test(expected = IllegalArgumentException.class)
public void methodArgumentsDoNotMatchAndThrowsException() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
AnnotationDrivenStaticEntityMockingControl.playback();
assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void reentrant() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
called(found, id);
}
private void called(Person found, long id) {
assertEquals(found, Person.findPerson(id));
}
@Test(expected = IllegalStateException.class)
public void rejectUnexpectedCall() {
AnnotationDrivenStaticEntityMockingControl.playback();
Person.countPeople();
}
@Test(expected = IllegalStateException.class)
public void tooFewCalls() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
AnnotationDrivenStaticEntityMockingControl.playback();
assertEquals(found, Person.findPerson(id));
}
@Test
public void empty() {
// Test that verification check doesn't blow up if no replay() call happened.
}
@Test(expected = IllegalStateException.class)
public void doesNotEnterPlaybackMode() {
Person.countPeople();
}
@Test(expected = IllegalStateException.class)
public void doesNotSetExpectedReturnValue() {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
}
/**
* Note: this test method currently does NOT actually verify that the mock
* verification fails.
*/
// TODO Determine if it's possible for a mock verification failure to fail a test in
// JUnit 4+ if the test method itself throws an expected exception.
@Test(expected = RemoteException.class)
public void verificationFailsEvenWhenTestFailsInExpectedManner() throws Exception {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
// No calls in order to allow verification failure
throw new RemoteException();
}
}
@@ -1,92 +0,0 @@
/*
* Copyright 2002-2012 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.mock.staticmock;
import static org.junit.Assert.assertEquals;
import java.rmi.RemoteException;
import javax.persistence.PersistenceException;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
import org.springframework.mock.staticmock.MockStaticEntityMethods;
//Used because verification failures occur after method returns,
//so we can't test for them in the test case itself
@MockStaticEntityMethods
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
public class Delegate {
@Test
public void testArgMethodNoMatchExpectReturn() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
AnnotationDrivenStaticEntityMockingControl.playback();
assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void testArgMethodNoMatchExpectThrow() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
AnnotationDrivenStaticEntityMockingControl.playback();
assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void failTooFewCalls() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
AnnotationDrivenStaticEntityMockingControl.playback();
assertEquals(found, Person.findPerson(id));
}
@Test
public void doesntEverReplay() {
Person.countPeople();
}
@Test
public void doesntEverSetReturn() {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
}
@Test
public void rejectUnexpectedCall() {
AnnotationDrivenStaticEntityMockingControl.playback();
Person.countPeople();
}
@Test(expected=RemoteException.class)
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
// No calls to allow verification failure
throw new RemoteException();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,33 +20,36 @@ import java.beans.BeanInfo;
import java.beans.IntrospectionException;
/**
* Strategy for creating {@link BeanInfo} instances.
* Strategy interface for creating {@link BeanInfo} instances for Spring beans.
* Can be used to plug in custom bean property resolution strategies (e.g. for other
* languages on the JVM) or more efficient {@link BeanInfo} retrieval algorithms.
*
* <p>BeanInfoFactories are are instantiated by the {@link CachedIntrospectionResults},
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader} utility
* class.
* by using the {@link org.springframework.core.io.support.SpringFactoriesLoader}
* utility class.
*
* When a {@link BeanInfo} is to be created, the {@code CachedIntrospectionResults}
* will iterate through the discovered factories, calling {@link
* #getBeanInfo(Class)} on each one. If {@code null} is returned, the next factory will
* be queried. If none of the factories support the class, an standard {@link BeanInfo}
* is created as a default.
* will iterate through the discovered factories, calling {@link #getBeanInfo(Class)}
* on each one. If {@code null} is returned, the next factory will be queried.
* If none of the factories support the class, a standard {@link BeanInfo} will be
* created as a default.
*
* <p>Note that the {@link org.springframework.core.io.support.SpringFactoriesLoader}
* sorts the {@code BeanInfoFactory} instances by
* {@link org.springframework.core.annotation.Order @Order}, so that ones with
* a higher precedence come first.
* {@link org.springframework.core.annotation.Order @Order}, so that ones with a
* higher precedence come first.
*
* @author Arjen Poutsma
* @since 3.2
* @see CachedIntrospectionResults
* @see org.springframework.core.io.support.SpringFactoriesLoader
*/
public interface BeanInfoFactory {
/**
* Returns the bean info for the given class, if supported.
*
* Return the bean info for the given class, if supported.
* @param beanClass the bean class
* @return the bean info, or {@code null} if not the given class is not supported
* @return the BeanInfo, or {@code null} if the given class is not supported
* @throws IntrospectionException in case of exceptions
*/
BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException;
@@ -600,7 +600,7 @@ public abstract class BeanUtils {
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null &&
writeMethod.getParameterTypes()[0].isAssignableFrom(readMethod.getReturnType())) {
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,7 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
* @return the type of the wrapped bean instance,
* or {@code null} if no wrapped object has been set
*/
Class getWrappedClass();
Class<?> getWrappedClass();
/**
* Obtain the PropertyDescriptors for the wrapped object
@@ -79,11 +79,13 @@ public interface BeanWrapper extends ConfigurablePropertyAccessor {
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
/**
* Set whether this BeanWrapper should attempt to "auto-grow" a nested path that contains a null value.
* <p>If "true", a null path location will be populated with a default object value and traversed
* instead of resulting in a {@link NullValueInNestedPathException}. Turning this flag on also
* enables auto-growth of collection elements when accessing an out-of-bounds index.
* <p>Default is "false" on a plain BeanWrapper.
* Set whether this BeanWrapper should attempt to "auto-grow" a
* nested path that contains a {@code null} value.
* <p>If {@code true}, a {@code null} path location will be populated
* with a default object value and traversed instead of resulting in a
* {@link NullValueInNestedPathException}. Turning this flag on also enables
* auto-growth of collection elements when accessing an out-of-bounds index.
* <p>Default is {@code false} on a plain BeanWrapper.
*/
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -223,7 +223,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
return this.object;
}
public final Class getWrappedClass() {
public final Class<?> getWrappedClass() {
return (this.object != null ? this.object.getClass() : null);
}
@@ -246,7 +246,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
* Return the class of the root object at the top of the path of this BeanWrapper.
* @see #getNestedPath
*/
public final Class getRootClass() {
public final Class<?> getRootClass() {
return (this.rootObject != null ? this.rootObject.getClass() : null);
}
@@ -304,7 +304,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
* Needs to be called when the target object changes.
* @param clazz the class to introspect
*/
protected void setIntrospectionClass(Class clazz) {
protected void setIntrospectionClass(Class<?> clazz) {
if (this.cachedIntrospectionResults != null &&
!clazz.equals(this.cachedIntrospectionResults.getBeanClass())) {
this.cachedIntrospectionResults = null;
@@ -352,7 +352,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
@Override
public Class getPropertyType(String propertyName) throws BeansException {
public Class<?> getPropertyType(String propertyName) throws BeansException {
try {
PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
if (pd != null) {
@@ -366,7 +366,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
// Check to see if there is a custom editor,
// which might give an indication on the desired target type.
Class editorType = guessPropertyTypeFromEditors(propertyName);
Class<?> editorType = guessPropertyTypeFromEditors(propertyName);
if (editorType != null) {
return editorType;
}
@@ -485,13 +485,13 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"No property '" + propertyName + "' found");
}
return convertForProperty(propertyName, null, value, pd);
return convertForProperty(propertyName, null, value, new TypeDescriptor(property(pd)));
}
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, PropertyDescriptor pd)
private Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td)
throws TypeMismatchException {
return convertIfNecessary(propertyName, oldValue, newValue, pd.getPropertyType(), new TypeDescriptor(property(pd)));
return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
}
private Property property(PropertyDescriptor pd) {
@@ -699,7 +699,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
return nestedBw.getPropertyValue(tokens);
}
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
@SuppressWarnings("unchecked")
private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
@@ -766,20 +767,20 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
else if (value instanceof List) {
int index = Integer.parseInt(key);
List list = (List) value;
List<Object> list = (List<Object>) value;
growCollectionIfNecessary(list, index, indexedPropertyName, pd, i + 1);
value = list.get(index);
}
else if (value instanceof Set) {
// Apply index to Iterator in case of a Set.
Set set = (Set) value;
Set<Object> set = (Set<Object>) value;
int index = Integer.parseInt(key);
if (index < 0 || index >= set.size()) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Cannot get element with index " + index + " from Set of size " +
set.size() + ", accessed using property path '" + propertyName + "'");
}
Iterator it = set.iterator();
Iterator<Object> it = set.iterator();
for (int j = 0; it.hasNext(); j++) {
Object elem = it.next();
if (j == index) {
@@ -789,11 +790,12 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
}
else if (value instanceof Map) {
Map map = (Map) value;
Map<Object, Object> map = (Map<Object, Object>) value;
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), i + 1);
// IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values.
TypeDescriptor typeDescriptor = mapKeyType != null ? TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class);
TypeDescriptor typeDescriptor = (mapKeyType != null ?
TypeDescriptor.valueOf(mapKeyType) : TypeDescriptor.valueOf(Object.class));
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor);
value = map.get(convertedMapKey);
}
@@ -850,16 +852,15 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
}
@SuppressWarnings("unchecked")
private void growCollectionIfNecessary(
Collection collection, int index, String name, PropertyDescriptor pd, int nestingLevel) {
private void growCollectionIfNecessary(Collection<Object> collection, int index, String name,
PropertyDescriptor pd, int nestingLevel) {
if (!this.autoGrowNestedPaths) {
return;
}
int size = collection.size();
if (index >= size && index < this.autoGrowCollectionLimit) {
Class elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), nestingLevel);
if (elementType != null) {
for (int i = collection.size(); i < index + 1; i++) {
collection.add(newValue(elementType, name));
@@ -945,7 +946,7 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
if (propValue.getClass().isArray()) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = propValue.getClass().getComponentType();
Class<?> requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(key);
Object oldValue = null;
try {
@@ -963,9 +964,9 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
else if (propValue instanceof List) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
Class<?> requiredType = GenericCollectionTypeResolver.getCollectionReturnType(
pd.getReadMethod(), tokens.keys.length);
List list = (List) propValue;
List<Object> list = (List<Object>) propValue;
int index = Integer.parseInt(key);
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
@@ -1000,11 +1001,11 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
else if (propValue instanceof Map) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
Class<?> mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(
pd.getReadMethod(), tokens.keys.length);
Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
Class<?> mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(
pd.getReadMethod(), tokens.keys.length);
Map map = (Map) propValue;
Map<Object, Object> map = (Map<Object, Object>) propValue;
// IMPORTANT: Do not pass full property name in here - property editors
// must not kick in for map keys but rather only for map values.
TypeDescriptor typeDescriptor = (mapKeyType != null ?
@@ -1094,7 +1095,8 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
}
}
valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd);
valueToApply = convertForProperty(
propertyName, oldValue, originalValue, new TypeDescriptor(property(pd)));
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +33,7 @@ import java.util.WeakHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.SpringProperties;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -50,6 +51,18 @@ import org.springframework.util.StringUtils;
* implements the factory design pattern, using a private constructor and
* a static {@link #forClass(Class)} factory method to obtain instances.
*
* <p>Note that for caching to work effectively, some preconditions need to be met:
* Prefer an arrangement where the Spring jars live in the same ClassLoader as the
* application classes, which allows for clean caching along with the application's
* lifecycle in any case. For a web application, consider declaring a local
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
*
* <p>In case of a non-clean ClassLoader arrangement without a cleanup listener having
* been set up, this class will fall back to a weak-reference-based caching model that
* recreates much-requested entries every time the garbage collector removed them. In
* such a scenario, consider the {@link #IGNORE_BEANINFO_PROPERTY_NAME} system property.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 05 May 2001
@@ -59,11 +72,34 @@ import org.springframework.util.StringUtils;
*/
public class CachedIntrospectionResults {
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
/**
* System property that instructs Spring to use the {@link Introspector#IGNORE_ALL_BEANINFO}
* mode when calling the JavaBeans {@link Introspector}: "spring.beaninfo.ignore", with a
* value of "true" skipping the search for {@code BeanInfo} classes (typically for scenarios
* where no such classes are being defined for beans in the application in the first place).
* <p>The default is "false", considering all {@code BeanInfo} metadata classes, like for
* standard {@link Introspector#getBeanInfo(Class)} calls. Consider switching this flag to
* "true" if you experience repeated ClassLoader access for non-existing {@code BeanInfo}
* classes, in case such access is expensive on startup or on lazy loading.
* <p>Note that such an effect may also indicate a scenario where caching doesn't work
* effectively: Prefer an arrangement where the Spring jars live in the same ClassLoader
* as the application classes, which allows for clean caching along with the application's
* lifecycle in any case. For a web application, consider declaring a local
* {@link org.springframework.web.util.IntrospectorCleanupListener} in {@code web.xml}
* in case of a multi-ClassLoader layout, which will allow for effective caching as well.
* @see Introspector#getBeanInfo(Class, int)
*/
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
/** Stores the BeanInfoFactory instances */
private static List<BeanInfoFactory> beanInfoFactories =
SpringFactoriesLoader.loadFactories(BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
/**
* Set of ClassLoaders that this CachedIntrospectionResults class will always
@@ -179,8 +215,8 @@ public class CachedIntrospectionResults {
synchronized (acceptedClassLoaders) {
acceptedLoaderArray = acceptedClassLoaders.toArray(new ClassLoader[acceptedClassLoaders.size()]);
}
for (ClassLoader registeredLoader : acceptedLoaderArray) {
if (isUnderneathClassLoader(classLoader, registeredLoader)) {
for (ClassLoader acceptedLoader : acceptedLoaderArray) {
if (isUnderneathClassLoader(classLoader, acceptedLoader)) {
return true;
}
}
@@ -238,20 +274,25 @@ public class CachedIntrospectionResults {
}
if (beanInfo == null) {
// If none of the factories supported the class, fall back to the default
beanInfo = Introspector.getBeanInfo(beanClass);
beanInfo = (shouldIntrospectorIgnoreBeaninfoClasses ?
Introspector.getBeanInfo(beanClass, Introspector.IGNORE_ALL_BEANINFO) :
Introspector.getBeanInfo(beanClass));
}
this.beanInfo = beanInfo;
// Immediately remove class from Introspector cache, to allow for proper
// garbage collection on class loader shutdown - we cache it here anyway,
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
// Introspector does not use WeakReferences as values of its WeakHashMap!
Class<?> classToFlush = beanClass;
do {
Introspector.flushFromCaches(classToFlush);
classToFlush = classToFlush.getSuperclass();
// Only bother with flushFromCaches if the Introspector actually cached...
if (!shouldIntrospectorIgnoreBeaninfoClasses) {
// Immediately remove class from Introspector cache, to allow for proper
// garbage collection on class loader shutdown - we cache it here anyway,
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
// Introspector does not use WeakReferences as values of its WeakHashMap!
Class<?> classToFlush = beanClass;
do {
Introspector.flushFromCaches(classToFlush);
classToFlush = classToFlush.getSuperclass();
}
while (classToFlush != null && classToFlush != Object.class);
}
while (classToFlush != null);
if (logger.isTraceEnabled()) {
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,8 +25,8 @@ import org.springframework.core.Ordered;
/**
* {@link BeanInfoFactory} implementation that evaluates whether bean classes have
* "non-standard" JavaBeans setter methods and are thus candidates for introspection by
* Spring's {@link ExtendedBeanInfo}.
* "non-standard" JavaBeans setter methods and are thus candidates for introspection
* by Spring's (package-visible) {@code ExtendedBeanInfo} implementation.
*
* <p>Ordered at {@link Ordered#LOWEST_PRECEDENCE} to allow other user-defined
* {@link BeanInfoFactory} types to take precedence.
@@ -34,20 +34,20 @@ import org.springframework.core.Ordered;
* @author Chris Beams
* @since 3.2
* @see BeanInfoFactory
* @see CachedIntrospectionResults
*/
public class ExtendedBeanInfoFactory implements Ordered, BeanInfoFactory {
public class ExtendedBeanInfoFactory implements BeanInfoFactory, Ordered {
/**
* Return a new {@link ExtendedBeanInfo} for the given bean class.
* Return an {@link ExtendedBeanInfo} for the given bean class, if applicable.
*/
public BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException {
return supports(beanClass) ?
new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null;
return (supports(beanClass) ? new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass)) : null);
}
/**
* Return whether the given bean class declares or inherits any non-void returning
* JavaBeans or <em>indexed property</em> setter methods.
* Return whether the given bean class declares or inherits any non-void
* returning bean property or indexed property setter methods.
*/
private boolean supports(Class<?> beanClass) {
for (Method method : beanClass.getMethods()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -220,8 +220,8 @@ class TypeConverterDelegate {
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
if (firstAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
Constructor strCtor = requiredType.getConstructor(String.class);
return (T) BeanUtils.instantiateClass(strCtor, convertedValue);
Constructor<T> strCtor = requiredType.getConstructor(String.class);
return BeanUtils.instantiateClass(strCtor, convertedValue);
}
catch (NoSuchMethodException ex) {
// proceed with field lookup
@@ -289,15 +289,15 @@ class TypeConverterDelegate {
if (index > - 1) {
String enumType = trimmedValue.substring(0, index);
String fieldName = trimmedValue.substring(index + 1);
ClassLoader loader = this.targetObject.getClass().getClassLoader();
ClassLoader cl = this.targetObject.getClass().getClassLoader();
try {
Class<?> enumValueType = loader.loadClass(enumType);
Class<?> enumValueType = ClassUtils.forName(enumType, cl);
Field enumField = enumValueType.getField(fieldName);
convertedValue = enumField.get(null);
}
catch (ClassNotFoundException ex) {
if(logger.isTraceEnabled()) {
logger.trace("Enum class [" + enumType + "] cannot be loaded from [" + loader + "]", ex);
logger.trace("Enum class [" + enumType + "] cannot be loaded", ex);
}
}
catch (Throwable ex) {
@@ -331,7 +331,7 @@ class TypeConverterDelegate {
* @param requiredType the type to find an editor for
* @return the corresponding editor, or {@code null} if none
*/
private PropertyEditor findDefaultEditor(Class requiredType) {
private PropertyEditor findDefaultEditor(Class<?> requiredType) {
PropertyEditor editor = null;
if (requiredType != null) {
// No custom editor -> check BeanWrapperImpl's default editors.
@@ -496,7 +496,7 @@ class TypeConverterDelegate {
@SuppressWarnings("unchecked")
private Collection convertToTypedCollection(
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
Collection original, String propertyName, Class<?> requiredType, TypeDescriptor typeDescriptor) {
if (!Collection.class.isAssignableFrom(requiredType)) {
return original;
@@ -578,7 +578,7 @@ class TypeConverterDelegate {
@SuppressWarnings("unchecked")
private Map convertToTypedMap(
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
Map original, String propertyName, Class<?> requiredType, TypeDescriptor typeDescriptor) {
if (!Map.class.isAssignableFrom(requiredType)) {
return original;
@@ -674,7 +674,7 @@ class TypeConverterDelegate {
null);
}
private boolean canCreateCopy(Class requiredType) {
private boolean canCreateCopy(Class<?> requiredType) {
return (!requiredType.isInterface() && !Modifier.isAbstract(requiredType.getModifiers()) &&
Modifier.isPublic(requiredType.getModifiers()) && ClassUtils.hasConstructor(requiredType));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,6 @@ package org.springframework.beans.factory.access.el;
import java.beans.FeatureDescriptor;
import java.util.Iterator;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
@@ -78,8 +77,14 @@ public abstract class SpringBeanELResolver extends ELResolver {
String beanName = property.toString();
BeanFactory bf = getBeanFactory(elContext);
if (bf.containsBean(beanName)) {
throw new PropertyNotWritableException(
"Variable '" + beanName + "' refers to a Spring bean which by definition is not writable");
if (value == bf.getBean(beanName)) {
// Setting the bean reference to the same value is alright - can simply be ignored...
elContext.setPropertyResolved(true);
}
else {
throw new PropertyNotWritableException(
"Variable '" + beanName + "' refers to a Spring bean which by definition is not writable");
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -135,9 +135,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
@@ -265,10 +265,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
if (requiredConstructor == null && defaultConstructor != null) {
candidates.add(defaultConstructor);
}
candidateConstructors = candidates.toArray(new Constructor[candidates.size()]);
candidateConstructors = candidates.toArray(new Constructor<?>[candidates.size()]);
}
else {
candidateConstructors = new Constructor[0];
candidateConstructors = new Constructor<?>[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
@@ -314,10 +314,10 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
@@ -90,6 +90,11 @@ public class InjectionMetadata {
}
public static boolean needsRefresh(InjectionMetadata metadata, Class<?> clazz) {
return (metadata == null || !metadata.targetClass.equals(clazz));
}
public static abstract class InjectedElement {
protected final Member member;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,9 +71,9 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
@SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() {
this.qualifierTypes.add(Qualifier.class);
ClassLoader cl = QualifierAnnotationAutowireCandidateResolver.class.getClassLoader();
try {
this.qualifierTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Qualifier"));
this.qualifierTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Qualifier", QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -206,7 +206,7 @@ public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfi
visitor.visitBeanDefinition(bd);
}
catch (Exception ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage());
throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,8 @@ import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.core.Constants;
import org.springframework.core.SpringProperties;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
import org.springframework.util.StringValueResolver;
@@ -82,7 +84,8 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
private boolean searchSystemEnvironment = true;
private boolean searchSystemEnvironment =
!SpringProperties.getFlag(AbstractEnvironment.IGNORE_GETENV_PROPERTY_NAME);
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -1373,7 +1373,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (System.getSecurityManager()!= null) {
if (System.getSecurityManager() != null) {
if (bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
@@ -1666,7 +1666,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/**
* Special DependencyDescriptor variant for autowire="byType".
* Special DependencyDescriptor variant for Spring's good old autowire="byType" mode.
* Always optional; never considering the parameter name for choosing a primary candidate.
*/
@SuppressWarnings("serial")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,8 +38,8 @@ import org.springframework.util.StringUtils;
/**
* Base class for concrete, full-fledged
* {@link org.springframework.beans.factory.config.BeanDefinition} classes,
* factoring out common properties of {@link RootBeanDefinition} and
* {@link ChildBeanDefinition}.
* factoring out common properties of {@link GenericBeanDefinition},
* {@link RootBeanDefinition} and {@link ChildBeanDefinition}.
*
* <p>The autowire constants match the ones defined in the
* {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
@@ -123,11 +123,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
public static final int DEPENDENCY_CHECK_ALL = 3;
/**
* Constant that indicates the container should attempt to infer the {@link
* #setDestroyMethodName destroy method name} for a bean as opposed to explicit
* specification of a method name. The value {@value} is specifically designed to
* include characters otherwise illegal in a method name, ensuring no possibility of
* collisions with legitimately named methods having the same name.
* Constant that indicates the container should attempt to infer the
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
* explicit specification of a method name. The value {@value} is specifically
* designed to include characters otherwise illegal in a method name, ensuring
* no possibility of collisions with legitimately named methods having the same
* name.
* <p>Currently, the method names detected during destroy method inference
* are "close" and "shutdown", if present on the specific bean class.
*/
public static final String INFER_METHOD = "(inferred)";
@@ -383,7 +386,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
throw new IllegalStateException(
"Bean class name [" + beanClassObject + "] has not been resolved into an actual Class");
}
return (Class) beanClassObject;
return (Class<?>) beanClassObject;
}
public void setBeanClassName(String beanClassName) {
@@ -393,7 +396,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
public String getBeanClassName() {
Object beanClassObject = this.beanClass;
if (beanClassObject instanceof Class) {
return ((Class) beanClassObject).getName();
return ((Class<?>) beanClassObject).getName();
}
else {
return (String) beanClassObject;
@@ -408,12 +411,12 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
* @return the resolved bean class
* @throws ClassNotFoundException if the class name could be resolved
*/
public Class resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
public Class<?> resolveBeanClass(ClassLoader classLoader) throws ClassNotFoundException {
String className = getBeanClassName();
if (className == null) {
return null;
}
Class resolvedClass = ClassUtils.forName(className, classLoader);
Class<?> resolvedClass = ClassUtils.forName(className, classLoader);
this.beanClass = resolvedClass;
return resolvedClass;
}
@@ -551,8 +554,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
// Work out whether to apply setter autowiring or constructor autowiring.
// If it has a no-arg constructor it's deemed to be setter autowiring,
// otherwise we'll try constructor autowiring.
Constructor[] constructors = getBeanClass().getConstructors();
for (Constructor constructor : constructors) {
Constructor<?>[] constructors = getBeanClass().getConstructors();
for (Constructor<?> constructor : constructors) {
if (constructor.getParameterTypes().length == 0) {
return AUTOWIRE_BY_TYPE;
}
@@ -677,7 +680,8 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
/**
* Specify whether to allow access to non-public constructors and methods,
* for the case of externalized metadata pointing to those.
* for the case of externalized metadata pointing to those. The default is
* {@code true}; switch this to {@code false} for public access only.
* <p>This applies to constructor resolution, factory method resolution,
* and also init/destroy methods. Bean property accessors have to be public
* in any case and are not affected by this setting.
@@ -699,7 +703,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
/**
* Specify whether to resolve constructors in lenient mode ({@code true},
* which is the default) or to switch to strict resolution (throwing an exception
* in case of ambigious constructors that all match when converting the arguments,
* in case of ambiguous constructors that all match when converting the arguments,
* whereas lenient mode would use the one with the 'closest' type matches).
*/
public void setLenientConstructorResolution(boolean lenientConstructorResolution) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,6 +81,7 @@ class BeanDefinitionValueResolver {
this.typeConverter = typeConverter;
}
/**
* Given a PropertyValue, return a value, resolving any references to other
* beans in the factory if necessary. The value could be:
@@ -123,7 +124,9 @@ class BeanDefinitionValueResolver {
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
return resolveInnerBean(argName, "(inner bean)", bd);
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
@@ -164,7 +167,7 @@ class BeanDefinitionValueResolver {
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
for (Map.Entry propEntry : original.entrySet()) {
for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
Object propKey = propEntry.getKey();
Object propValue = propEntry.getValue();
if (propKey instanceof TypedStringValue) {
@@ -256,20 +259,25 @@ class BeanDefinitionValueResolver {
mbd = this.beanFactory.getMergedBeanDefinition(innerBeanName, innerBd, this.beanDefinition);
// Check given bean name whether it is unique. If not already unique,
// add counter - increasing the counter until the name is unique.
String actualInnerBeanName = adaptInnerBeanName(innerBeanName);
String actualInnerBeanName = innerBeanName;
if (mbd.isSingleton()) {
actualInnerBeanName = adaptInnerBeanName(innerBeanName);
}
this.beanFactory.registerContainedBean(actualInnerBeanName, this.beanName);
// Guarantee initialization of beans that the inner bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
this.beanFactory.getBean(dependsOnBean);
this.beanFactory.registerDependentBean(dependsOnBean, actualInnerBeanName);
this.beanFactory.getBean(dependsOnBean);
}
}
// Actually create the inner bean instance now...
Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
if (innerBean instanceof FactoryBean) {
boolean synthetic = mbd.isSynthetic();
return this.beanFactory.getObjectFromFactoryBean((FactoryBean) innerBean, actualInnerBeanName, !synthetic);
return this.beanFactory.getObjectFromFactoryBean(
(FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
}
else {
return innerBean;
@@ -344,7 +352,7 @@ class BeanDefinitionValueResolver {
/**
* For each element in the managed list, resolve reference if necessary.
*/
private List resolveManagedList(Object argName, List<?> ml) {
private List<?> resolveManagedList(Object argName, List<?> ml) {
List<Object> resolved = new ArrayList<Object>(ml.size());
for (int i = 0; i < ml.size(); i++) {
resolved.add(
@@ -356,7 +364,7 @@ class BeanDefinitionValueResolver {
/**
* For each element in the managed set, resolve reference if necessary.
*/
private Set resolveManagedSet(Object argName, Set<?> ms) {
private Set<?> resolveManagedSet(Object argName, Set<?> ms) {
Set<Object> resolved = new LinkedHashSet<Object>(ms.size());
int i = 0;
for (Object m : ms) {
@@ -369,9 +377,9 @@ class BeanDefinitionValueResolver {
/**
* For each element in the managed map, resolve reference if necessary.
*/
private Map resolveManagedMap(Object argName, Map<?, ?> mm) {
private Map<?, ?> resolveManagedMap(Object argName, Map<?, ?> mm) {
Map<Object, Object> resolved = new LinkedHashMap<Object, Object>(mm.size());
for (Map.Entry entry : mm.entrySet()) {
for (Map.Entry<?, ?> entry : mm.entrySet()) {
Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());
Object resolvedValue = resolveValueIfNecessary(
new KeyedArgName(argName, entry.getKey()), entry.getValue());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cglib.core.SpringNamingPolicy;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
@@ -72,7 +72,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
@Override
protected Object instantiateWithMethodInjection(
RootBeanDefinition beanDefinition, String beanName, BeanFactory owner,
Constructor ctor, Object[] args) {
Constructor<?> ctor, Object[] args) {
return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args);
}
@@ -104,9 +104,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
* Ignored if the ctor parameter is {@code null}.
* @return new instance of the dynamically generated class
*/
public Object instantiate(Constructor ctor, Object[] args) {
public Object instantiate(Constructor<?> ctor, Object[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
NoOp.INSTANCE,
@@ -114,9 +115,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
new ReplaceOverrideMethodInterceptor()
});
return (ctor == null) ?
enhancer.create() :
enhancer.create(ctor.getParameterTypes(), args);
return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
}
@@ -17,6 +17,7 @@
package org.springframework.beans.factory.support;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.util.ObjectUtils;
@@ -127,7 +128,7 @@ public class ChildBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public ChildBeanDefinition(ChildBeanDefinition original) {
super(original);
super((BeanDefinition) original);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,12 +54,9 @@ import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Helper class for resolving constructors and factory methods.
* Delegate for resolving constructors and factory methods.
* Performs constructor resolution through argument matching.
*
* <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
* Used by {@link AbstractAutowireCapableBeanFactory}.
*
* @author Juergen Hoeller
* @author Rob Harrop
* @author Mark Fisher
@@ -103,12 +100,12 @@ class ConstructorResolver {
* @return a BeanWrapper for the new instance
*/
public BeanWrapper autowireConstructor(
final String beanName, final RootBeanDefinition mbd, Constructor[] chosenCtors, final Object[] explicitArgs) {
final String beanName, final RootBeanDefinition mbd, Constructor<?>[] chosenCtors, final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor constructorToUse = null;
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
@@ -118,7 +115,7 @@ class ConstructorResolver {
else {
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
argsToUse = mbd.resolvedConstructorArguments;
@@ -149,7 +146,7 @@ class ConstructorResolver {
}
// Take specified constructors, if any.
Constructor[] candidates = chosenCtors;
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
@@ -164,7 +161,7 @@ class ConstructorResolver {
}
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor> ambiguousConstructors = null;
Set<Constructor<?>> ambiguousConstructors = null;
List<Exception> causes = null;
for (int i = 0; i < candidates.length; i++) {
@@ -185,7 +182,7 @@ class ConstructorResolver {
try {
String[] paramNames = null;
if (constructorPropertiesAnnotationAvailable) {
paramNames = ConstructorPropertiesChecker.evaluateAnnotation(candidate, paramTypes.length);
paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
}
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
@@ -239,7 +236,7 @@ class ConstructorResolver {
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<Constructor>();
ambiguousConstructors = new LinkedHashSet<Constructor<?>>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
@@ -267,7 +264,7 @@ class ConstructorResolver {
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor ctorToUse = constructorToUse;
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
@@ -295,18 +292,22 @@ class ConstructorResolver {
* @param mbd the bean definition to check
*/
public void resolveFactoryMethodIfPossible(RootBeanDefinition mbd) {
Class factoryClass;
Class<?> factoryClass;
boolean isStatic;
if (mbd.getFactoryBeanName() != null) {
factoryClass = this.beanFactory.getType(mbd.getFactoryBeanName());
isStatic = false;
}
else {
factoryClass = mbd.getBeanClass();
isStatic = true;
}
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass);
Method[] candidates = getCandidateMethods(factoryClass, mbd);
Method uniqueCandidate = null;
for (Method candidate : candidates) {
if (mbd.isFactoryMethod(candidate)) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
if (uniqueCandidate == null) {
uniqueCandidate = candidate;
}
@@ -321,6 +322,27 @@ class ConstructorResolver {
}
}
/**
* Retrieve all candidate methods for the given class, considering
* the {@link RootBeanDefinition#isNonPublicAccessAllowed()} flag.
* Called as the starting point for factory method determination.
*/
private Method[] getCandidateMethods(final Class<?> factoryClass, final RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
@Override
public Method[] run() {
return (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
}
});
}
else {
return (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClass) : factoryClass.getMethods());
}
}
/**
* Instantiate the bean using a named factory method. The method may be static, if the
* bean definition parameter specifies a class, rather than a "factory-bean", or
@@ -336,7 +358,9 @@ class ConstructorResolver {
* method, or {@code null} if none (-> use constructor argument values from bean definition)
* @return a BeanWrapper for the new instance
*/
public BeanWrapper instantiateUsingFactoryMethod(final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
public BeanWrapper instantiateUsingFactoryMethod(
final String beanName, final RootBeanDefinition mbd, final Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
@@ -397,27 +421,11 @@ class ConstructorResolver {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
factoryClass = ClassUtils.getUserClass(factoryClass);
Method[] rawCandidates;
final Class<?> factoryClazz = factoryClass;
if (System.getSecurityManager() != null) {
rawCandidates = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
public Method[] run() {
return (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
}
});
}
else {
rawCandidates = (mbd.isNonPublicAccessAllowed() ?
ReflectionUtils.getAllDeclaredMethods(factoryClazz) : factoryClazz.getMethods());
}
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
List<Method> candidateSet = new ArrayList<Method>();
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic &&
candidate.getName().equals(mbd.getFactoryMethodName()) &&
mbd.isFactoryMethod(candidate)) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateSet.add(candidate);
}
}
@@ -522,24 +530,30 @@ class ConstructorResolver {
}
if (factoryMethodToUse == null) {
boolean hasArgs = (resolvedValues.getArgumentCount() > 0);
String argDesc = "";
if (hasArgs) {
List<String> argTypes = new ArrayList<String>();
for (ValueHolder value : resolvedValues.getIndexedArgumentValues().values()) {
String argType = (value.getType() != null ?
ClassUtils.getShortName(value.getType()) : value.getValue().getClass().getSimpleName());
List<String> argTypes = new ArrayList<String>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else {
Set<ValueHolder> valueHolders = new LinkedHashSet<ValueHolder>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(hasArgs ? "and arguments " : "") +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
@@ -759,7 +773,7 @@ class ConstructorResolver {
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor, Object[] argsToResolve) {
Class<?>[] paramTypes = (methodOrCtor instanceof Method ?
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
((Method) methodOrCtor).getParameterTypes() : ((Constructor<?>) methodOrCtor).getParameterTypes());
TypeConverter converter = (this.beanFactory.getCustomTypeConverter() != null ?
this.beanFactory.getCustomTypeConverter() : bw);
BeanDefinitionValueResolver valueResolver =
@@ -881,7 +895,7 @@ class ConstructorResolver {
*/
private static class ConstructorPropertiesChecker {
public static String[] evaluateAnnotation(Constructor<?> candidate, int paramCount) {
public static String[] evaluate(Constructor<?> candidate, int paramCount) {
ConstructorProperties cp = candidate.getAnnotation(ConstructorProperties.class);
if (cp != null) {
String[] names = cp.value();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,6 +59,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -102,9 +103,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private static Class<?> javaxInjectProviderClass = null;
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
try {
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
javaxInjectProviderClass =
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
@@ -322,7 +323,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
@@ -332,7 +333,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
cache.put(type, resolvedBeanNames);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
@@ -480,7 +483,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* found on the given class itself, as well as checking its raw bean class
* if not found on the exposed bean reference (e.g. in case of a proxy).
*/
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) {
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException{
A ann = null;
Class<?> beanType = getType(beanName);
if (beanType != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -65,11 +65,12 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class);
private static Class closeableInterface;
private static Class<?> closeableInterface;
static {
try {
closeableInterface = DisposableBeanAdapter.class.getClassLoader().loadClass("java.lang.AutoCloseable");
closeableInterface = ClassUtils.forName("java.lang.AutoCloseable",
DisposableBeanAdapter.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
closeableInterface = Closeable.class;
@@ -85,14 +86,14 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private final boolean nonPublicAccessAllowed;
private final AccessControlContext acc;
private String destroyMethodName;
private transient Method destroyMethod;
private List<DestructionAwareBeanPostProcessor> beanPostProcessors;
private final AccessControlContext acc;
/**
* Create a new DisposableBeanAdapter for the given bean.
@@ -149,9 +150,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.beanName = beanName;
this.invokeDisposableBean = invokeDisposableBean;
this.nonPublicAccessAllowed = nonPublicAccessAllowed;
this.acc = null;
this.destroyMethodName = destroyMethodName;
this.beanPostProcessors = postProcessors;
this.acc = null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -87,7 +87,12 @@ public class GenericBeanDefinition extends AbstractBeanDefinition {
@Override
public String toString() {
return "Generic bean: " + super.toString();
StringBuilder sb = new StringBuilder("Generic bean");
if (this.parentName != null) {
sb.append(" with parent '").append(this.parentName).append("'");
}
sb.append(": ").append(super.toString());
return sb.toString();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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,14 +23,15 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Object representing the override of a method on a managed
* object by the IoC container.
* Object representing the override of a method on a managed object by the IoC
* container.
*
* <p>Note that the override mechanism is <i>not</i> intended as a
* generic means of inserting crosscutting code: use AOP for that.
* <p>Note that the override mechanism is <em>not</em> intended as a generic
* means of inserting crosscutting code: use AOP for that.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since 1.1
*/
public abstract class MethodOverride implements BeanMetadataElement {
@@ -59,17 +60,18 @@ public abstract class MethodOverride implements BeanMetadataElement {
}
/**
* Set whether the overridden method has to be considered as overloaded
* (that is, whether arg type matching has to happen).
* <p>Default is "true"; can be switched to "false" to optimize runtime performance.
* Set whether the overridden method is <em>overloaded</em> (i.e., whether argument
* type matching needs to occur to disambiguate methods of the same name).
* <p>Default is {@code true}; can be switched to {@code false} to optimize
* runtime performance.
*/
protected void setOverloaded(boolean overloaded) {
this.overloaded = overloaded;
}
/**
* Return whether the overridden method has to be considered as overloaded
* (that is, whether arg type matching has to happen).
* Return whether the overridden method is <em>overloaded</em> (i.e., whether argument
* type matching needs to occur to disambiguate methods of the same name).
*/
protected boolean isOverloaded() {
return this.overloaded;
@@ -87,17 +89,15 @@ public abstract class MethodOverride implements BeanMetadataElement {
return this.source;
}
/**
* Subclasses must override this to indicate whether they match
* the given method. This allows for argument list checking
* as well as method name checking.
* Subclasses must override this to indicate whether they <em>match</em> the
* given method. This allows for argument list checking as well as method
* name checking.
* @param method the method to check
* @return whether this override matches the given method
*/
public abstract boolean matches(Method method);
@Override
public boolean equals(Object other) {
if (this == other) {
@@ -108,7 +108,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
}
MethodOverride that = (MethodOverride) other;
return (ObjectUtils.nullSafeEquals(this.methodName, that.methodName) &&
this.overloaded == that.overloaded &&
ObjectUtils.nullSafeEquals(this.source, that.source));
}
@@ -116,7 +115,6 @@ public abstract class MethodOverride implements BeanMetadataElement {
public int hashCode() {
int hashCode = ObjectUtils.nullSafeHashCode(this.methodName);
hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.source);
hashCode = 29 * hashCode + (this.overloaded ? 1 : 0);
return hashCode;
}
@@ -18,8 +18,8 @@ package org.springframework.beans.factory.support;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -48,19 +48,10 @@ import org.springframework.util.Assert;
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
// using a ConcurrentHashMap as a Set
private final Map<Member, Boolean> externallyManagedConfigMembers = new ConcurrentHashMap<Member, Boolean>(0);
// using a ConcurrentHashMap as a Set
private final Map<String, Boolean> externallyManagedInitMethods = new ConcurrentHashMap<String, Boolean>(0);
// using a ConcurrentHashMap as a Set
private final Map<String, Boolean> externallyManagedDestroyMethods = new ConcurrentHashMap<String, Boolean>(0);
boolean allowCaching = true;
private BeanDefinitionHolder decoratedDefinition;
boolean allowCaching = true;
private volatile Class<?> targetType;
boolean isFactoryMethodUnique = false;
@@ -87,6 +78,12 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
/** Package-visible field that indicates a before-instantiation post-processor having kicked in */
volatile Boolean beforeInstantiationResolved;
private Set<Member> externallyManagedConfigMembers;
private Set<String> externallyManagedInitMethods;
private Set<String> externallyManagedDestroyMethods;
/**
* Create a new RootBeanDefinition, to be configured through its bean
@@ -225,9 +222,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
* @param original the original bean definition to copy from
*/
public RootBeanDefinition(RootBeanDefinition original) {
super(original);
this.decoratedDefinition = original.decoratedDefinition;
super((BeanDefinition) original);
this.allowCaching = original.allowCaching;
this.decoratedDefinition = original.decoratedDefinition;
this.targetType = original.targetType;
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
}
@@ -252,6 +249,20 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
}
}
/**
* Register a target definition that is being decorated by this bean definition.
*/
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
this.decoratedDefinition = decoratedDefinition;
}
/**
* Return the target definition that is being decorated by this bean definition, if any.
*/
public BeanDefinitionHolder getDecoratedDefinition() {
return this.decoratedDefinition;
}
/**
* Specify the target type of this bean definition, if known in advance.
*/
@@ -294,37 +305,52 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
}
}
public void registerExternallyManagedConfigMember(Member configMember) {
this.externallyManagedConfigMembers.put(configMember, Boolean.TRUE);
synchronized (this.postProcessingLock) {
if (this.externallyManagedConfigMembers == null) {
this.externallyManagedConfigMembers = new HashSet<Member>(1);
}
this.externallyManagedConfigMembers.add(configMember);
}
}
public boolean isExternallyManagedConfigMember(Member configMember) {
return this.externallyManagedConfigMembers.containsKey(configMember);
synchronized (this.postProcessingLock) {
return (this.externallyManagedConfigMembers != null &&
this.externallyManagedConfigMembers.contains(configMember));
}
}
public void registerExternallyManagedInitMethod(String initMethod) {
this.externallyManagedInitMethods.put(initMethod, Boolean.TRUE);
synchronized (this.postProcessingLock) {
if (this.externallyManagedInitMethods == null) {
this.externallyManagedInitMethods = new HashSet<String>(1);
}
this.externallyManagedInitMethods.add(initMethod);
}
}
public boolean isExternallyManagedInitMethod(String initMethod) {
return this.externallyManagedInitMethods.containsKey(initMethod);
synchronized (this.postProcessingLock) {
return (this.externallyManagedInitMethods != null &&
this.externallyManagedInitMethods.contains(initMethod));
}
}
public void registerExternallyManagedDestroyMethod(String destroyMethod) {
this.externallyManagedDestroyMethods.put(destroyMethod, Boolean.TRUE);
synchronized (this.postProcessingLock) {
if (this.externallyManagedDestroyMethods == null) {
this.externallyManagedDestroyMethods = new HashSet<String>(1);
}
this.externallyManagedDestroyMethods.add(destroyMethod);
}
}
public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
return this.externallyManagedDestroyMethods.containsKey(destroyMethod);
}
public void setDecoratedDefinition(BeanDefinitionHolder decoratedDefinition) {
this.decoratedDefinition = decoratedDefinition;
}
public BeanDefinitionHolder getDecoratedDefinition() {
return this.decoratedDefinition;
synchronized (this.postProcessingLock) {
return (this.externallyManagedDestroyMethods != null &&
this.externallyManagedDestroyMethods.contains(destroyMethod));
}
}
@@ -62,14 +62,14 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
synchronized (beanDefinition.constructorArgumentLock) {
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class clazz = beanDefinition.getBeanClass();
final Class<?> clazz = beanDefinition.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor run() throws Exception {
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
@@ -132,7 +132,7 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
* Instantiation should use the given constructor and parameters.
*/
protected Object instantiateWithMethodInjection(RootBeanDefinition beanDefinition,
String beanName, BeanFactory owner, Constructor ctor, Object[] args) {
String beanName, BeanFactory owner, Constructor<?> ctor, Object[] args) {
throw new UnsupportedOperationException(
"Method Injection not supported in SimpleInstantiationStrategy");
@@ -189,9 +189,13 @@ public final class BeanUtilsTests {
public void testCopyPropertiesWithInvalidProperty() {
InvalidProperty source = new InvalidProperty();
source.setName("name");
source.setFlag1(true);
source.setFlag2(true);
InvalidProperty target = new InvalidProperty();
BeanUtils.copyProperties(source, target);
assertEquals(target.getName(), "name");
assertTrue(target.getFlag1());
assertTrue(target.getFlag2());
}
@Test
@@ -308,6 +312,10 @@ public final class BeanUtilsTests {
private String value;
private boolean flag1;
private boolean flag2;
public void setName(String name) {
this.name = name;
}
@@ -323,6 +331,22 @@ public final class BeanUtilsTests {
public String getValue() {
return this.value;
}
public void setFlag1(boolean flag1) {
this.flag1 = flag1;
}
public Boolean getFlag1() {
return this.flag1;
}
public void setFlag2(Boolean flag2) {
this.flag2 = flag2;
}
public boolean getFlag2() {
return this.flag2;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,13 +16,6 @@
package org.springframework.beans;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.beans.PropertyEditorSupport;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -44,11 +37,16 @@ import java.util.TreeSet;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.beans.propertyeditors.StringArrayPropertyEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.beans.support.DerivedFromProtectedBaseBean;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import org.springframework.tests.sample.beans.BooleanTestBean;
@@ -56,18 +54,12 @@ import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.IndexedTestBean;
import org.springframework.tests.sample.beans.NumberTestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* @author Rod Johnson
* @author Juergen Hoeller
@@ -1557,28 +1549,55 @@ public final class BeanWrapperTests {
@Test
public void cornerSpr10115() {
Spr10115Bean foo = new Spr10115Bean();
BeanWrapperImpl bwi = new BeanWrapperImpl();
bwi.setWrappedInstance(foo);
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
bwi.setPropertyValue("prop1", "val1");
assertEquals("val1", Spr10115Bean.prop1);
}
@Test
public void testArrayToObject() throws Exception {
public void testArrayToObject() {
ArrayToObject foo = new ArrayToObject();
BeanWrapperImpl bwi = new BeanWrapperImpl();
bwi.setWrappedInstance(foo);
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
Object[] array = new Object[] {"1","2"};
bwi.setPropertyValue("object", array );
bwi.setPropertyValue("object", array);
assertThat(foo.getObject(), equalTo((Object) array));
array = new Object[] {"1"};
bwi.setPropertyValue("object", array );
bwi.setPropertyValue("object", array);
assertThat(foo.getObject(), equalTo((Object) array));
}
}
@Test
public void testPropertyTypeMismatch() {
PropertyTypeMismatch foo = new PropertyTypeMismatch();
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
bwi.setPropertyValue("object", "a String");
assertEquals("a String", foo.value);
assertEquals(8, bwi.getPropertyValue("object"));
}
@Test
public void testGenericArraySetter() {
SkipReaderStub foo = new SkipReaderStub();
BeanWrapperImpl bwi = new BeanWrapperImpl(foo);
List<String> values = new LinkedList<String>();
values.add("1");
values.add("2");
values.add("3");
values.add("4");
bwi.setPropertyValue("items", values);
Object[] result = foo.items;
assertEquals(4, result.length);
assertEquals("1", result[0]);
assertEquals("2", result[1]);
assertEquals("3", result[2]);
assertEquals("4", result[3]);
}
static class Spr10115Bean {
private static String prop1;
public static void setProp1(String prop1) {
@@ -1963,11 +1982,10 @@ public final class BeanWrapperTests {
}
static class ArrayToObject {
public static class ArrayToObject {
private Object object;
public void setObject(Object object) {
this.object = object;
}
@@ -1975,6 +1993,37 @@ public final class BeanWrapperTests {
public Object getObject() {
return object;
}
}
public static class PropertyTypeMismatch {
public String value;
public void setObject(String object) {
this.value = object;
}
public Integer getObject() {
return (this.value != null ? this.value.length() : null);
}
}
public static class SkipReaderStub<T> {
public T[] items;
public SkipReaderStub() {
}
public SkipReaderStub(T... items) {
this.items = items;
}
public void setItems(T... items) {
this.items = items;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,63 +16,95 @@
package org.springframework.beans.factory.support;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* Unit tests for {@code equals()} and {@code hashCode()} in bean definitions.
*
* @author Rob Harrop
* @author Sam Brannen
*/
public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
@SuppressWarnings("serial")
public class DefinitionMetadataEqualsHashCodeTests {
@SuppressWarnings("serial")
public void testRootBeanDefinitionEqualsAndHashCode() throws Exception {
@Test
public void rootBeanDefinition() {
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
RootBeanDefinition notEqual = new RootBeanDefinition(String.class);
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {};
RootBeanDefinition subclass = new RootBeanDefinition(TestBean.class) {
};
setBaseProperties(master);
setBaseProperties(equal);
setBaseProperties(notEqual);
setBaseProperties(subclass);
assertEqualsContract(master, equal, notEqual, subclass);
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
}
@SuppressWarnings("serial")
public void testChildBeanDefinitionEqualsAndHashCode() throws Exception {
/**
* @since 3.2.8
* @see <a href="https://jira.springsource.org/browse/SPR-11420">SPR-11420</a>
*/
@Test
public void rootBeanDefinitionAndMethodOverridesWithDifferentOverloadedValues() {
RootBeanDefinition master = new RootBeanDefinition(TestBean.class);
RootBeanDefinition equal = new RootBeanDefinition(TestBean.class);
setBaseProperties(master);
setBaseProperties(equal);
// Simulate AbstractBeanDefinition.validate() which delegates to
// AbstractBeanDefinition.prepareMethodOverrides():
master.getMethodOverrides().getOverrides().iterator().next().setOverloaded(false);
// But do not simulate validation of the 'equal' bean. As a consequence, a method
// override in 'equal' will be marked as overloaded, but the corresponding
// override in 'master' will not. But... the bean definitions should still be
// considered equal.
assertEquals("Should be equal", master, equal);
assertEquals("Hash code for equal instances must match", master.hashCode(), equal.hashCode());
}
@Test
public void childBeanDefinition() {
ChildBeanDefinition master = new ChildBeanDefinition("foo");
ChildBeanDefinition equal = new ChildBeanDefinition("foo");
ChildBeanDefinition notEqual = new ChildBeanDefinition("bar");
ChildBeanDefinition subclass = new ChildBeanDefinition("foo"){};
ChildBeanDefinition subclass = new ChildBeanDefinition("foo") {
};
setBaseProperties(master);
setBaseProperties(equal);
setBaseProperties(notEqual);
setBaseProperties(subclass);
assertEqualsContract(master, equal, notEqual, subclass);
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
}
public void testRuntimeBeanReference() throws Exception {
@Test
public void runtimeBeanReference() {
RuntimeBeanReference master = new RuntimeBeanReference("name");
RuntimeBeanReference equal = new RuntimeBeanReference("name");
RuntimeBeanReference notEqual = new RuntimeBeanReference("someOtherName");
RuntimeBeanReference subclass = new RuntimeBeanReference("name"){};
assertEqualsContract(master, equal, notEqual, subclass);
RuntimeBeanReference subclass = new RuntimeBeanReference("name") {
};
assertEqualsAndHashCodeContracts(master, equal, notEqual, subclass);
}
private void setBaseProperties(AbstractBeanDefinition definition) {
definition.setAbstract(true);
definition.setAttribute("foo", "bar");
definition.setAutowireCandidate(false);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
//definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
// definition.getConstructorArgumentValues().addGenericArgumentValue("foo");
definition.setDependencyCheck(AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
definition.setDependsOn(new String[]{"foo", "bar"});
definition.setDependsOn(new String[] { "foo", "bar" });
definition.setDestroyMethodName("destroy");
definition.setEnforceDestroyMethod(false);
definition.setEnforceInitMethod(true);
@@ -89,10 +121,15 @@ public class DefinitionMetadataEqualsHashCodeTests extends TestCase {
definition.setSource("foo");
}
private void assertEqualsContract(Object master, Object equal, Object notEqual, Object subclass) {
private void assertEqualsAndHashCodeContracts(Object master, Object equal, Object notEqual, Object subclass) {
assertEquals("Should be equal", master, equal);
assertFalse("Should not be equal", master.equals(notEqual));
assertEquals("Hash code for equal instances should match", master.hashCode(), equal.hashCode());
assertNotEquals("Should not be equal", master, notEqual);
assertNotEquals("Hash code for non-equal instances should not match", master.hashCode(), notEqual.hashCode());
assertEquals("Subclass should be equal", master, subclass);
assertEquals("Hash code for subclass should match", master.hashCode(), subclass.hashCode());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -21,7 +21,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
@@ -30,6 +29,8 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
* @author Chris Beams
@@ -259,6 +260,34 @@ public class FactoryMethodTests {
}
}
@Test
public void testNonExistingFactoryMethod() {
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass()));
try {
xbf.getBean("invalidPrototype");
fail("Should have thrown BeanCreationException");
}
catch (BeanCreationException ex) {
assertTrue(ex.getMessage().contains("nonExisting(TestBean)"));
}
}
@Test
public void testFactoryMethodArgumentsForNonExistingMethod() {
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf);
reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass()));
try {
xbf.getBean("invalidPrototype", new TestBean());
fail("Should have thrown BeanCreationException");
}
catch (BeanCreationException ex) {
assertTrue(ex.getMessage().contains("nonExisting(TestBean)"));
}
}
@Test
public void testCanSpecifyFactoryMethodArgumentsOnFactoryMethodPrototype() {
DefaultListableBeanFactory xbf = new DefaultListableBeanFactory();
@@ -360,7 +389,9 @@ public class FactoryMethodTests {
}
class MailSession {
private Properties props;
private MailSession() {
@@ -377,6 +408,6 @@ class MailSession {
}
public Object getProperty(String key) {
return props.get(key);
return this.props.get(key);
}
}
@@ -84,6 +84,11 @@
<property name="stringValue"><value>testBeanOnlyPrototypeDISetterString</value></property>
</bean>
<bean id="invalidPrototype" class="org.springframework.beans.factory.xml.FactoryMethods"
factory-method="nonExisting" scope="prototype">
<constructor-arg><ref local="juergen"/></constructor-arg>
</bean>
<bean id="fullPrototype" class="org.springframework.beans.factory.xml.FactoryMethods"
factory-method="newInstance" scope="prototype">
<constructor-arg type="int"><value>27</value></constructor-arg>
@@ -120,9 +125,7 @@
<constructor-arg><value type="java.lang.Integer">33</value></constructor-arg>
</bean>
<bean id="instanceFactoryMethodWithoutArgs"
factory-bean="instanceFactory"
factory-method="defaultInstance"/>
<bean id="instanceFactoryMethodWithoutArgs" factory-bean="instanceFactory" factory-method="defaultInstance"/>
<!-- Unnamed bean with factory-bean declaration -->
<bean factory-bean="instanceFactory" factory-method="defaultInstance"/>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
}
/**
* Create a new EhCacheCacheManager for the given backing EhCache.
* Create a new EhCacheCacheManager for the given backing EhCache CacheManager.
* @param cacheManager the backing EhCache {@link net.sf.ehcache.CacheManager}
*/
public EhCacheCacheManager(net.sf.ehcache.CacheManager cacheManager) {
@@ -92,8 +92,8 @@ public class EhCacheCacheManager extends AbstractTransactionSupportingCacheManag
// (in case the cache was added at runtime)
Ehcache ehcache = this.cacheManager.getEhcache(name);
if (ehcache != null) {
cache = new EhCacheCache(ehcache);
addCache(cache);
addCache(new EhCacheCache(ehcache));
cache = super.getCache(name); // potentially decorated
}
}
return cache;
@@ -38,6 +38,7 @@ import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* {@link FactoryBean} that creates a named EhCache {@link net.sf.ehcache.Cache} instance
@@ -64,6 +65,11 @@ import org.springframework.util.Assert;
*/
public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware, InitializingBean {
// EhCache's setStatisticsEnabled(boolean) available? Not anymore as of EhCache 2.7...
private static final boolean setStatisticsAvailable =
ClassUtils.hasMethod(Ehcache.class, "setStatisticsEnabled", boolean.class);
protected final Log logger = LogFactory.getLog(getClass());
private CacheManager cacheManager;
@@ -275,7 +281,9 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
/**
* Set whether to enable EhCache statistics on this cache.
* @see net.sf.ehcache.Cache#setStatisticsEnabled
* <p>Note: As of EhCache 2.7, statistics are enabled by default, and cannot be turned off.
* This setter therefore has no effect in such a scenario.
* @see net.sf.ehcache.Ehcache#setStatisticsEnabled
*/
public void setStatisticsEnabled(boolean statisticsEnabled) {
this.statisticsEnabled = statisticsEnabled;
@@ -283,7 +291,9 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
/**
* Set whether to enable EhCache's sampled statistics on this cache.
* @see net.sf.ehcache.Cache#setSampledStatisticsEnabled
* <p>Note: As of EhCache 2.7, statistics are enabled by default, and cannot be turned off.
* This setter therefore has no effect in such a scenario.
* @see net.sf.ehcache.Ehcache#setSampledStatisticsEnabled
*/
public void setSampledStatisticsEnabled(boolean sampledStatisticsEnabled) {
this.sampledStatisticsEnabled = sampledStatisticsEnabled;
@@ -346,11 +356,14 @@ public class EhCacheFactoryBean implements FactoryBean<Ehcache>, BeanNameAware,
this.cacheManager.addCache(rawCache);
}
if (this.statisticsEnabled) {
rawCache.setStatisticsEnabled(true);
}
if (this.sampledStatisticsEnabled) {
rawCache.setSampledStatisticsEnabled(true);
// Only necessary on EhCache <2.7: As of 2.7, statistics are on by default.
if (setStatisticsAvailable) {
if (this.statisticsEnabled) {
rawCache.setStatisticsEnabled(true);
}
if (this.sampledStatisticsEnabled) {
rawCache.setSampledStatisticsEnabled(true);
}
}
if (this.disabled) {
rawCache.setDisabled(true);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -110,8 +110,8 @@ public class JCacheCacheManager extends AbstractTransactionSupportingCacheManage
// (in case the cache was added at runtime)
javax.cache.Cache<?,?> jcache = this.cacheManager.getCache(name);
if (jcache != null) {
cache = new JCacheCache(jcache, this.allowNullValues);
addCache(cache);
addCache(new JCacheCache(jcache, this.allowNullValues));
cache = super.getCache(name); // potentially decorated
}
}
return cache;
@@ -73,7 +73,7 @@ public class CronTriggerBean extends CronTrigger
private String beanName;
private long startDelay;
private long startDelay = 0;
/**
@@ -108,9 +108,9 @@ public class CronTriggerBean extends CronTrigger
* @see SchedulerFactoryBean#setTriggerListeners
* @see org.quartz.TriggerListener#getName
*/
public void setTriggerListenerNames(String[] names) {
for (int i = 0; i < names.length; i++) {
addTriggerListener(names[i]);
public void setTriggerListenerNames(String... names) {
for (String name : names) {
addTriggerListener(name);
}
}
@@ -148,19 +148,19 @@ public class CronTriggerBean extends CronTrigger
}
/**
* Note that this method's declaration of an Exception is deprecated
* and will be removed in the Spring 4.0 line.
*/
public void afterPropertiesSet() throws Exception {
if (this.startDelay > 0) {
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
}
if (getName() == null) {
setName(this.beanName);
}
if (getGroup() == null) {
setGroup(Scheduler.DEFAULT_GROUP);
}
if (getStartTime() == null) {
setStartTime(new Date());
if (this.startDelay > 0 || getStartTime() == null) {
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
}
if (getTimeZone() == null) {
setTimeZone(TimeZone.getDefault());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +34,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -78,16 +79,20 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
private Date startTime;
private long startDelay;
private long startDelay = 0;
private String cronExpression;
private TimeZone timeZone;
private String calendarName;
private int priority;
private int misfireInstruction;
private String description;
private String beanName;
private CronTrigger cronTrigger;
@@ -141,6 +146,15 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
this.jobDataMap.putAll(jobDataAsMap);
}
/**
* Set a specific start time for the trigger.
* <p>Note that a dynamically computed {@link #setStartDelay} specification
* overrides a static timestamp set here.
*/
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
/**
* Set the start delay in milliseconds.
* <p>The start delay is added to the current system time (when the bean starts)
@@ -165,6 +179,13 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
this.timeZone = timeZone;
}
/**
* Associate a specific calendar with this cron trigger.
*/
public void setCalendarName(String calendarName) {
this.calendarName = calendarName;
}
/**
* Specify the priority of this trigger.
*/
@@ -191,6 +212,13 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
this.misfireInstruction = constants.asNumber(constantName).intValue();
}
/**
* Associate a textual description with this trigger.
*/
public void setDescription(String description) {
this.description = description;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@@ -206,12 +234,9 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
if (this.jobDetail != null) {
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
}
if (this.startDelay > 0) {
if (this.startDelay > 0 || this.startTime == null) {
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
}
else if (this.startTime == null) {
this.startTime = new Date();
}
if (this.timeZone == null) {
this.timeZone = TimeZone.getDefault();
}
@@ -225,15 +250,17 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
cti.setStartTime(this.startTime);
cti.setCronExpression(this.cronExpression);
cti.setTimeZone(this.timeZone);
cti.setCalendarName(this.calendarName);
cti.setPriority(this.priority);
cti.setMisfireInstruction(this.misfireInstruction);
cti.setDescription(this.description);
this.cronTrigger = cti;
*/
Class cronTriggerClass;
Class<?> cronTriggerClass;
Method jobKeyMethod;
try {
cronTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.CronTriggerImpl");
cronTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.CronTriggerImpl", getClass().getClassLoader());
jobKeyMethod = JobDetail.class.getMethod("getKey");
}
catch (ClassNotFoundException ex) {
@@ -258,8 +285,10 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
pvs.add("startTime", this.startTime);
pvs.add("cronExpression", this.cronExpression);
pvs.add("timeZone", this.timeZone);
pvs.add("calendarName", this.calendarName);
pvs.add("priority", this.priority);
pvs.add("misfireInstruction", this.misfireInstruction);
pvs.add("description", this.description);
bw.setPropertyValues(pvs);
this.cronTrigger = (CronTrigger) bw.getWrappedInstance();
}
@@ -48,11 +48,11 @@ import org.springframework.context.ApplicationContextAware;
* @see org.springframework.beans.factory.BeanNameAware
* @see org.quartz.Scheduler#DEFAULT_GROUP
*/
@SuppressWarnings("serial")
@SuppressWarnings({"serial", "rawtypes"})
public class JobDetailBean extends JobDetail
implements BeanNameAware, ApplicationContextAware, InitializingBean {
private Class actualJobClass;
private Class<?> actualJobClass;
private String beanName;
@@ -97,7 +97,7 @@ public class JobDetailBean extends JobDetail
* (for example Spring-managed beans)
* @see SchedulerFactoryBean#setSchedulerContextAsMap
*/
public void setJobDataAsMap(Map jobDataAsMap) {
public void setJobDataAsMap(Map<String, ?> jobDataAsMap) {
getJobDataMap().putAll(jobDataAsMap);
}
@@ -109,9 +109,9 @@ public class JobDetailBean extends JobDetail
* @see SchedulerFactoryBean#setJobListeners
* @see org.quartz.JobListener#getName
*/
public void setJobListenerNames(String[] names) {
for (int i = 0; i < names.length; i++) {
addJobListener(names[i]);
public void setJobListenerNames(String... names) {
for (String name : names) {
addJobListener(name);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +30,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;
/**
* A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.JobDetail}
@@ -56,7 +57,7 @@ public class JobDetailFactoryBean
private String group;
private Class jobClass;
private Class<?> jobClass;
private JobDataMap jobDataMap = new JobDataMap();
@@ -92,7 +93,7 @@ public class JobDetailFactoryBean
/**
* Specify the job's implementation class.
*/
public void setJobClass(Class jobClass) {
public void setJobClass(Class<?> jobClass) {
this.jobClass = jobClass;
}
@@ -207,7 +208,7 @@ public class JobDetailFactoryBean
Class<?> jobDetailClass;
try {
jobDetailClass = getClass().getClassLoader().loadClass("org.quartz.impl.JobDetailImpl");
jobDetailClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl", getClass().getClassLoader());
}
catch (ClassNotFoundException ex) {
jobDetailClass = JobDetail.class;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package org.springframework.scheduling.quartz;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.quartz.SchedulerConfigException;
@@ -108,14 +107,17 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
public void shutdown() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
/* Quartz 2.2 initialize method */
public void initialize() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
}
);
// Non-transactional DataSource is optional: fall back to default
// DataSource if not explicitly specified.
DataSource nonTxDataSource = SchedulerFactoryBean.getConfigTimeNonTransactionalDataSource();
final DataSource nonTxDataSourceToUse =
(nonTxDataSource != null ? nonTxDataSource : this.dataSource);
final DataSource nonTxDataSourceToUse = (nonTxDataSource != null ? nonTxDataSource : this.dataSource);
// Configure non-transactional connection settings for Quartz.
setNonManagedTXDataSource(NON_TX_DATA_SOURCE_PREFIX + getInstanceName());
@@ -131,21 +133,24 @@ public class LocalDataSourceJobStore extends JobStoreCMT {
public void shutdown() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
/* Quartz 2.2 initialize method */
public void initialize() {
// Do nothing - a Spring-managed DataSource has its own lifecycle.
}
}
);
// No, if HSQL is the platform, we really don't want to use locks
// No, if HSQL is the platform, we really don't want to use locks...
try {
String productName = JdbcUtils.extractDatabaseMetaData(dataSource,
"getDatabaseProductName").toString();
String productName = JdbcUtils.extractDatabaseMetaData(this.dataSource, "getDatabaseProductName").toString();
productName = JdbcUtils.commonDatabaseName(productName);
if (productName != null
&& productName.toLowerCase().contains("hsql")) {
if (productName != null && productName.toLowerCase().contains("hsql")) {
setUseDBLocks(false);
setLockHandler(new SimpleSemaphore());
}
} catch (MetaDataAccessException e) {
logWarnIfNonZero(1, "Could not detect database type. Assuming locks can be taken.");
}
catch (MetaDataAccessException ex) {
logWarnIfNonZero(1, "Could not detect database type. Assuming locks can be taken.");
}
super.initialize(loadHelper, signaler);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
@@ -80,7 +80,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
}
public int blockForAvailableThreads() {
// The present implementation always returns 1, making Quartz (1.6)
// The present implementation always returns 1, making Quartz
// always schedule any tasks that it feels like scheduling.
// This could be made smarter for specific TaskExecutors,
// for example calling {@code getMaximumPoolSize() - getActiveCount()}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -86,14 +86,15 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
static {
try {
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
jobDetailImplClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl",
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
jobDetailImplClass = null;
}
try {
Class jobExecutionContextClass =
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
Class<?> jobExecutionContextClass = ClassUtils.forName("org.quartz.JobExecutionContext",
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
}
catch (Exception ex) {
@@ -172,7 +173,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
* @see SchedulerFactoryBean#setJobListeners
* @see org.quartz.JobListener#getName
*/
public void setJobListenerNames(String[] names) {
public void setJobListenerNames(String... names) {
this.jobListenerNames = names;
}
@@ -189,7 +190,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
}
@Override
protected Class resolveClassName(String className) throws ClassNotFoundException {
protected Class<?> resolveClassName(String className) throws ClassNotFoundException {
return ClassUtils.forName(className, this.beanClassLoader);
}
@@ -201,7 +202,7 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
String name = (this.name != null ? this.name : this.beanName);
// Consider the concurrent flag to choose between stateful and stateless job.
Class jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
Class<?> jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
// Build JobDetail instance.
if (jobDetailImplClass != null) {
@@ -249,8 +250,8 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
* Overridden to support the {@link #setTargetBeanName "targetBeanName"} feature.
*/
@Override
public Class getTargetClass() {
Class targetClass = super.getTargetClass();
public Class<?> getTargetClass() {
Class<?> targetClass = super.getTargetClass();
if (targetClass == null && this.targetBeanName != null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
targetClass = this.beanFactory.getType(this.targetBeanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.quartz.SchedulerException;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -79,8 +80,8 @@ public abstract class QuartzJobBean implements Job {
static {
try {
Class jobExecutionContextClass =
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
Class<?> jobExecutionContextClass =
ClassUtils.forName("org.quartz.JobExecutionContext", QuartzJobBean.class.getClassLoader());
getSchedulerMethod = jobExecutionContextClass.getMethod("getScheduler");
getMergedJobDataMapMethod = jobExecutionContextClass.getMethod("getMergedJobDataMap");
}
@@ -99,7 +100,7 @@ public abstract class QuartzJobBean implements Job {
try {
// Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
Scheduler scheduler = (Scheduler) ReflectionUtils.invokeMethod(getSchedulerMethod, context);
Map mergedJobDataMap = (Map) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);
Map<?, ?> mergedJobDataMap = (Map<?, ?>) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
MutablePropertyValues pvs = new MutablePropertyValues();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +42,7 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -54,6 +55,7 @@ import org.springframework.util.ReflectionUtils;
* <p>Compatible with Quartz 1.5+ as well as Quartz 2.0-2.2, as of Spring 3.2.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 2.5.6
*/
public abstract class SchedulerAccessor implements ResourceLoaderAware {
@@ -63,9 +65,10 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
private static Class<?> triggerKeyClass;
static {
// Quartz 2.0 job/trigger key available?
try {
jobKeyClass = Class.forName("org.quartz.JobKey");
triggerKeyClass = Class.forName("org.quartz.TriggerKey");
jobKeyClass = ClassUtils.forName("org.quartz.JobKey", SchedulerAccessor.class.getClassLoader());
triggerKeyClass = ClassUtils.forName("org.quartz.TriggerKey", SchedulerAccessor.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
jobKeyClass = null;
@@ -128,7 +131,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* to jobs defined directly on this SchedulerFactoryBean.
* @see org.quartz.xml.XmlSchedulingDataProcessor
*/
public void setJobSchedulingDataLocations(String[] jobSchedulingDataLocations) {
public void setJobSchedulingDataLocations(String... jobSchedulingDataLocations) {
this.jobSchedulingDataLocations = jobSchedulingDataLocations;
}
@@ -140,11 +143,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* in combination with the Trigger.
* @see #setTriggers
* @see org.quartz.JobDetail
* @see JobDetailBean
* @see JobDetailAwareTrigger
* @see org.quartz.Trigger#setJobName
*/
public void setJobDetails(JobDetail[] jobDetails) {
public void setJobDetails(JobDetail... jobDetails) {
// Use modifiable ArrayList here, to allow for further adding of
// JobDetail objects during autodetection of JobDetailAwareTriggers.
this.jobDetails = new ArrayList<JobDetail>(Arrays.asList(jobDetails));
@@ -156,7 +156,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* @param calendars Map with calendar names as keys as Calendar
* objects as values
* @see org.quartz.Calendar
* @see org.quartz.Trigger#setCalendarName
*/
public void setCalendars(Map<String, Calendar> calendars) {
this.calendars = calendars;
@@ -171,19 +170,15 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* "jobDetails" property of this FactoryBean.
* @see #setJobDetails
* @see org.quartz.JobDetail
* @see JobDetailAwareTrigger
* @see CronTriggerBean
* @see SimpleTriggerBean
*/
public void setTriggers(Trigger[] triggers) {
public void setTriggers(Trigger... triggers) {
this.triggers = Arrays.asList(triggers);
}
/**
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
*/
public void setSchedulerListeners(SchedulerListener[] schedulerListeners) {
public void setSchedulerListeners(SchedulerListener... schedulerListeners) {
this.schedulerListeners = schedulerListeners;
}
@@ -191,7 +186,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* Specify global Quartz JobListeners to be registered with the Scheduler.
* Such JobListeners will apply to all Jobs in the Scheduler.
*/
public void setGlobalJobListeners(JobListener[] globalJobListeners) {
public void setGlobalJobListeners(JobListener... globalJobListeners) {
this.globalJobListeners = globalJobListeners;
}
@@ -199,11 +194,12 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* Specify named Quartz JobListeners to be registered with the Scheduler.
* Such JobListeners will only apply to Jobs that explicitly activate
* them via their name.
* <p>Note that non-global JobListeners are not supported on Quartz 2.x -
* manually register a Matcher against the Quartz ListenerManager instead.
* @see org.quartz.JobListener#getName
* @see org.quartz.JobDetail#addJobListener
* @see JobDetailBean#setJobListenerNames
*/
public void setJobListeners(JobListener[] jobListeners) {
public void setJobListeners(JobListener... jobListeners) {
this.jobListeners = jobListeners;
}
@@ -211,7 +207,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* Specify global Quartz TriggerListeners to be registered with the Scheduler.
* Such TriggerListeners will apply to all Triggers in the Scheduler.
*/
public void setGlobalTriggerListeners(TriggerListener[] globalTriggerListeners) {
public void setGlobalTriggerListeners(TriggerListener... globalTriggerListeners) {
this.globalTriggerListeners = globalTriggerListeners;
}
@@ -219,12 +215,13 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* Specify named Quartz TriggerListeners to be registered with the Scheduler.
* Such TriggerListeners will only apply to Triggers that explicitly activate
* them via their name.
* <p>Note that non-global TriggerListeners are not supported on Quartz 2.x -
* manually register a Matcher against the Quartz ListenerManager instead.
* @see org.quartz.TriggerListener#getName
* @see org.quartz.Trigger#addTriggerListener
* @see CronTriggerBean#setTriggerListenerNames
* @see SimpleTriggerBean#setTriggerListenerNames
*/
public void setTriggerListeners(TriggerListener[] triggerListeners) {
public void setTriggerListeners(TriggerListener... triggerListeners) {
this.triggerListeners = triggerListeners;
}
@@ -251,14 +248,14 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
if (this.transactionManager != null) {
transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
}
try {
try {
if (this.jobSchedulingDataLocations != null) {
ClassLoadHelper clh = new ResourceLoaderClassLoadHelper(this.resourceLoader);
clh.initialize();
try {
// Quartz 1.8 or higher?
Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.XMLSchedulingDataProcessor");
Class<?> dataProcessorClass = ClassUtils.forName("org.quartz.xml.XMLSchedulingDataProcessor", getClass().getClassLoader());
logger.debug("Using Quartz 1.8 XMLSchedulingDataProcessor");
Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class).newInstance(clh);
Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class);
@@ -268,7 +265,7 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
}
catch (ClassNotFoundException ex) {
// Quartz 1.6
Class dataProcessorClass = getClass().getClassLoader().loadClass("org.quartz.xml.JobSchedulingDataProcessor");
Class<?> dataProcessorClass = ClassUtils.forName("org.quartz.xml.JobSchedulingDataProcessor", getClass().getClassLoader());
logger.debug("Using Quartz 1.6 JobSchedulingDataProcessor");
Object dataProcessor = dataProcessorClass.getConstructor(ClassLoadHelper.class, boolean.class, boolean.class).newInstance(clh, true, true);
Method processFileAndScheduleJobs = dataProcessorClass.getMethod("processFileAndScheduleJobs", String.class, Scheduler.class, boolean.class);
@@ -396,7 +393,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
}
else {
try {
Map jobDataMap = (Map) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
Map<?, ?> jobDataMap =
(Map<?, ?>) ReflectionUtils.invokeMethod(Trigger.class.getMethod("getJobDataMap"), trigger);
return (JobDetail) jobDataMap.remove(JobDetailAwareTrigger.JOB_DETAIL_KEY);
}
catch (NoSuchMethodException ex) {
@@ -473,19 +471,33 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
target = getScheduler();
quartz2 = false;
}
Class<?> targetClass = target.getClass();
try {
if (this.schedulerListeners != null) {
Method addSchedulerListener = target.getClass().getMethod("addSchedulerListener", SchedulerListener.class);
Method addSchedulerListener = targetClass.getMethod("addSchedulerListener", SchedulerListener.class);
for (SchedulerListener listener : this.schedulerListeners) {
ReflectionUtils.invokeMethod(addSchedulerListener, target, listener);
}
}
if (this.globalJobListeners != null) {
Method addJobListener = target.getClass().getMethod(
(quartz2 ? "addJobListener" : "addGlobalJobListener"), JobListener.class);
Method addJobListener;
if (quartz2) {
// addJobListener(JobListener) only introduced as late as Quartz 2.2, so we need
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
addJobListener = targetClass.getMethod("addJobListener", JobListener.class, List.class);
}
else {
addJobListener = targetClass.getMethod("addGlobalJobListener", JobListener.class);
}
for (JobListener listener : this.globalJobListeners) {
ReflectionUtils.invokeMethod(addJobListener, target, listener);
if (quartz2) {
List<?> emptyMatchers = new LinkedList<Object>();
ReflectionUtils.invokeMethod(addJobListener, target, listener, emptyMatchers);
}
else {
ReflectionUtils.invokeMethod(addJobListener, target, listener);
}
}
}
if (this.jobListeners != null) {
@@ -498,10 +510,23 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
}
}
if (this.globalTriggerListeners != null) {
Method addTriggerListener = target.getClass().getMethod(
(quartz2 ? "addTriggerListener" : "addGlobalTriggerListener"), TriggerListener.class);
Method addTriggerListener;
if (quartz2) {
// addTriggerListener(TriggerListener) only introduced as late as Quartz 2.2, so we need
// to fall back to the Quartz 2.0/2.1 compatible variant with an empty matchers List
addTriggerListener = targetClass.getMethod("addTriggerListener", TriggerListener.class, List.class);
}
else {
addTriggerListener = targetClass.getMethod("addGlobalTriggerListener", TriggerListener.class);
}
for (TriggerListener listener : this.globalTriggerListeners) {
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
if (quartz2) {
List<?> emptyMatchers = new LinkedList<Object>();
ReflectionUtils.invokeMethod(addTriggerListener, target, listener, emptyMatchers);
}
else {
ReflectionUtils.invokeMethod(addTriggerListener, target, listener);
}
}
}
if (this.triggerListeners != null) {
@@ -43,6 +43,7 @@ import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.scheduling.SchedulingException;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
@@ -157,7 +158,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
private Class<?> schedulerFactoryClass = StdSchedulerFactory.class;
private Class<? extends SchedulerFactory> schedulerFactoryClass = StdSchedulerFactory.class;
private String schedulerName;
@@ -173,7 +174,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
private DataSource nonTransactionalDataSource;
private Map schedulerContextMap;
private Map<String, ?> schedulerContextMap;
private ApplicationContext applicationContext;
@@ -200,7 +201,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
/**
* Set the Quartz SchedulerFactory implementation to use.
* <p>Default is StdSchedulerFactory, reading in the standard
* <p>Default is {@link StdSchedulerFactory}, reading in the standard
* {@code quartz.properties} from {@code quartz.jar}.
* To use custom Quartz properties, specify the "configLocation"
* or "quartzProperties" bean property on this FactoryBean.
@@ -208,10 +209,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
* @see #setConfigLocation
* @see #setQuartzProperties
*/
public void setSchedulerFactoryClass(Class schedulerFactoryClass) {
if (schedulerFactoryClass == null || !SchedulerFactory.class.isAssignableFrom(schedulerFactoryClass)) {
throw new IllegalArgumentException("schedulerFactoryClass must implement [org.quartz.SchedulerFactory]");
}
public void setSchedulerFactoryClass(Class<? extends SchedulerFactory> schedulerFactoryClass) {
Assert.isAssignable(SchedulerFactory.class, schedulerFactoryClass);
this.schedulerFactoryClass = schedulerFactoryClass;
}
@@ -313,7 +312,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
* values (for example Spring-managed beans)
* @see JobDetailBean#setJobDataAsMap
*/
public void setSchedulerContextAsMap(Map schedulerContextAsMap) {
public void setSchedulerContextAsMap(Map<String, ?> schedulerContextAsMap) {
this.schedulerContextMap = schedulerContextAsMap;
}
@@ -450,10 +449,8 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
this.resourceLoader = this.applicationContext;
}
// Create SchedulerFactory instance.
SchedulerFactory schedulerFactory = (SchedulerFactory)
BeanUtils.instantiateClass(this.schedulerFactoryClass);
// Create SchedulerFactory instance...
SchedulerFactory schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
initSchedulerFactory(schedulerFactory);
if (this.resourceLoader != null) {
@@ -516,9 +513,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
* Load and/or apply Quartz properties to the given SchedulerFactory.
* @param schedulerFactory the SchedulerFactory to initialize
*/
private void initSchedulerFactory(SchedulerFactory schedulerFactory)
throws SchedulerException, IOException {
private void initSchedulerFactory(SchedulerFactory schedulerFactory) throws SchedulerException, IOException {
if (!(schedulerFactory instanceof StdSchedulerFactory)) {
if (this.configLocation != null || this.quartzProperties != null ||
this.taskExecutor != null || this.dataSource != null) {
@@ -114,9 +114,9 @@ public class SimpleTriggerBean extends SimpleTrigger
* @see SchedulerFactoryBean#setTriggerListeners
* @see org.quartz.TriggerListener#getName
*/
public void setTriggerListenerNames(String[] names) {
for (int i = 0; i < names.length; i++) {
addTriggerListener(names[i]);
public void setTriggerListenerNames(String... names) {
for (String name : names) {
addTriggerListener(name);
}
}
@@ -153,6 +153,10 @@ public class SimpleTriggerBean extends SimpleTrigger
}
/**
* Note that this method's declaration of a ParseException is deprecated
* and will be removed in the Spring 4.0 line.
*/
public void afterPropertiesSet() throws ParseException {
if (getName() == null) {
setName(this.beanName);
@@ -160,7 +164,7 @@ public class SimpleTriggerBean extends SimpleTrigger
if (getGroup() == null) {
setGroup(Scheduler.DEFAULT_GROUP);
}
if (getStartTime() == null) {
if (this.startDelay > 0 || getStartTime() == null) {
setStartTime(new Date(System.currentTimeMillis() + this.startDelay));
}
if (this.jobDetail != null) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.scheduling.quartz;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
@@ -34,6 +33,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -88,6 +88,8 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
private int misfireInstruction;
private String description;
private String beanName;
private SimpleTrigger simpleTrigger;
@@ -141,10 +143,20 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
this.jobDataMap.putAll(jobDataAsMap);
}
/**
* Set a specific start time for the trigger.
* <p>Note that a dynamically computed {@link #setStartDelay} specification
* overrides a static timestamp set here.
*/
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
/**
* Set the start delay in milliseconds.
* <p>The start delay is added to the current system time (when the bean starts)
* to control the start time of the trigger.
* @see #setStartTime
*/
public void setStartDelay(long startDelay) {
Assert.isTrue(startDelay >= 0, "Start delay cannot be negative");
@@ -195,12 +207,19 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
this.misfireInstruction = constants.asNumber(constantName).intValue();
}
/**
* Associate a textual description with this trigger.
*/
public void setDescription(String description) {
this.description = description;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void afterPropertiesSet() throws ParseException {
public void afterPropertiesSet() {
if (this.name == null) {
this.name = this.beanName;
}
@@ -210,12 +229,9 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
if (this.jobDetail != null) {
this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail);
}
if (this.startDelay > 0) {
if (this.startDelay > 0 || this.startTime == null) {
this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
}
else if (this.startTime == null) {
this.startTime = new Date();
}
/*
SimpleTriggerImpl sti = new SimpleTriggerImpl();
@@ -228,13 +244,14 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
sti.setRepeatCount(this.repeatCount);
sti.setPriority(this.priority);
sti.setMisfireInstruction(this.misfireInstruction);
sti.setDescription(this.description);
this.simpleTrigger = sti;
*/
Class simpleTriggerClass;
Class<?> simpleTriggerClass;
Method jobKeyMethod;
try {
simpleTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.SimpleTriggerImpl");
simpleTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.SimpleTriggerImpl", getClass().getClassLoader());
jobKeyMethod = JobDetail.class.getMethod("getKey");
}
catch (ClassNotFoundException ex) {
@@ -261,6 +278,7 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
pvs.add("repeatCount", this.repeatCount);
pvs.add("priority", this.priority);
pvs.add("misfireInstruction", this.misfireInstruction);
pvs.add("description", this.description);
bw.setPropertyValues(pvs);
this.simpleTrigger = (SimpleTrigger) bw.getWrappedInstance();
}
@@ -277,4 +295,5 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
public boolean isSingleton() {
return true;
}
}
@@ -59,7 +59,7 @@ public class SpringBeanJobFactory extends AdaptableJobFactory implements Schedul
* ignored if there is no corresponding property found on the particular
* job class (all other unknown properties will still trigger an exception).
*/
public void setIgnoredUnknownProperties(String[] ignoredUnknownProperties) {
public void setIgnoredUnknownProperties(String... ignoredUnknownProperties) {
this.ignoredUnknownProperties = ignoredUnknownProperties;
}
@@ -122,7 +122,7 @@ public class JasperReportsUtilsTests extends TestCase {
public void testRenderAsPdfWithExporterParameters() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Map<JRExporterParameter, Object> exporterParameters = new HashMap<JRExporterParameter, Object>();
exporterParameters.put(JRPdfExporterParameter.PDF_VERSION, JRPdfExporterParameter.PDF_VERSION_1_6.toString());
exporterParameters.put(JRPdfExporterParameter.PDF_VERSION, JRPdfExporterParameter.PDF_VERSION_1_6);
JasperReportsUtils.renderAsPdf(getReport(), getParameters(), getData(), os, exporterParameters);
byte[] output = os.toByteArray();
assertPdfOutputCorrect(output);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 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,7 +19,8 @@ package org.springframework.cache;
import java.util.Collection;
/**
* A manager for a set of {@link Cache}s.
* Spring's central cache manager SPI.
* Allows for retrieving named {@link Cache} regions.
*
* @author Costin Leau
* @since 3.1
@@ -28,14 +29,14 @@ public interface CacheManager {
/**
* Return the cache associated with the given name.
* @param name cache identifier (must not be {@code null})
* @return associated cache, or {@code null} if none is found
* @param name the cache identifier (must not be {@code null})
* @return the associated cache, or {@code null} if none found
*/
Cache getCache(String name);
/**
* Return a collection of the caches known by this cache manager.
* @return names of caches known by the cache manager.
* Return a collection of the cache names known by this manager.
* @return the names of all caches known by the cache manager
*/
Collection<String> getCacheNames();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -103,7 +103,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
* @param cacheOperationSources must not be {@code null}
*/
public void setCacheOperationSources(CacheOperationSource... cacheOperationSources) {
Assert.notEmpty(cacheOperationSources);
Assert.notEmpty(cacheOperationSources, "At least 1 CacheOperationSource needs to be specified");
this.cacheOperationSource = (cacheOperationSources.length > 1 ?
new CompositeCacheOperationSource(cacheOperationSources) : cacheOperationSources[0]);
}
@@ -132,10 +132,10 @@ public abstract class CacheAspectSupport implements InitializingBean {
public void afterPropertiesSet() {
if (this.cacheManager == null) {
throw new IllegalStateException("'cacheManager' is required");
throw new IllegalStateException("Property 'cacheManager' is required");
}
if (this.cacheOperationSource == null) {
throw new IllegalStateException("The 'cacheOperationSources' property is required: " +
throw new IllegalStateException("Property 'cacheOperationSources' is required: " +
"If there are no cacheable methods, then don't use a cache aspect.");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 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,7 @@
package org.springframework.cache.interceptor;
import java.lang.reflect.Method;
import org.springframework.cache.interceptor.KeyGenerator;
import java.util.Arrays;
/**
* Default key generator. Returns {@value #NO_PARAM_KEY} if no
@@ -29,25 +28,29 @@ import org.springframework.cache.interceptor.KeyGenerator;
*
* @author Costin Leau
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
*/
public class DefaultKeyGenerator implements KeyGenerator {
public static final int NO_PARAM_KEY = 0;
public static final int NULL_PARAM_KEY = 53;
public Object generate(Object target, Method method, Object... params) {
if (params.length == 1) {
return (params[0] == null ? NULL_PARAM_KEY : params[0]);
}
if (params.length == 0) {
return NO_PARAM_KEY;
}
int hashCode = 17;
for (Object object : params) {
hashCode = 31 * hashCode + (object == null ? NULL_PARAM_KEY : object.hashCode());
if (params.length == 1) {
Object param = params[0];
if (param == null) {
return NULL_PARAM_KEY;
}
if (!param.getClass().isArray()) {
return param;
}
}
return Integer.valueOf(hashCode);
return Arrays.deepHashCode(params);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 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,42 +17,73 @@
package org.springframework.cache.support;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
/**
* Composite {@link CacheManager} implementation that iterates
* over a given collection of {@link CacheManager} instances.
* Composite {@link CacheManager} implementation that iterates over
* a given collection of delegate {@link CacheManager} instances.
*
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
* the cache declarations without a backing store.
* <p>Allows {@link NoOpCacheManager} to be automatically added to the end of
* the list for handling cache declarations without a backing store. Otherwise,
* any custom {@link CacheManager} may play that role of the last delegate as
* well, lazily creating cache regions for any requested name.
*
* <p>Note: Regular CacheManagers that this composite manager delegates to need
* to return {@code null} from {@link #getCache(String)} if they are unaware of
* the specified cache name, allowing for iteration to the next delegate in line.
* However, most {@link CacheManager} implementations fall back to lazy creation
* of named caches once requested; check out the specific configuration details
* for a 'static' mode with fixed cache names, if available.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 3.1
* @see #setFallbackToNoOpCache
* @see org.springframework.cache.concurrent.ConcurrentMapCacheManager#setCacheNames
*/
public class CompositeCacheManager implements InitializingBean, CacheManager {
public class CompositeCacheManager implements CacheManager, InitializingBean {
private List<CacheManager> cacheManagers;
private final List<CacheManager> cacheManagers = new ArrayList<CacheManager>();
private boolean fallbackToNoOpCache = false;
/**
* Construct an empty CompositeCacheManager, with delegate CacheManagers to
* be added via the {@link #setCacheManagers "cacheManagers"} property.
*/
public CompositeCacheManager() {
}
/**
* Construct a CompositeCacheManager from the given delegate CacheManagers.
* @param cacheManagers the CacheManagers to delegate to
*/
public CompositeCacheManager(CacheManager... cacheManagers) {
setCacheManagers(Arrays.asList(cacheManagers));
}
/**
* Specify the CacheManagers to delegate to.
*/
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
Assert.notEmpty(cacheManagers, "cacheManagers Collection must not be empty");
this.cacheManagers = new ArrayList<CacheManager>();
this.cacheManagers.clear(); // just here to preserve compatibility with previous behavior
this.cacheManagers.addAll(cacheManagers);
}
/**
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the manager lists.
* In this case, any {@code getCache} requests not handled by the configured cache managers will
* Indicate whether a {@link NoOpCacheManager} should be added at the end of the delegate list.
* In this case, any {@code getCache} requests not handled by the configured CacheManagers will
* be automatically handled by the {@link NoOpCacheManager} (and hence never return {@code null}).
*/
public void setFallbackToNoOpCache(boolean fallbackToNoOpCache) {
@@ -77,11 +108,11 @@ public class CompositeCacheManager implements InitializingBean, CacheManager {
}
public Collection<String> getCacheNames() {
List<String> names = new ArrayList<String>();
Set<String> names = new LinkedHashSet<String>();
for (CacheManager manager : this.cacheManagers) {
names.addAll(manager.getCacheNames());
}
return Collections.unmodifiableList(names);
return Collections.unmodifiableSet(names);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Convenient base class for {@link ImportSelector} implementations that select imports
* based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*}
@@ -40,6 +38,7 @@ public abstract class AdviceModeImportSelector<A extends Annotation> implements
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
/**
* The name of the {@link AdviceMode} attribute for the annotation specified by the
* generic type {@code A}. The default is {@value #DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME},
@@ -50,47 +49,37 @@ public abstract class AdviceModeImportSelector<A extends Annotation> implements
}
/**
* {@inheritDoc}
*
* <p>This implementation resolves the type of annotation from generic metadata and
* This implementation resolves the type of annotation from generic metadata and
* validates that (a) the annotation is in fact present on the importing
* {@code @Configuration} class and (b) that the given annotation has an
* {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type
* {@link AdviceMode}.
*
* <p>The {@link #selectImports(AdviceMode)} method is then invoked, allowing the
* concrete implementation to choose imports in a safe and convenient fashion.
*
* @throws IllegalArgumentException if expected annotation {@code A} is not present
* on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)}
* returns {@code null}
*/
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annoType = GenericTypeResolver.resolveTypeArgument(this.getClass(), AdviceModeImportSelector.class);
AnnotationAttributes attributes = attributesFor(importingClassMetadata, annoType);
Class<?> annoType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
AnnotationAttributes attributes = MetadataUtils.attributesFor(importingClassMetadata, annoType);
Assert.notNull(attributes, String.format(
"@%s is not present on importing class '%s' as expected",
annoType.getSimpleName(), importingClassMetadata.getClassName()));
AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName());
String[] imports = selectImports(adviceMode);
Assert.notNull(imports, String.format("Unknown AdviceMode: '%s'", adviceMode));
return imports;
}
/**
* Determine which classes should be imported based on the given {@code AdviceMode}.
*
* <p>Returning {@code null} from this method indicates that the {@code AdviceMode} could
* not be handled or was unknown and that an {@code IllegalArgumentException} should
* be thrown.
*
* @param adviceMode the value of the {@linkplain #getAdviceModeAttributeName()
* advice mode attribute} for the annotation specified via generics.
*
* @return array containing classes to import; empty array if none, {@code null} if
* the given {@code AdviceMode} is unknown.
*/
@@ -88,13 +88,16 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
for (String type : types) {
AnnotationAttributes attributes = MetadataUtils.attributesFor(amd, type);
if (isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {
String value = (String) attributes.get("value");
if (StringUtils.hasLength(value)) {
if (beanName != null && !value.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + value + "'");
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
beanName = value;
}
}
}
@@ -117,9 +120,7 @@ public class AnnotationBeanNameGenerator implements BeanNameGenerator {
annotationType.equals("javax.annotation.ManagedBean") ||
annotationType.equals("javax.inject.Named");
return (isStereotype && attributes != null &&
attributes.containsKey("value") &&
attributes.get("value") instanceof String);
return (isStereotype && attributes != null && attributes.containsKey("value"));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -208,8 +208,8 @@ public class AnnotationConfigUtils {
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,11 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -33,8 +32,8 @@ import org.springframework.core.type.AnnotationMetadata;
* {@code proxyTargetClass} attributes set to the correct values.
*
* @author Chris Beams
* @see EnableAspectJAutoProxy
* @since 3.1
* @see EnableAspectJAutoProxy
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@@ -47,7 +46,6 @@ public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
* attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
* {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
* subclass (CGLIB) proxying.
*
* <p>Several {@code @Enable*} annotations expose both {@code mode} and
* {@code proxyTargetClass} attributes. It is important to note that most of these
* capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
@@ -60,16 +58,15 @@ public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = attributesFor(importingClassMetadata, annoType);
AnnotationAttributes candidate = MetadataUtils.attributesFor(importingClassMetadata, annoType);
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null
&& mode.getClass().equals(AdviceMode.class)
&& proxyTargetClass.getClass().equals(Boolean.class)) {
if (mode != null && proxyTargetClass != null && mode.getClass().equals(AdviceMode.class) &&
proxyTargetClass.getClass().equals(Boolean.class)) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean)proxyTargetClass) {
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
@@ -88,4 +85,5 @@ public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
"altogether.", name, name, name));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -197,25 +197,26 @@ public @interface Bean {
/**
* The optional name of a method to call on the bean instance during initialization.
* Not commonly used, given that the method may be called programmatically directly
* within the body of a Bean-annotated method. Default value is {@code ""}, indicating
* that no init method should be called.
* within the body of a Bean-annotated method.
* <p>The default value is {@code ""}, indicating no init method to be called.
*/
String initMethod() default "";
/**
* The optional name of a method to call on the bean instance upon closing the
* application context, for example a {@code close()} method on a JDBC {@code
* DataSource} implementation, or a Hibernate {@code SessionFactory} object.
* application context, for example a {@code close()} method on a JDBC
* {@code DataSource} implementation, or a Hibernate {@code SessionFactory} object.
* The method must have no arguments but may throw any exception.
* <p>As a convenience to the user, the container will attempt to infer a destroy
* method against an object returned from the {@code @Bean} method. For example, given a
* {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource}, the
* container will notice the {@code close()} method available on that object and
* method against an object returned from the {@code @Bean} method. For example, given
* an {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource},
* the container will notice the {@code close()} method available on that object and
* automatically register it as the {@code destroyMethod}. This 'destroy method
* inference' is currently limited to detecting only public, no-arg methods named
* 'close'. The method may be declared at any level of the inheritance hierarchy and
* will be detected regardless of the return type of the {@code @Bean} method (i.e.,
* detection occurs reflectively against the bean instance itself at creation time).
* 'close' or 'shutdown'. The method may be declared at any level of the inheritance
* hierarchy and will be detected regardless of the return type of the {@code @Bean}
* method (i.e., detection occurs reflectively against the bean instance itself at
* creation time).
* <p>To disable destroy method inference for a particular {@code @Bean}, specify an
* empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
* {@link org.springframework.beans.factory.DisposableBean} and the
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -227,7 +227,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
@@ -235,7 +235,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -145,10 +145,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
private static Class<? extends Annotation> ejbRefClass = null;
static {
ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.xml.ws.WebServiceRef");
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());
webServiceRefClass = clazz;
}
catch (ClassNotFoundException ex) {
@@ -156,7 +156,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.ejb.EJB");
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());
ejbRefClass = clazz;
}
catch (ClassNotFoundException ex) {
@@ -314,10 +315,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (metadata == null) {
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
@@ -606,7 +607,7 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
if (StringUtils.hasLength(this.wsdlLocation)) {
try {
Constructor<?> ctor = this.lookupType.getConstructor(new Class[] {URL.class, QName.class});
Constructor<?> ctor = this.lookupType.getConstructor(new Class<?>[] {URL.class, QName.class});
WebServiceClient clientAnn = this.lookupType.getAnnotation(WebServiceClient.class);
if (clientAnn == null) {
throw new IllegalStateException("JAX-WS Service class [" + this.lookupType.getName() +
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2014 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.
@@ -239,7 +239,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
return new RegexPatternTypeFilter(Pattern.compile(expression));
}
else if ("custom".equals(filterType)) {
Class filterClass = classLoader.loadClass(expression);
Class<?> filterClass = classLoader.loadClass(expression);
if (!TypeFilter.class.isAssignableFrom(filterClass)) {
throw new IllegalArgumentException(
"Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression);
@@ -256,8 +256,8 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
}
@SuppressWarnings("unchecked")
private Object instantiateUserDefinedStrategy(String className, Class strategyType, ClassLoader classLoader) {
Object result = null;
private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) {
Object result;
try {
result = classLoader.loadClass(className).newInstance();
}
@@ -267,7 +267,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
}
catch (Exception ex) {
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
strategyType.getName() + "]. A zero-argument constructor is required", ex);
strategyType.getName() + "]: a zero-argument constructor is required", ex);
}
if (!strategyType.isAssignableFrom(result.getClass())) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -179,7 +179,7 @@ final class ConfigurationClass {
for (BeanMethod beanMethod : this.beanMethods) {
String fqMethodName = beanMethod.getFullyQualifiedMethodName();
Integer currentCount = methodNameCounts.get(fqMethodName);
int newCount = currentCount != null ? currentCount + 1 : 1;
int newCount = (currentCount != null ? currentCount + 1 : 1);
methodNameCounts.put(fqMethodName, newCount);
}
for (String fqMethodName : methodNameCounts.keySet()) {
@@ -51,8 +51,6 @@ import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Reads a given fully-populated set of ConfigurationClass instances, registering bean
* definitions with the given {@link BeanDefinitionRegistry} based on its contents.
@@ -173,13 +171,13 @@ class ConfigurationClassBeanDefinitionReader {
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
// consider role
AnnotationAttributes role = attributesFor(metadata, Role.class);
AnnotationAttributes role = MetadataUtils.attributesFor(metadata, Role.class);
if (role != null) {
beanDef.setRole(role.<Integer>getNumber("value"));
}
// consider name and any aliases
AnnotationAttributes bean = attributesFor(metadata, Bean.class);
AnnotationAttributes bean = MetadataUtils.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());
for (String alias : names) {
@@ -216,16 +214,16 @@ class ConfigurationClassBeanDefinitionReader {
// is this bean to be instantiated lazily?
if (metadata.isAnnotated(Lazy.class.getName())) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
AnnotationAttributes lazy = MetadataUtils.attributesFor(metadata, Lazy.class);
beanDef.setLazyInit(lazy.getBoolean("value"));
}
else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())){
AnnotationAttributes lazy = attributesFor(configClass.getMetadata(), Lazy.class);
AnnotationAttributes lazy = MetadataUtils.attributesFor(configClass.getMetadata(), Lazy.class);
beanDef.setLazyInit(lazy.getBoolean("value"));
}
if (metadata.isAnnotated(DependsOn.class.getName())) {
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
AnnotationAttributes dependsOn = MetadataUtils.attributesFor(metadata, DependsOn.class);
String[] otherBeans = dependsOn.getStringArray("value");
if (otherBeans.length > 0) {
beanDef.setDependsOn(otherBeans);
@@ -249,7 +247,7 @@ class ConfigurationClassBeanDefinitionReader {
// Consider scoping
ScopedProxyMode proxyMode = ScopedProxyMode.NO;
AnnotationAttributes scope = attributesFor(metadata, Scope.class);
AnnotationAttributes scope = MetadataUtils.attributesFor(metadata, Scope.class);
if (scope != null) {
beanDef.setScope(scope.getString("value"));
proxyMode = scope.getEnum("proxyMode");
@@ -272,7 +270,7 @@ class ConfigurationClassBeanDefinitionReader {
configClass.getMetadata().getClassName(), beanName));
}
registry.registerBeanDefinition(beanName, beanDefToRegister);
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}
@@ -297,7 +295,8 @@ class ConfigurationClassBeanDefinitionReader {
readerInstanceCache.put(readerClass, readerInstance);
}
catch (Exception ex) {
throw new IllegalStateException("Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
throw new IllegalStateException(
"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
}
}
BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +29,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
import org.springframework.cglib.core.SpringNamingPolicy;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
@@ -39,8 +40,13 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
/**
* Enhances {@link Configuration} classes by generating a CGLIB subclass capable of
* interacting with the Spring container to respect bean semantics.
* Enhances {@link Configuration} classes by generating a CGLIB subclass which
* interacts with the Spring container to respect bean scoping semantics for
* {@code @Bean} methods. Each such {@code @Bean} method will be overridden in
* the generated subclass, only delegating to the actual {@code @Bean} method
* implementation if the container actually requests the construction of a new
* instance. Otherwise, a call to such an {@code @Bean} method serves as a
* reference back to the container, obtaining the corresponding bean by name.
*
* @author Chris Beams
* @author Juergen Hoeller
@@ -105,6 +111,7 @@ class ConfigurationClassEnhancer {
enhancer.setSuperclass(superclass);
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_TYPES);
return enhancer;
@@ -128,9 +135,9 @@ class ConfigurationClassEnhancer {
* Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance(Class)}
* through checking to see if candidate classes are already assignable to it, e.g.
* have already been enhanced.
* <p>Also extends {@link DisposableBean}, as all enhanced
* {@code @Configuration} classes must de-register static CGLIB callbacks on
* destruction, which is handled by the (private) {@code DisposableBeanMethodInterceptor}.
* <p>Also extends {@link DisposableBean}, as all enhanced {@code @Configuration}
* classes must de-register static CGLIB callbacks on destruction, which is handled
* by the (private) {@code DisposableBeanMethodInterceptor}.
* <p>Note that this interface is intended for framework-internal use only, however
* must remain public in order to allow access to subclasses generated from other
* packages (i.e. user code).
@@ -353,7 +360,7 @@ class ConfigurationClassEnhancer {
};
enhancer.setCallbackTypes(CALLBACK_TYPES);
Class<?> fbSubclass = enhancer.createClass();
Enhancer.registerCallbacks(fbSubclass, callbackInstances);
Enhancer.registerStaticCallbacks(fbSubclass, callbackInstances);
return fbSubclass.newInstance();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,6 +42,7 @@ import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.NestedIOException;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -59,8 +60,6 @@ import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
/**
* Parses a {@link Configuration} class definition, populating a collection of
* {@link ConfigurationClass} objects (parsing a single Configuration class may result in
@@ -172,20 +171,19 @@ class ConfigurationClassParser {
/**
* @return annotation metadata of superclass, {@code null} if none found or previously processed
*/
protected AnnotationMetadata doProcessConfigurationClass(
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
protected AnnotationMetadata doProcessConfigurationClass(ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// recursively process any member (nested) classes first
processMemberClasses(metadata);
// process any @PropertySource annotations
AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
AnnotationAttributes propertySource = MetadataUtils.attributesFor(metadata,
org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) {
processPropertySource(propertySource);
}
// process any @ComponentScan annotations
AnnotationAttributes componentScan = attributesFor(metadata, ComponentScan.class);
AnnotationAttributes componentScan = MetadataUtils.attributesFor(metadata, ComponentScan.class);
if (componentScan != null) {
// the config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
@@ -204,12 +202,12 @@ class ConfigurationClassParser {
Set<Object> visited = new LinkedHashSet<Object>();
collectImports(metadata, imports, visited);
if (!imports.isEmpty()) {
processImport(configClass, imports, true);
processImport(configClass, metadata, imports, true);
}
// process any @ImportResource annotations
if (metadata.isAnnotated(ImportResource.class.getName())) {
AnnotationAttributes importResource = attributesFor(metadata, ImportResource.class);
AnnotationAttributes importResource = MetadataUtils.attributesFor(metadata, ImportResource.class);
String[] resources = importResource.getStringArray("value");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
@@ -227,23 +225,13 @@ class ConfigurationClassParser {
// process superclass, if any
if (metadata.hasSuperClass()) {
String superclass = metadata.getSuperClassName();
if (!this.knownSuperclasses.containsKey(superclass)) {
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// superclass found, return its annotation metadata and recurse
if (metadata instanceof StandardAnnotationMetadata) {
Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass();
return new StandardAnnotationMetadata(clazz.getSuperclass(), true);
}
else if (superclass.startsWith("java")) {
// never load core JDK classes via ASM, in particular not java.lang.Object!
try {
return new StandardAnnotationMetadata(
this.resourceLoader.getClassLoader().loadClass(superclass), true);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}
}
else {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superclass);
return reader.getAnnotationMetadata();
@@ -369,13 +357,14 @@ class ConfigurationClassParser {
}
}
private void processImport(ConfigurationClass configClass, Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
private void processImport(ConfigurationClass configClass, AnnotationMetadata metadata,
Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
}
else {
this.importStack.push(configClass);
AnnotationMetadata importingClassMetadata = configClass.getMetadata();
try {
for (Object candidate : classesToImport) {
Object candidateToCheck = (candidate instanceof Class ? (Class) candidate :
@@ -385,7 +374,7 @@ class ConfigurationClassParser {
Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate :
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
processImport(configClass, Arrays.asList(selector.selectImports(importingClassMetadata)), false);
processImport(configClass, metadata, Arrays.asList(selector.selectImports(metadata)), false);
}
else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
@@ -393,11 +382,11 @@ class ConfigurationClassParser {
this.resourceLoader.getClassLoader().loadClass((String) candidate));
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar);
registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
registrar.registerBeanDefinitions(metadata, this.registry);
}
else {
// candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata,
this.importStack.registerImport(metadata,
(candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) :
new ConfigurationClass((MetadataReader) candidateToCheck, true));
@@ -423,11 +412,14 @@ class ConfigurationClassParser {
}
/**
* Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
* {@link BeanFactoryAware} contracts if implemented by the given {@code registrar}.
* Invoke {@link EnvironmentAware}, {@link ResourceLoaderAware}, {@link BeanClassLoaderAware}
* and {@link BeanFactoryAware} contracts if implemented by the given {@code registrar}.
*/
private void invokeAwareMethods(ImportBeanDefinitionRegistrar registrar) {
if (registrar instanceof Aware) {
if (registrar instanceof EnvironmentAware) {
((EnvironmentAware) registrar).setEnvironment(this.environment);
}
if (registrar instanceof ResourceLoaderAware) {
((ResourceLoaderAware) registrar).setResourceLoader(this.resourceLoader);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,14 +93,36 @@ abstract class ConfigurationClassUtils {
return false;
}
/**
* Check the given metadata for a configuration class candidate
* (or nested component class declared within a configuration/component class).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be registered as a
* reflection-detected bean definition; {@code false} otherwise
*/
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}
/**
* Check the given metadata for a full configuration class candidate
* (i.e. a class annotated with {@code @Configuration}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a full
* configuration class, including cross-method call interception
*/
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
/**
* Check the given metadata for a lite configuration class candidate
* (e.g. a class annotated with {@code @Component} or just having
* {@code @Bean methods}).
* @param metadata the metadata of the annotated class
* @return {@code true} if the given class is to be processed as a lite
* configuration class, just registering it and scanning it for {@code @Bean} methods
*/
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
// Do not consider an interface or an annotation...
return (!metadata.isInterface() && (
@@ -108,7 +130,8 @@ abstract class ConfigurationClassUtils {
}
/**
* Determine whether the given bean definition indicates a full @Configuration class.
* Determine whether the given bean definition indicates a full
* {@code @Configuration} class.
*/
public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,11 +23,14 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.OrderComparator;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
@@ -49,13 +52,16 @@ import org.springframework.util.ObjectUtils;
* @see #getApplicationListeners(ApplicationEvent)
* @see SimpleApplicationEventMulticaster
*/
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
public abstract class AbstractApplicationEventMulticaster
implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache =
new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
@@ -95,8 +101,15 @@ public abstract class AbstractApplicationEventMulticaster implements Application
}
}
public final void setBeanFactory(BeanFactory beanFactory) {
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) {
this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader();
}
}
private BeanFactory getBeanFactory() {
@@ -162,7 +175,11 @@ public abstract class AbstractApplicationEventMulticaster implements Application
}
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(eventType, this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
this.retrieverCache.put(cacheKey, retriever);
}
return allListeners;
}
}
@@ -176,8 +193,8 @@ public abstract class AbstractApplicationEventMulticaster implements Application
* @param listener the target listener to check
* @param eventType the event type to check against
* @param sourceType the source type to check against
* @return whether the given listener should be included in the
* candidates for the given event type
* @return whether the given listener should be included in the candidates
* for the given event type
*/
protected boolean supportsEvent(
ApplicationListener listener, Class<? extends ApplicationEvent> eventType, Class sourceType) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2014 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,6 +32,11 @@ import org.springframework.expression.TypedValue;
*/
public class BeanFactoryAccessor implements PropertyAccessor {
public Class<?>[] getSpecificTargetClasses() {
return new Class<?>[] {BeanFactory.class};
}
@Override
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
return (((BeanFactory) target).containsBean(name));
}
@@ -48,8 +53,4 @@ public class BeanFactoryAccessor implements PropertyAccessor {
throw new AccessException("Beans in a BeanFactory are read-only");
}
public Class[] getSpecificTargetClasses() {
return new Class[] {BeanFactory.class};
}
}

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