Compare commits

...

93 Commits

Author SHA1 Message Date
Rossen Stoyanchev 7a7df66374 Update JavaScriptUtils
Add escaping for <, >, and PS/LS line terminators

Issue: SPR-9983
2013-02-15 06:45:54 -05:00
Spring Buildmaster 63bff1f068 Increment version to 3.1.5.BUILD-SNAPSHOT 2013-01-23 15:00:13 +01:00
Spring Buildmaster e7d2ac4427 Release version 3.1.4.RELEASE 2013-01-23 14:58:18 +01:00
Chris Beams ae1b36dc4f Update changelog for 3.1.4 2013-01-23 12:53:25 +01:00
Juergen Hoeller 75a84b50e3 Fixed potential SLF4J version mismatch through referring to fixed Hibernate EntityManager 3.4.0.GA-A bundles 2013-01-23 12:47:49 +01:00
Rossen Stoyanchev 72013f975c Raise exception on missing request parameters
Issue: SPR-10193
2013-01-22 18:10:36 -05:00
Rossen Stoyanchev 3a6e7b8020 Support sub-types of ResponseEntity
Issue: SPR-10207
2013-01-22 17:25:52 -05:00
Juergen Hoeller 8a93309c22 Final preparations for 3.1.4 2013-01-22 21:11:10 +01:00
Juergen Hoeller 50ed863279 EntityManagerFactoryUtils finds default EntityManagerFactory in parent contexts as well
Also introduces consistent use of getBean(Class) for similar use cases across the framework, accepting a locally unique target bean even if further matching beans would be available in parent contexts (in contrast to BeanFactoryUtils.beanOfType's behavior).

Issue: SPR-10160
2013-01-22 20:39:23 +01:00
Juergen Hoeller f9bb4b3b80 MockHttpServletResponse's getHeaderNames declares Collection instead of Set for Servlet 3.0 compatibility
Issue: SPR-9885
2013-01-22 16:07:12 +01:00
Juergen Hoeller 01f31027d7 MockHttpServletRequest's getParameter(Values) returns null for null parameter name
Issue: SPR-10192
2013-01-22 16:07:11 +01:00
Chris Beams a52396b342 Backport "Remove xsd versions from reference samples"
Issue: SPR-10010
2013-01-22 16:03:36 +01:00
Chris Beams d547570bcd Merge branch 'backport-SPR-9925' into 3.1.x
* backport-SPR-9925:
  Backport "Polish @Imports search code"
  Backport "Ensure @Imports are processed in correct order"
  Backport "Prevent duplicate @Import processing"
  Backport "Polish Javadoc for @Import"
2013-01-22 15:24:00 +01:00
Phillip Webb a9290d80c4 Backport "Polish @Imports search code"
Issue: SPR-9925
Backport-Commit: 4cdf46f83c
Conflicts:
	spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
2013-01-22 15:19:52 +01:00
Phillip Webb 1f52f09089 Backport "Ensure @Imports are processed in correct order"
Issue: SPR-9925
Backport-Commit: 3416e058a0
Conflicts:
	spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
2013-01-22 15:17:46 +01:00
Phillip Webb e9616b7204 Backport "Prevent duplicate @Import processing"
Refactor ConfigurationClassParser to recursively find values from
all @Import annotations, combining them into a single unique set.

This change prevents ImportBeanDefinitionRegistrars from being
invoked twice.

Issue: SPR-9925
Backport-Commit: 6d8b37d8bb
Conflicts:
	spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
2013-01-22 15:15:25 +01:00
Phillip Webb bbd5fc6f35 Backport "Polish Javadoc for @Import"
Issue: SPR-9925
Backport-Commit: e6c4840356
Conflicts:
	spring-context/src/main/java/org/springframework/context/annotation/Import.java
2013-01-22 15:12:56 +01:00
Chris Beams a420e84591 Backport "Support XML properties in ResourcePropertySource"
JDK 5 introduced an XML-based properties file syntax. This commit
ensures that when such files are supplied as the underlying resource
for a ResourcePropertySource instance, they are routed appropriately
to Properties#loadFromXML as opposed to Properties#load.

Issue: SPR-9896
Backport-Commit: 3a626f9319
2013-01-22 14:20:27 +01:00
Rossen Stoyanchev b1267b95b9 Fix NPE in FormHttpMessageConverter
Issue: SPR-10187
2013-01-21 14:11:06 -05:00
Chris Beams a3161632dd Backport "Use ExtendedBeanInfo on an as-needed basis only"
Prior to this change, CachedIntrospectionResults delegated to
ExtendedBeanInfo by default in order to inspect JavaBean
PropertyDescriptor information for bean classes.

Originally introduced with SPR-8079, ExtendedBeanInfo was designed to
go beyond the capabilities of the default JavaBeans Introspector in
order to support non-void returning setter methods, principally to
support use of builder-style APIs within Spring XML. This is a complex
affair, and the non-trivial logic in ExtendedBeanInfo has led to various
bugs including regressions for bean classes that do not declare
non-void returning setters.

Many of these issues were fixed when overhauling non-void JavaBean write
method support in SPR-10029, however it appears that some extremely
subtle issues may still remain. ExtendedBeanInfo was taken out of use
completely in the 3.2.x line with SPR-9677 and the new BeanInfoFactory
mechanism. This support was not backported to 3.1.x, however, in the
interest of stability.

This commit, then, inlines the conditional logic introduced by
BeanInfoFactory directly into CachedIntrospectionResults. The net effect
is that ExtendedBeanInfo is out of the code path entirely except for
bean classes that actually contain 'candidate' methods, i.e. non-void
and/or static write methods.

This commit also includes the changes made in SPR-10115.

Issue: SPR-9723, SPR-10029, SPR-9677, SPR-8079
2013-01-21 19:44:18 +01:00
Rossen Stoyanchev e731746bb0 Fix exception message about producible media types
Issue: SPR-10175
2013-01-21 12:40:45 -05:00
Rossen Stoyanchev f2d7d663b4 Update HttpHeaders.getAccept method
Some servlet containers (iPlanet) parse the Accept header and return
multiple values from request.getHeader("Accept"). The HttpHeaders
getAccept method has been updated to accommodate that hopefully
without causing any other issues.

The extra functionality is in effect only if we find only one
MediaType and there is more than one value for the 'Accept' header.

Issue: SPR-9655
2013-01-21 12:25:21 -05:00
Chris Beams acd268e48f Fix broken Castor URLs in ref docs and mapping XML
Issue: SPR-10189
Backport-Commit: d40c8cf

Conflicts:
	spring-framework-reference/src/oxm.xml
2013-01-21 11:29:42 +01:00
Chris Beams 9d77afc218 Fix typo in reference documentation
Issue: SPR-10171
Backport-Commit: 24cc33306d

Conflicts:
	spring-framework-reference/src/overview.xml
2013-01-21 11:08:46 +01:00
Juergen Hoeller f3d0beb955 AbstractDriverBasedDataSource does not rely on Properties chaining anymore
Issue: SPR-9461
2013-01-18 19:07:46 +01:00
Juergen Hoeller 245c61e278 Further preparations for 3.1.4 2013-01-18 18:01:41 +01:00
Juergen Hoeller c374389a59 Added "exposeAccessContext" flag JndiRmiClientInterceptor/ProxyFactoryBean (for WebLogic)
Issue: SPR-9428
2013-01-18 16:51:52 +01:00
Juergen Hoeller b720804c6d ContextLoader properly detects pre-refreshed WebApplicationContext
Issue: SPR-9996
2013-01-18 15:21:23 +01:00
Juergen Hoeller 1e888706d3 BridgeMethodResolver properly handles bridge methods in interfaces
Issue: SPR-9330
2013-01-18 15:00:23 +01:00
Juergen Hoeller 1bca2c01fd LocalVariableTableParameterNameDiscoverer works for bridge methods as well
Issue: SPR-9429
2013-01-18 14:52:48 +01:00
Juergen Hoeller 0c45f179b3 MBeanExporter does not log warnings for manually unregistered MBeans
Issue: SPR-9451
2013-01-18 14:43:39 +01:00
Juergen Hoeller eb492ed583 SpringBeanAutowiringInterceptor eagerly releases BeanFactory if post-construction fails
Issue: SPR-10013
2013-01-18 14:13:35 +01:00
Juergen Hoeller cd8d72e3f8 AbstractDriverBasedDataSource does not rely on Properties chaining anymore
Issue: SPR-9461
2013-01-18 14:02:40 +01:00
Juergen Hoeller 8cf61c595e Added hint towards not using orm.hibernate3 classes with Hibernate 4
Issue: SPR-9365
2013-01-18 13:58:39 +01:00
Juergen Hoeller 8422da4d3f Fixed reference to "fallbackToNoOpCache" flag
Issue: SPR-9064
2013-01-18 13:50:22 +01:00
Juergen Hoeller b93d266c75 Fixed ConnectionSpecConnectionFactoryAdapter explanation
Issue: SPR-9466
2013-01-18 13:47:27 +01:00
Juergen Hoeller 57bf64364f Removed reference to AttributesJmxAttributeSource
Issue: SPR-8916
2013-01-18 13:42:53 +01:00
Juergen Hoeller ebbcc4d9fb CachedIntrospectionResults.clearClassLoader(null) removes cached classes for the system class loader
Issue: SPR-9189
2013-01-16 10:24:44 +01:00
Juergen Hoeller 27f0142d9e Further fixes for 3.1.4 2013-01-15 22:10:28 +01:00
Juergen Hoeller 8135442336 Polishing 2013-01-15 22:09:52 +01:00
Juergen Hoeller aa388bc094 Reintroduced "mode" and "proxy-target-class" attributes in spring-task-3.1.xsd
Issue: SPR-10177
2013-01-15 22:05:52 +01:00
Juergen Hoeller e5783b1bfa SpEL support for static finals on interfaces
Issue: SPR-10125
Backport-Issue: SPR-10174
2013-01-15 16:51:35 +01:00
Juergen Hoeller 7f7fbe8172 AbstractCacheManager accepts no caches defined, allowing for EHCache default cache setup
Issue: SPR-7955
2013-01-15 15:55:43 +01:00
Phillip Webb 42ab04a299 Remove accidentally committed interface @Override 2013-01-11 15:23:27 -08:00
Phillip Webb 5ae706ee10 Consider bridge methods in SpEL properties
Revert ReflectivePropertyAccessor changes from 107fafb and instead
consider all methods when resolving properties. Methods are now
sorted such that non-bridge methods are considered before bridge
methods.

Issue: SPR-10162
Backport-Commit: fce7adc400
2013-01-11 15:17:51 -08:00
Juergen Hoeller f449b5a5b3 JDBC parameter binding uses JDBC 3.0 ParameterMetaData (if available) for type determination
In sync with 3.2.1 now, containing minor modifications for defensiveness against the JDBC driver.

Issue: SPR-10084
2013-01-11 21:57:55 +01:00
Juergen Hoeller bdc8d798e2 Further backports from 3.2.1 2013-01-10 17:04:19 +01:00
Juergen Hoeller 30ad07a4e2 SpringContextResourceAdapter implements equals/hashCode according to the JCA 1.5 contract
Issue: SPR-9162
2013-01-10 17:03:33 +01:00
Juergen Hoeller 0ed1a21073 FreeMarkerConfigurationFactory properly supports TemplateLoaders when recreating Configurations
Issue: SPR-9389
2013-01-10 17:03:31 +01:00
Juergen Hoeller bad2b900e9 MimeMessageHelper encodes attachment filename if not ASCII compliant
Issue: SPR-9258
2013-01-10 17:03:30 +01:00
Juergen Hoeller 9a04191c2b MessageSourceResourceBundle overrides JDK 1.6 containsKey method, avoiding NPE in getKeys
Issue: SPR-10136
2013-01-10 17:03:29 +01:00
Chris Beams a7889c9df4 Backport "Add 3.1 migration section to reference docs"
Address error raised when using component-scan against the unqualified
"org" base package.

Issue: SPR-9843
Backport-Commit: b8f223c404
2013-01-08 11:46:37 +01:00
Phillip Webb 1cd7600d8a Backport "Replace reference to aspectjrt with aspectjweaver"
Replace reference to aspectjrt.jar with aspectjweaver.jar since
aspectjrt is a subset of aspectjweaver and the full jar is required
by Spring.

Issue: SPR-8896
Backport-Commit: d70762baaf
2012-12-31 15:06:21 +01:00
Chris Beams 418c2a8641 Add spring-oxm-1.5.xsd
Issue: SPR-10121
Backport-Commit: 3724b90a8f
2012-12-26 09:39:08 +01:00
Juergen Hoeller 377f3eecb4 Preparations for 3.1.4 release in January 2012-12-21 21:34:56 +01:00
Juergen Hoeller d1efd4c3a1 Marked LocalCacheProviderProxy as deprecated (following Hibernate 3.3.'s CacheProvider deprecation) 2012-12-21 21:32:56 +01:00
Juergen Hoeller aba4be83a7 Upgraded remaining Hibernate 3.3.1 dependencies to Hibernate 3.3.2.GA (and SLF4J 1.6.1) 2012-12-21 21:31:36 +01:00
Juergen Hoeller 5bc58773fb Fixed javadoc 2012-12-20 20:32:59 +01:00
Juergen Hoeller 39fe8eebb1 JmsTemplate uses configured receiveTimeout if shorter than remaining transaction timeout
Issue: SPR-10109
2012-12-20 20:32:58 +01:00
Juergen Hoeller 778693f9f8 Added MappingJackson2MessageConverter for JMS
Issue: SPR-10099
2012-12-20 20:32:57 +01:00
Chris Beams aa3e0be1a0 Handle non-void write methods deterministically
This change resolves a specific issue with processing
java.math.BigDecimal via ExtendedBeanInfo. BigDecimal has a particular
constellation of #setScale methods that, prior to this change, had the
potential to cause ExtendedBeanInfo to throw an IntrospectionException
depending on the order in which the methods were processed.

Because JDK 7 no longer returns deterministic results from
Class#getDeclaredMethods, it became a genuine possibility - indeed a
statistical certainty that the 'wrong' setScale method handling order
happens sooner or later. Typically one could observe this failure once
out of every four test runs.

This commit introduces deterministic method ordering of all discovered
non-void returning write methods in such a way that solves the problem
for BigDecimal as well as for any other class having a similar method
arrangement.

Also:

 - Remove unnecessary cast

 - Pass no method information to PropertyDescriptor superclasses when
   invoking super(...). This ensures that any 'type mismatch'
   IntrospectionExceptions are handled locally in ExtendedBeanInfo and
   its Simple* PropertyDescriptor variants where we have full control.

Issue: SPR-10111, SPR-9702
2012-12-20 02:16:07 +01:00
Juergen Hoeller 28c7760c79 Further backports from 3.2 GA 2012-12-13 11:34:17 +01:00
Juergen Hoeller cc11b811ea DefaultMessageListenerContainer clears resources of paused tasks when shutting down after stop
Issue: SPR-10092
2012-12-13 11:29:51 +01:00
Juergen Hoeller 8abe1f055e SpEL correctly handles "is" accessors with Boolean return type
Issue: SPR-10091
2012-12-13 11:28:06 +01:00
Juergen Hoeller 12c4f8e7f9 Polishing 2012-12-13 00:07:36 +01:00
Juergen Hoeller b9ff29ec7e Revised NoOpCacheManager implementation (along with changes for 3.2 GA) 2012-12-13 00:07:16 +01:00
Juergen Hoeller a551cbcf9d Marked all applicable fields as final (along with changes for 3.2 GA) 2012-12-13 00:06:00 +01:00
Juergen Hoeller c207882fdc Removed unused cachedFieldValue (along with changes for 3.2 GA) 2012-12-13 00:05:05 +01:00
Juergen Hoeller ab21bd4266 Fixed targetSourcedBeans contains check (along with changes for 3.2 GA) 2012-12-13 00:04:17 +01:00
Juergen Hoeller 2ec41af799 ReflectivePropertyAccessor should not consider bridge methods
Issue: SPR-9995
Backport-Issue: SPR-9994
2012-12-12 12:34:36 +01:00
Juergen Hoeller eb24365556 ResourceDatabasePopulator explicitly closes its LineNumberReader
Issue: SPR-9960
Backport-Issue: SPR-9912
2012-12-12 12:15:20 +01:00
Juergen Hoeller 3a31efaf31 Further backports from 3.2 GA 2012-12-12 03:32:18 +01:00
Juergen Hoeller 751c429897 Polishing 2012-12-12 03:31:18 +01:00
Juergen Hoeller f19bc572da AbstractCachingViewResolver uses a cache limit of 1024 by default, avoiding overflow for redirect URLs
Issue: SPR-10065
2012-12-12 03:13:30 +01:00
Juergen Hoeller 81348516ff Polishing 2012-12-11 20:41:31 +01:00
Juergen Hoeller a00e00bd47 Fixed CGLIB proxy class leaks through further equals/hashCode implementations in Spring AOP pointcuts
Issue: SPR-8008
2012-12-11 20:37:42 +01:00
Juergen Hoeller b0fce78abf Fixed HierarchicalUriComponents equals implementation
Issue: SPR-10088
2012-12-11 15:50:57 +01:00
Juergen Hoeller 90fbeb1643 Removed coverage of deprecated java.util.Timer support
Issue: SPR-10050
2012-12-05 19:19:42 +01:00
Juergen Hoeller 7384c3d82f ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK classes via ASM
Issue: SPR-10058
2012-12-05 19:12:38 +01:00
Juergen Hoeller b016c8db91 Upgraded Hibernate 3 dependency to Hibernate 3.3.2.GA (and SLF4J 1.6.1) 2012-12-04 16:42:55 +01:00
Juergen Hoeller ceb8ce0a76 Polishing 2012-12-04 15:35:59 +01:00
Juergen Hoeller d34c392c53 Transaction timeouts for JPA translate to "javax.persistence.query.timeout" only (for EclipseLink compatibility)
Issue: SPR-10068
2012-12-04 15:34:28 +01:00
Juergen Hoeller 2b4e25b6f3 Fixed typos in javadoc 2012-11-29 23:11:04 +01:00
Juergen Hoeller 9929810610 Removed accidentally added DestructionAwareAttributeHolder class 2012-11-29 23:09:24 +01:00
Juergen Hoeller 4058f693e5 DefaultMessageListenerContainer allows for concurrent subscription consumers on WebLogic/ActiveMQ
Issue: SPR-10037
2012-11-29 23:08:46 +01:00
Juergen Hoeller 959ab7a5db Preparations for 3.1.4 2012-11-25 23:41:57 +01:00
Juergen Hoeller bed2134736 CachedIntrospectionResults uses full WeakReference for any non-safe ClassLoader arrangement
Previously, CachedIntrospectionResults had three modes of caching, with the intermediate mode relying on WeakReferences in the JDK PropertyDescriptor implementation. Since the JDK is actually using SoftReferences there these days, losing information in case of a GC run with tough memory constraints, we want to allow for hard references in PropertyDescriptor objects and therefore use a full WeakReference for the CachedIntrospectionResults object itself.

Issue: SPR-10028
2012-11-25 23:36:59 +01:00
Juergen Hoeller dd68fecbf2 Avoid wide locks in order to remove deadlock potential in case of multi-threaded singleton creation/destruction
Issue: SPR-10020
Issue: SPR-8471
2012-11-25 23:33:05 +01:00
Juergen Hoeller 667438ddb0 Polishing 2012-11-25 22:29:05 +01:00
Juergen Hoeller f4532ad704 Avoid a hard dependency on Sun's CachedRowSetImpl class 2012-11-25 22:21:01 +01:00
Juergen Hoeller 0deacb9fa1 Oracle OC4J support will be deprecated in favor of Oracle WebLogic as of Spring 3.2 2012-11-25 21:04:06 +01:00
Chris Beams 0ee12563b0 Overhaul non-void JavaBean write method support
This change revisits the implementation of ExtendedBeanInfo, simplifying
the overall approach while also ensuring that ExtendedBeanInfo is fully
isolated from the BeanInfo instance it wraps. This includes any existing
PropertyDescriptors in the wrapped BeanInfo - along with being copied
locally into ExtendedBeanInfo, each property descriptor is now also
wrapped with our own new "simple" PropertyDescriptor variants that
bypass the soft/weak reference management that goes on in both
java.beans.PropertyDescriptor and java.beans.IndexedPropertyDescriptor,
maintaining hard references to methods and bean classes instead. This
ensures that changes we make to property descriptors, e.g. adding write
methods, do not cause subtle conflicts during garbage collection (as was
reported and reproduced in SPR-9702).

Eliminating soft/weak reference management means that we must take extra
care to ensure that we do not cause ClassLoader leaks by maintaining
hard references to methods, and therefore transitively to the
ClassLoader in which the bean class was loaded. The forthcoming
SPR-10028 addresses this aspect.

See the updated ExtendedBeanInfo Javadoc for further details.

Issue: SPR-8079, SPR-8175, SPR-8347, SPR-8432, SPR-8491, SPR-8522,
       SPR-8806, SPR-8931, SPR-8937, SPR-8949, SPR-9007, SPR-9059,
       SPR-9414, SPR-9453, SPR-9542, SPR-9584, SPR-9677, SPR-9702,
       SPR-9723, SPR-9943, SPR-9978, SPR-10028, SPR-10029
Backport-Commit: 4a8be69099
Conflicts:
	spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfoFactory.java
2012-11-25 13:08:20 +01:00
Spring Buildmaster e0b29b708c Increment version to 3.1.4.BUILD-SNAPSHOT 2012-10-31 18:14:06 +01:00
170 changed files with 3184 additions and 1736 deletions
@@ -3,6 +3,43 @@ SPRING FRAMEWORK CHANGELOG
http://www.springsource.org
Changes in version 3.1.4 (2013-01-23)
-------------------------------------
* overhauled non-void JavaBean write method support (SPR-10029)
* SpEL support for static finals on interfaces (SPR-10125)
* BridgeMethodResolver properly handles bridge methods in interfaces (SPR-9330)
* LocalVariableTableParameterNameDiscoverer works for bridge methods as well (SPR-9429)
* CachedIntrospectionResults uses full WeakReference for any non-safe ClassLoader arrangement (SPR-10028)
* CachedIntrospectionResults.clearClassLoader(null) removes cached classes for the system class loader (SPR-9189)
* DefaultListableBeanFactory avoids wide/interleaved metadata locks to avoid deadlock potential (SPR-10020)
* fixed CGLIB proxy class leaks through further equals/hashCode implementations in Spring AOP pointcuts (SPR-8008)
* ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK classes via ASM (SPR-10058)
* MessageSourceResourceBundle overrides JDK 1.6 containsKey method, avoiding NPE in getKeys (SPR-10136)
* SpringBeanAutowiringInterceptor eagerly releases BeanFactory if post-construction fails (SPR-10013)
* added "exposeAccessContext" flag JndiRmiClientInterceptor/ProxyFactoryBean (for WebLogic; SPR-9428)
* MBeanExporter does not log warnings for manually unregistered MBeans (SPR-9451)
* AbstractCacheManager accepts no caches defined, allowing for EHCache default cache setup (SPR-7955)
* reintroduced "mode" and "proxy-target-class" attributes in spring-task-3.1.xsd (SPR-10177)
* improved defensiveness of JDBC 3.0 ParameterMetaData calls for parameter type determination (SPR-10084)
* JpaTransactionManager etc finds default EntityManagerFactory in parent context as well (SPR-10160)
* tx timeouts for JPA translate to "javax.persistence.query.timeout" only (for EclipseLink compatibility; SPR-10068)
* DefaultMessageListenerContainer allows for concurrent subscription consumers on WebLogic/ActiveMQ (SPR-10037)
* DefaultMessageListenerContainer clears resources of paused tasks when shutting down after stop (SPR-10092)
* JmsTemplate uses configured receiveTimeout if shorter than remaining transaction timeout (SPR-10109)
* added MappingJackson2MessageConverter for JMS (SPR-10099)
* ResourceDatabasePopulator explicitly closes its LineNumberReader (SPR-9912)
* MimeMessageHelper encodes attachment filename if not ASCII compliant (SPR-9258)
* FreeMarkerConfigurationFactory properly supports TemplateLoaders when recreating Configurations (SPR-9389)
* SpringContextResourceAdapter implements equals/hashCode according to the JCA 1.5 contract (SPR-9162)
* ContextLoader properly detects pre-refreshed WebApplicationContext (SPR-9996)
* AbstractCachingViewResolver uses a cache limit of 1024 by default, avoiding overflow for redirect URLs (SPR-10065)
* fixed HierarchicalUriComponents equals implementation (SPR-10088)
* MockHttpServletRequest's getParameter(Values) returns null for null parameter name (SPR-10192)
* MockHttpServletResponse's getHeaderNames declares Collection instead of Set for Servlet 3.0 compatibility (SPR-9885)
* ResourcePropertySource supports JDK 5-style Properties XML (SPR-9896)
Changes in version 3.1.3 (2012-10-31)
-------------------------------------
+2 -2
View File
@@ -1,5 +1,5 @@
SPRING FRAMEWORK 3.1.3 (October 2012)
---------------------------------------
SPRING FRAMEWORK 3.1.4 (January 2013)
-------------------------------------
http://www.springsource.org
1. INTRODUCTION
+5 -5
View File
@@ -1,4 +1,4 @@
version=3.1.3
version=3.1.5
natural.name=spring-framework
project.name=Spring Framework
@@ -17,16 +17,16 @@ spring.osgi.range="${spring.osgi.range.nq}"
aj.osgi.range="[1.6.8, 2.0.0)"
## For GA releases
release.type=release
build.stamp=RELEASE
#release.type=release
#build.stamp=RELEASE
## For milestone releases
#release.type=milestone
#build.stamp=M1
## For trunk development / ci builds
#release.type=integration
#build.stamp=BUILD-SNAPSHOT
release.type=integration
build.stamp=BUILD-SNAPSHOT
#bundlor
fail.on.warnings=false
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@@ -681,6 +681,23 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
public boolean matches(Method method, Class targetClass) {
return !this.adviceMethod.equals(method);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AdviceExcludingMethodMatcher)) {
return false;
}
AdviceExcludingMethodMatcher otherMm = (AdviceExcludingMethodMatcher) other;
return this.adviceMethod.equals(otherMm.adviceMethod);
}
@Override
public int hashCode() {
return this.adviceMethod.hashCode();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -271,7 +271,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!this.targetSourcedBeans.contains(cacheKey)) {
if (!this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.contains(cacheKey) || this.nonAdvisedBeans.contains(cacheKey)) {
return null;
}
@@ -371,17 +371,18 @@ public abstract class AbstractAutoProxyCreator extends ProxyConfig
/**
* Return whether the given bean class represents an infrastructure class
* that should never be proxied.
* <p>Default implementation considers Advisors, Advices and
* AbstractAutoProxyCreators as infrastructure classes.
* <p>The default implementation considers Advices, Advisors and
* AopInfrastructureBeans as infrastructure classes.
* @param beanClass the class of the bean
* @return whether the bean represents an infrastructure class
* @see org.aopalliance.aop.Advice
* @see org.springframework.aop.Advisor
* @see org.aopalliance.intercept.MethodInterceptor
* @see org.springframework.aop.framework.AopInfrastructureBean
* @see #shouldSkip
*/
protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advisor.class.isAssignableFrom(beanClass) ||
Advice.class.isAssignableFrom(beanClass) ||
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
if (retVal && logger.isTraceEnabled()) {
logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.
@@ -56,4 +56,21 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
return (specificMethod != method && specificMethod.isAnnotationPresent(this.annotationType));
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AnnotationMethodMatcher)) {
return false;
}
AnnotationMethodMatcher otherMm = (AnnotationMethodMatcher) other;
return this.annotationType.equals(otherMm.annotationType);
}
@Override
public int hashCode() {
return this.annotationType.hashCode();
}
}
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-asm</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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 java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
@@ -32,7 +33,6 @@ import java.util.WeakHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -100,9 +100,6 @@ public class CachedIntrospectionResults {
* @param classLoader the ClassLoader to clear the cache for
*/
public static void clearClassLoader(ClassLoader classLoader) {
if (classLoader == null) {
return;
}
synchronized (classCache) {
for (Iterator<Class> it = classCache.keySet().iterator(); it.hasNext();) {
Class beanClass = it.next();
@@ -140,20 +137,16 @@ public class CachedIntrospectionResults {
results = (CachedIntrospectionResults) value;
}
if (results == null) {
// On JDK 1.5 and higher, it is almost always safe to cache the bean class...
// The sole exception is a custom BeanInfo class being provided in a non-safe ClassLoader.
boolean fullyCacheable =
ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
isClassLoaderAccepted(beanClass.getClassLoader());
if (fullyCacheable || !ClassUtils.isPresent(beanClass.getName() + "BeanInfo", beanClass.getClassLoader())) {
results = new CachedIntrospectionResults(beanClass, fullyCacheable);
if (ClassUtils.isCacheSafe(beanClass, CachedIntrospectionResults.class.getClassLoader()) ||
isClassLoaderAccepted(beanClass.getClassLoader())) {
results = new CachedIntrospectionResults(beanClass);
classCache.put(beanClass, results);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Not strongly caching class [" + beanClass.getName() + "] because it is not cache-safe");
}
results = new CachedIntrospectionResults(beanClass, true);
results = new CachedIntrospectionResults(beanClass);
classCache.put(beanClass, new WeakReference<CachedIntrospectionResults>(results));
}
}
@@ -187,12 +180,12 @@ public class CachedIntrospectionResults {
* @param parent the parent ClassLoader to check for
*/
private static boolean isUnderneathClassLoader(ClassLoader candidate, ClassLoader parent) {
if (candidate == null) {
return false;
}
if (candidate == parent) {
return true;
}
if (candidate == null) {
return false;
}
ClassLoader classLoaderToCheck = candidate;
while (classLoaderToCheck != null) {
classLoaderToCheck = classLoaderToCheck.getParent();
@@ -216,12 +209,20 @@ public class CachedIntrospectionResults {
* @param beanClass the bean class to analyze
* @throws BeansException in case of introspection failure
*/
private CachedIntrospectionResults(Class beanClass, boolean cacheFullMetadata) throws BeansException {
private CachedIntrospectionResults(Class beanClass) throws BeansException {
try {
if (logger.isTraceEnabled()) {
logger.trace("Getting BeanInfo for class [" + beanClass.getName() + "]");
}
this.beanInfo = new ExtendedBeanInfo(Introspector.getBeanInfo(beanClass));
BeanInfo originalBeanInfo = Introspector.getBeanInfo(beanClass);
BeanInfo extendedBeanInfo = null;
for (Method method : beanClass.getMethods()) {
if (ExtendedBeanInfo.isCandidateWriteMethod(method)) {
extendedBeanInfo = new ExtendedBeanInfo(originalBeanInfo);
break;
}
}
this.beanInfo = extendedBeanInfo != null ? extendedBeanInfo : originalBeanInfo;
// Immediately remove class from Introspector cache, to allow for proper
// garbage collection on class loader shutdown - we cache it here anyway,
@@ -252,9 +253,7 @@ public class CachedIntrospectionResults {
(pd.getPropertyEditorClass() != null ?
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
}
if (cacheFullMetadata) {
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
}
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptorCache.put(pd.getName(), pd);
}
}
@@ -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,9 +16,8 @@
package org.springframework.beans;
import static java.lang.String.format;
import java.awt.Image;
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.EventSetDescriptor;
@@ -27,310 +26,202 @@ import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import static org.springframework.beans.PropertyDescriptorUtils.*;
/**
* Decorates a standard {@link BeanInfo} object (likely created created by
* {@link Introspector#getBeanInfo(Class)}) by including non-void returning setter
* methods in the collection of {@link #getPropertyDescriptors() property descriptors}.
* Both regular and
* Decorator for a standard {@link BeanInfo} object, e.g. as created by
* {@link Introspector#getBeanInfo(Class)}, designed to discover and register static
* and/or non-void returning setter methods. For example:
* <pre>{@code
* public class Bean {
* private Foo foo;
*
* public Foo getFoo() {
* return this.foo;
* }
*
* public Bean setFoo(Foo foo) {
* this.foo = foo;
* return this;
* }
* }</pre>
* The standard JavaBeans {@code Introspector} will discover the {@code getFoo} read
* method, but will bypass the {@code #setFoo(Foo)} write method, because its non-void
* returning signature does not comply with the JavaBeans specification.
* {@code ExtendedBeanInfo}, on the other hand, will recognize and include it. This is
* designed to allow APIs with "builder" or method-chaining style setter signatures to be
* used within Spring {@code <beans>} XML. {@link #getPropertyDescriptors()} returns all
* existing property descriptors from the wrapped {@code BeanInfo} as well any added for
* non-void returning setters. Both standard ("non-indexed") and
* <a href="http://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html">
* indexed properties</a> are fully supported.
*
* <p>The wrapped {@code BeanInfo} object is not modified in any way.
*
* @author Chris Beams
* @since 3.1
* @see #ExtendedBeanInfo(BeanInfo)
* @see CachedIntrospectionResults
*/
class ExtendedBeanInfo implements BeanInfo {
private final Log logger = LogFactory.getLog(getClass());
private final BeanInfo delegate;
private final SortedSet<PropertyDescriptor> propertyDescriptors =
new TreeSet<PropertyDescriptor>(new PropertyDescriptorComparator());
private final Set<PropertyDescriptor> propertyDescriptors =
new TreeSet<PropertyDescriptor>(new PropertyDescriptorComparator());
/**
* Wrap the given delegate {@link BeanInfo} instance and find any non-void returning
* setter methods, creating and adding a {@link PropertyDescriptor} for each.
*
* <p>Note that the wrapped {@code BeanInfo} is modified by this process.
*
* Wrap the given {@link BeanInfo} instance; copy all its existing property descriptors
* locally, wrapping each in a custom {@link SimpleIndexedPropertyDescriptor indexed} or
* {@link SimpleNonIndexedPropertyDescriptor non-indexed} {@code PropertyDescriptor}
* variant that bypasses default JDK weak/soft reference management; then search
* through its method descriptors to find any non-void returning write methods and
* update or create the corresponding {@link PropertyDescriptor} for each one found.
* @param delegate the wrapped {@code BeanInfo}, which is never modified
* @throws IntrospectionException if any problems occur creating and adding new
* property descriptors
* @see #getPropertyDescriptors()
* @throws IntrospectionException if any problems occur creating and adding new {@code PropertyDescriptors}
*/
public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException {
this.delegate = delegate;
ALL_METHODS:
for (MethodDescriptor md : delegate.getMethodDescriptors()) {
Method method = resolveMethod(md.getMethod());
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
new SimpleNonIndexedPropertyDescriptor(pd));
}
// bypass non-getter java.lang.Class methods for efficiency
if (ReflectionUtils.isObjectMethod(method) && !method.getName().startsWith("get")) {
continue ALL_METHODS;
}
// is the method a NON-INDEXED setter? ignore return type in order to capture non-void signatures
if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
String propertyName = propertyNameFor(method);
if(propertyName.length() == 0) {
continue ALL_METHODS;
}
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
Method readMethod = readMethodFor(pd);
Method writeMethod = writeMethodFor(pd);
// has the setter already been found by the wrapped BeanInfo?
if (writeMethod != null
&& writeMethod.getName().equals(method.getName())) {
// yes -> copy it, including corresponding getter method (if any -- may be null)
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod);
continue ALL_METHODS;
}
// has a getter corresponding to this setter already been found by the wrapped BeanInfo?
if (readMethod != null
&& readMethod.getName().equals(getterMethodNameFor(propertyName))
&& readMethod.getReturnType().equals(method.getParameterTypes()[0])) {
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, method);
continue ALL_METHODS;
}
}
// the setter method was not found by the wrapped BeanInfo -> add a new PropertyDescriptor for it
// no corresponding getter was detected, so the 'read method' parameter is null.
this.addOrUpdatePropertyDescriptor(null, propertyName, null, method);
continue ALL_METHODS;
}
// is the method an INDEXED setter? ignore return type in order to capture non-void signatures
if (method.getName().startsWith("set") && method.getParameterTypes().length == 2 && method.getParameterTypes()[0].equals(int.class)) {
String propertyName = propertyNameFor(method);
if(propertyName.length() == 0) {
continue ALL_METHODS;
}
DELEGATE_PD:
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
if (!(pd instanceof IndexedPropertyDescriptor)) {
continue DELEGATE_PD;
}
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
Method readMethod = readMethodFor(ipd);
Method writeMethod = writeMethodFor(ipd);
Method indexedReadMethod = indexedReadMethodFor(ipd);
Method indexedWriteMethod = indexedWriteMethodFor(ipd);
// has the setter already been found by the wrapped BeanInfo?
if (!(indexedWriteMethod != null
&& indexedWriteMethod.getName().equals(method.getName()))) {
indexedWriteMethod = method;
}
// yes -> copy it, including corresponding getter method (if any -- may be null)
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
continue ALL_METHODS;
}
// the INDEXED setter method was not found by the wrapped BeanInfo -> add a new PropertyDescriptor
// for it. no corresponding INDEXED getter was detected, so the 'indexed read method' parameter is null.
this.addOrUpdatePropertyDescriptor(null, propertyName, null, null, null, method);
continue ALL_METHODS;
}
// the method is not a setter, but is it a getter?
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
// have we already copied this read method to a property descriptor locally?
String propertyName = pd.getName();
Method readMethod = readMethodFor(pd);
Method mostSpecificReadMethod = ClassUtils.getMostSpecificMethod(readMethod, method.getDeclaringClass());
for (PropertyDescriptor existingPD : this.propertyDescriptors) {
if (method.equals(mostSpecificReadMethod)
&& existingPD.getName().equals(propertyName)) {
if (readMethodFor(existingPD) == null) {
// no -> add it now
this.addOrUpdatePropertyDescriptor(pd, propertyName, method, writeMethodFor(pd));
}
// yes -> do not add a duplicate
continue ALL_METHODS;
}
}
if (method.equals(mostSpecificReadMethod)
|| (pd instanceof IndexedPropertyDescriptor && method.equals(indexedReadMethodFor((IndexedPropertyDescriptor) pd)))) {
// yes -> copy it, including corresponding setter method (if any -- may be null)
if (pd instanceof IndexedPropertyDescriptor) {
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethodFor(pd), indexedReadMethodFor((IndexedPropertyDescriptor)pd), indexedWriteMethodFor((IndexedPropertyDescriptor)pd));
} else {
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethodFor(pd));
}
continue ALL_METHODS;
}
}
for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) {
handleCandidateWriteMethod(method);
}
}
private static Method resolveMethod(Method method) {
return BridgeMethodResolver.findBridgedMethod(method);
}
private static Method readMethodFor(PropertyDescriptor pd) {
return resolveMethod(pd.getReadMethod());
}
private static Method writeMethodFor(PropertyDescriptor pd) {
return resolveMethod(pd.getWriteMethod());
}
private static Method indexedReadMethodFor(IndexedPropertyDescriptor ipd) {
return resolveMethod(ipd.getIndexedReadMethod());
}
private static Method indexedWriteMethodFor(IndexedPropertyDescriptor ipd) {
return resolveMethod(ipd.getIndexedWriteMethod());
}
private void addOrUpdatePropertyDescriptor(PropertyDescriptor pd, String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException {
addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, null, null);
}
private void addOrUpdatePropertyDescriptor(PropertyDescriptor pd, String propertyName, Method readMethod, Method writeMethod, Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
Assert.notNull(propertyName, "propertyName may not be null");
propertyName = pd == null ? propertyName : pd.getName();
for (PropertyDescriptor existingPD : this.propertyDescriptors) {
if (existingPD.getName().equals(propertyName)) {
// is there already a descriptor that captures this read method or its corresponding write method?
if (readMethodFor(existingPD) != null) {
if (readMethod != null && readMethodFor(existingPD).getReturnType() != readMethod.getReturnType()
|| writeMethod != null && readMethodFor(existingPD).getReturnType() != writeMethod.getParameterTypes()[0]) {
// no -> add a new descriptor for it below
break;
}
}
// update the existing descriptor's read method
if (readMethod != null) {
try {
existingPD.setReadMethod(readMethod);
} catch (IntrospectionException ex) {
// there is a conflicting setter method present -> null it out and try again
existingPD.setWriteMethod(null);
existingPD.setReadMethod(readMethod);
}
}
// is there already a descriptor that captures this write method or its corresponding read method?
if (writeMethodFor(existingPD) != null) {
if (readMethod != null && writeMethodFor(existingPD).getParameterTypes()[0] != readMethod.getReturnType()
|| writeMethod != null && writeMethodFor(existingPD).getParameterTypes()[0] != writeMethod.getParameterTypes()[0]) {
// no -> add a new descriptor for it below
break;
}
}
// update the existing descriptor's write method
if (writeMethod != null
&& !(existingPD instanceof IndexedPropertyDescriptor &&
!writeMethod.getParameterTypes()[0].isArray())) {
existingPD.setWriteMethod(writeMethod);
}
// is this descriptor indexed?
if (existingPD instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor existingIPD = (IndexedPropertyDescriptor) existingPD;
// is there already a descriptor that captures this indexed read method or its corresponding indexed write method?
if (indexedReadMethodFor(existingIPD) != null) {
if (indexedReadMethod != null && indexedReadMethodFor(existingIPD).getReturnType() != indexedReadMethod.getReturnType()
|| indexedWriteMethod != null && indexedReadMethodFor(existingIPD).getReturnType() != indexedWriteMethod.getParameterTypes()[1]) {
// no -> add a new descriptor for it below
break;
}
}
// update the existing descriptor's indexed read method
try {
if (indexedReadMethod != null) {
existingIPD.setIndexedReadMethod(indexedReadMethod);
}
} catch (IntrospectionException ex) {
// there is a conflicting indexed setter method present -> null it out and try again
existingIPD.setIndexedWriteMethod(null);
existingIPD.setIndexedReadMethod(indexedReadMethod);
}
// is there already a descriptor that captures this indexed write method or its corresponding indexed read method?
if (indexedWriteMethodFor(existingIPD) != null) {
if (indexedReadMethod != null && indexedWriteMethodFor(existingIPD).getParameterTypes()[1] != indexedReadMethod.getReturnType()
|| indexedWriteMethod != null && indexedWriteMethodFor(existingIPD).getParameterTypes()[1] != indexedWriteMethod.getParameterTypes()[1]) {
// no -> add a new descriptor for it below
break;
}
}
// update the existing descriptor's indexed write method
if (indexedWriteMethod != null) {
existingIPD.setIndexedWriteMethod(indexedWriteMethod);
}
}
// the descriptor has been updated -> return immediately
return;
private List<Method> findCandidateWriteMethods(MethodDescriptor[] methodDescriptors) {
List<Method> matches = new ArrayList<Method>();
for (MethodDescriptor methodDescriptor : methodDescriptors) {
Method method = methodDescriptor.getMethod();
if (isCandidateWriteMethod(method)) {
matches.add(method);
}
}
// sort non-void returning write methods to guard against the ill effects of
// non-deterministic sorting of methods returned from Class#getDeclaredMethods
// under JDK 7. See http://bugs.sun.com/view_bug.do?bug_id=7023180
Collections.sort(matches, new Comparator<Method>() {
public int compare(Method m1, Method m2) {
return m2.toString().compareTo(m1.toString());
}
});
return matches;
}
// we haven't yet seen read or write methods for this property -> add a new descriptor
if (pd == null) {
try {
if (indexedReadMethod == null && indexedWriteMethod == null) {
pd = new PropertyDescriptor(propertyName, readMethod, writeMethod);
}
else {
pd = new IndexedPropertyDescriptor(propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
}
this.propertyDescriptors.add(pd);
} catch (IntrospectionException ex) {
logger.debug(format("Could not create new PropertyDescriptor for readMethod [%s] writeMethod [%s] " +
"indexedReadMethod [%s] indexedWriteMethod [%s] for property [%s]. Reason: %s",
readMethod, writeMethod, indexedReadMethod, indexedWriteMethod, propertyName, ex.getMessage()));
// suppress exception and attempt to continue
public static boolean isCandidateWriteMethod(Method method) {
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
int nParams = parameterTypes.length;
if (methodName.length() > 3 && methodName.startsWith("set") &&
Modifier.isPublic(method.getModifiers()) &&
(
!void.class.isAssignableFrom(method.getReturnType()) ||
Modifier.isStatic(method.getModifiers())
) &&
(nParams == 1 || (nParams == 2 && parameterTypes[0].equals(int.class)))) {
return true;
}
return false;
}
private void handleCandidateWriteMethod(Method method) throws IntrospectionException {
int nParams = method.getParameterTypes().length;
String propertyName = propertyNameFor(method);
Class<?> propertyType = method.getParameterTypes()[nParams-1];
PropertyDescriptor existingPD = findExistingPropertyDescriptor(propertyName, propertyType);
if (nParams == 1) {
if (existingPD == null) {
this.propertyDescriptors.add(
new SimpleNonIndexedPropertyDescriptor(propertyName, null, method));
}
else {
existingPD.setWriteMethod(method);
}
}
else if (nParams == 2) {
if (existingPD == null) {
this.propertyDescriptors.add(
new SimpleIndexedPropertyDescriptor(
propertyName, null, null, null, method));
}
else if (existingPD instanceof IndexedPropertyDescriptor) {
((IndexedPropertyDescriptor)existingPD).setIndexedWriteMethod(method);
}
else {
this.propertyDescriptors.remove(existingPD);
this.propertyDescriptors.add(
new SimpleIndexedPropertyDescriptor(
propertyName, existingPD.getReadMethod(),
existingPD.getWriteMethod(), null, method));
}
}
else {
pd.setWriteMethod(null);
pd.setReadMethod(readMethod);
try {
pd.setWriteMethod(writeMethod);
} catch (IntrospectionException ex) {
logger.debug(format("Could not add write method [%s] for property [%s]. Reason: %s",
writeMethod, propertyName, ex.getMessage()));
// fall through -> add property descriptor as best we can
}
if (pd instanceof IndexedPropertyDescriptor) {
((IndexedPropertyDescriptor)pd).setIndexedWriteMethod(null);
((IndexedPropertyDescriptor)pd).setIndexedReadMethod(indexedReadMethod);
try {
((IndexedPropertyDescriptor)pd).setIndexedWriteMethod(indexedWriteMethod);
} catch (IntrospectionException ex) {
logger.debug(format("Could not add indexed write method [%s] for property [%s]. Reason: %s",
indexedWriteMethod, propertyName, ex.getMessage()));
// fall through -> add property descriptor as best we can
}
}
this.propertyDescriptors.add(pd);
throw new IllegalArgumentException(
"write method must have exactly 1 or 2 parameters: " + method);
}
}
private String propertyNameFor(Method method) {
return Introspector.decapitalize(method.getName().substring(3,method.getName().length()));
private PropertyDescriptor findExistingPropertyDescriptor(
String propertyName, Class<?> propertyType) {
for (PropertyDescriptor pd : this.propertyDescriptors) {
final Class<?> candidateType;
final String candidateName = pd.getName();
if (pd instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
candidateType = ipd.getIndexedPropertyType();
if (candidateName.equals(propertyName) &&
(candidateType.equals(propertyType) ||
candidateType.equals(propertyType.getComponentType()))) {
return pd;
}
}
else {
candidateType = pd.getPropertyType();
if (candidateName.equals(propertyName) &&
(candidateType.equals(propertyType) ||
propertyType.equals(candidateType.getComponentType()))) {
return pd;
}
}
}
return null;
}
private Object getterMethodNameFor(String name) {
return "get" + StringUtils.capitalize(name);
private String propertyNameFor(Method method) {
return Introspector.decapitalize(
method.getName().substring(3, method.getName().length()));
}
/**
* Return the set of {@link PropertyDescriptor}s from the wrapped {@link BeanInfo}
* object as well as {@code PropertyDescriptor}s for each non-void returning setter
* method found during construction.
* @see #ExtendedBeanInfo(BeanInfo)
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return this.propertyDescriptors.toArray(
new PropertyDescriptor[this.propertyDescriptors.size()]);
}
public BeanInfo[] getAdditionalBeanInfo() {
@@ -353,45 +244,431 @@ class ExtendedBeanInfo implements BeanInfo {
return delegate.getEventSetDescriptors();
}
public Image getIcon(int arg0) {
return delegate.getIcon(arg0);
public Image getIcon(int iconKind) {
return delegate.getIcon(iconKind);
}
public MethodDescriptor[] getMethodDescriptors() {
return delegate.getMethodDescriptors();
}
}
/**
* Return the set of {@link PropertyDescriptor}s from the wrapped {@link BeanInfo}
* object as well as {@code PropertyDescriptor}s for each non-void returning setter
* method found during construction.
* @see #ExtendedBeanInfo(BeanInfo)
*/
public PropertyDescriptor[] getPropertyDescriptors() {
return this.propertyDescriptors.toArray(new PropertyDescriptor[this.propertyDescriptors.size()]);
class SimpleNonIndexedPropertyDescriptor extends PropertyDescriptor {
private Method readMethod;
private Method writeMethod;
private Class<?> propertyType;
private Class<?> propertyEditorClass;
public SimpleNonIndexedPropertyDescriptor(PropertyDescriptor original)
throws IntrospectionException {
this(original.getName(), original.getReadMethod(), original.getWriteMethod());
copyNonMethodProperties(original, this);
}
public SimpleNonIndexedPropertyDescriptor(String propertyName,
Method readMethod, Method writeMethod) throws IntrospectionException {
super(propertyName, null, null);
this.setReadMethod(readMethod);
this.setWriteMethod(writeMethod);
this.propertyType = findPropertyType(readMethod, writeMethod);
}
/**
* Sorts PropertyDescriptor instances alpha-numerically to emulate the behavior of
* {@link java.beans.BeanInfo#getPropertyDescriptors()}.
*
* @see ExtendedBeanInfo#propertyDescriptors
*/
static class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
String left = desc1.getName();
String right = desc2.getName();
for (int i = 0; i < left.length(); i++) {
if (right.length() == i) {
return 1;
}
int result = left.getBytes()[i] - right.getBytes()[i];
if (result != 0) {
return result;
}
@Override
public Method getReadMethod() {
return this.readMethod;
}
@Override
public void setReadMethod(Method readMethod) {
this.readMethod = readMethod;
}
@Override
public Method getWriteMethod() {
return this.writeMethod;
}
@Override
public void setWriteMethod(Method writeMethod) {
this.writeMethod = writeMethod;
}
@Override
public Class<?> getPropertyType() {
if (this.propertyType == null) {
try {
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
} catch (IntrospectionException ex) {
// ignore, as does PropertyDescriptor#getPropertyType
}
return left.length() - right.length();
}
return this.propertyType;
}
}
@Override
public Class<?> getPropertyEditorClass() {
return this.propertyEditorClass;
}
@Override
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
this.propertyEditorClass = propertyEditorClass;
}
@Override
public boolean equals(Object obj) {
return PropertyDescriptorUtils.equals(this, obj);
}
@Override
public String toString() {
return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]",
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
this.readMethod, this.writeMethod);
}
}
class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {
private Method readMethod;
private Method writeMethod;
private Class<?> propertyType;
private Class<?> propertyEditorClass;
private Method indexedReadMethod;
private Method indexedWriteMethod;
private Class<?> indexedPropertyType;
public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original)
throws IntrospectionException {
this(original.getName(), original.getReadMethod(), original.getWriteMethod(),
original.getIndexedReadMethod(), original.getIndexedWriteMethod());
copyNonMethodProperties(original, this);
}
public SimpleIndexedPropertyDescriptor(String propertyName,
Method readMethod, Method writeMethod,
Method indexedReadMethod, Method indexedWriteMethod)
throws IntrospectionException {
super(propertyName, null, null, null, null);
this.setReadMethod(readMethod);
this.setWriteMethod(writeMethod);
this.propertyType = findPropertyType(readMethod, writeMethod);
this.setIndexedReadMethod(indexedReadMethod);
this.setIndexedWriteMethod(indexedWriteMethod);
this.indexedPropertyType = findIndexedPropertyType(
this.getName(), this.propertyType, indexedReadMethod, indexedWriteMethod);
}
@Override
public Method getReadMethod() {
return this.readMethod;
}
@Override
public void setReadMethod(Method readMethod) {
this.readMethod = readMethod;
}
@Override
public Method getWriteMethod() {
return this.writeMethod;
}
@Override
public void setWriteMethod(Method writeMethod) {
this.writeMethod = writeMethod;
}
@Override
public Class<?> getPropertyType() {
if (this.propertyType == null) {
try {
this.propertyType = findPropertyType(this.readMethod, this.writeMethod);
} catch (IntrospectionException ex) {
// ignore, as does IndexedPropertyDescriptor#getPropertyType
}
}
return this.propertyType;
}
@Override
public Method getIndexedReadMethod() {
return this.indexedReadMethod;
}
@Override
public void setIndexedReadMethod(Method indexedReadMethod) throws IntrospectionException {
this.indexedReadMethod = indexedReadMethod;
}
@Override
public Method getIndexedWriteMethod() {
return this.indexedWriteMethod;
}
@Override
public void setIndexedWriteMethod(Method indexedWriteMethod) throws IntrospectionException {
this.indexedWriteMethod = indexedWriteMethod;
}
@Override
public Class<?> getIndexedPropertyType() {
if (this.indexedPropertyType == null) {
try {
this.indexedPropertyType = findIndexedPropertyType(
this.getName(), this.getPropertyType(),
this.indexedReadMethod, this.indexedWriteMethod);
} catch (IntrospectionException ex) {
// ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
}
}
return this.indexedPropertyType;
}
@Override
public Class<?> getPropertyEditorClass() {
return this.propertyEditorClass;
}
@Override
public void setPropertyEditorClass(Class<?> propertyEditorClass) {
this.propertyEditorClass = propertyEditorClass;
}
/*
* @see java.beans.IndexedPropertyDescriptor#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof IndexedPropertyDescriptor) {
IndexedPropertyDescriptor other = (IndexedPropertyDescriptor) obj;
if (!compareMethods(getIndexedReadMethod(), other.getIndexedReadMethod())) {
return false;
}
if (!compareMethods(getIndexedWriteMethod(), other.getIndexedWriteMethod())) {
return false;
}
if (getIndexedPropertyType() != other.getIndexedPropertyType()) {
return false;
}
return PropertyDescriptorUtils.equals(this, obj);
}
return false;
}
@Override
public String toString() {
return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " +
"readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]",
this.getClass().getSimpleName(), this.getName(), this.getPropertyType(),
this.getIndexedPropertyType(), this.readMethod, this.writeMethod,
this.indexedReadMethod, this.indexedWriteMethod);
}
}
class PropertyDescriptorUtils {
/*
* see java.beans.FeatureDescriptor#FeatureDescriptor(FeatureDescriptor)
*/
public static void copyNonMethodProperties(PropertyDescriptor source, PropertyDescriptor target)
throws IntrospectionException {
target.setExpert(source.isExpert());
target.setHidden(source.isHidden());
target.setPreferred(source.isPreferred());
target.setName(source.getName());
target.setShortDescription(source.getShortDescription());
target.setDisplayName(source.getDisplayName());
// copy all attributes (emulating behavior of private FeatureDescriptor#addTable)
Enumeration<String> keys = source.attributeNames();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
target.setValue(key, source.getValue(key));
}
// see java.beans.PropertyDescriptor#PropertyDescriptor(PropertyDescriptor)
target.setPropertyEditorClass(source.getPropertyEditorClass());
target.setBound(source.isBound());
target.setConstrained(source.isConstrained());
}
/*
* See PropertyDescriptor#findPropertyType
*/
public static Class<?> findPropertyType(Method readMethod, Method writeMethod)
throws IntrospectionException {
Class<?> propertyType = null;
if (readMethod != null) {
Class<?>[] params = readMethod.getParameterTypes();
if (params.length != 0) {
throw new IntrospectionException("bad read method arg count: " + readMethod);
}
propertyType = readMethod.getReturnType();
if (propertyType == Void.TYPE) {
throw new IntrospectionException("read method "
+ readMethod.getName() + " returns void");
}
}
if (writeMethod != null) {
Class<?> params[] = writeMethod.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException("bad write method arg count: " + writeMethod);
}
if (propertyType != null
&& !params[0].isAssignableFrom(propertyType)) {
throw new IntrospectionException("type mismatch between read and write methods");
}
propertyType = params[0];
}
return propertyType;
}
/*
* See IndexedPropertyDescriptor#findIndexedPropertyType
*/
public static Class<?> findIndexedPropertyType(String name, Class<?> propertyType,
Method indexedReadMethod, Method indexedWriteMethod)
throws IntrospectionException {
Class<?> indexedPropertyType = null;
if (indexedReadMethod != null) {
Class<?> params[] = indexedReadMethod.getParameterTypes();
if (params.length != 1) {
throw new IntrospectionException(
"bad indexed read method arg count");
}
if (params[0] != Integer.TYPE) {
throw new IntrospectionException(
"non int index to indexed read method");
}
indexedPropertyType = indexedReadMethod.getReturnType();
if (indexedPropertyType == Void.TYPE) {
throw new IntrospectionException(
"indexed read method returns void");
}
}
if (indexedWriteMethod != null) {
Class<?> params[] = indexedWriteMethod.getParameterTypes();
if (params.length != 2) {
throw new IntrospectionException(
"bad indexed write method arg count");
}
if (params[0] != Integer.TYPE) {
throw new IntrospectionException(
"non int index to indexed write method");
}
if (indexedPropertyType != null && indexedPropertyType != params[1]) {
throw new IntrospectionException(
"type mismatch between indexed read and indexed write methods: " + name);
}
indexedPropertyType = params[1];
}
if (propertyType != null
&& (!propertyType.isArray() ||
propertyType.getComponentType() != indexedPropertyType)) {
throw new IntrospectionException(
"type mismatch between indexed and non-indexed methods: " + name);
}
return indexedPropertyType;
}
/**
* Compare the given {@link PropertyDescriptor} against the given {@link Object} and
* return {@code true} if they are objects are equivalent, i.e. both are {@code
* PropertyDescriptor}s whose read method, write method, property types, property
* editor and flags are equivalent.
*
* @see PropertyDescriptor#equals(Object)
*/
public static boolean equals(PropertyDescriptor pd1, Object obj) {
if (pd1 == obj) {
return true;
}
if (obj != null && obj instanceof PropertyDescriptor) {
PropertyDescriptor pd2 = (PropertyDescriptor) obj;
if (!compareMethods(pd1.getReadMethod(), pd2.getReadMethod())) {
return false;
}
if (!compareMethods(pd1.getWriteMethod(), pd2.getWriteMethod())) {
return false;
}
if (pd1.getPropertyType() == pd2.getPropertyType()
&& pd1.getPropertyEditorClass() == pd2.getPropertyEditorClass()
&& pd1.isBound() == pd2.isBound()
&& pd1.isConstrained() == pd2.isConstrained()) {
return true;
}
}
return false;
}
/*
* see PropertyDescriptor#compareMethods
*/
public static boolean compareMethods(Method a, Method b) {
if ((a == null) != (b == null)) {
return false;
}
if (a != null && b != null) {
if (!a.equals(b)) {
return false;
}
}
return true;
}
}
/**
* Sorts PropertyDescriptor instances alpha-numerically to emulate the behavior of
* {@link java.beans.BeanInfo#getPropertyDescriptors()}.
*
* @see ExtendedBeanInfo#propertyDescriptors
*/
class PropertyDescriptorComparator implements Comparator<PropertyDescriptor> {
public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
String left = desc1.getName();
String right = desc2.getName();
for (int i = 0; i < left.length(); i++) {
if (right.length() == i) {
return 1;
}
int result = left.getBytes()[i] - right.getBytes()[i];
if (result != 0) {
return result;
}
}
return left.length() - right.length();
}
}
@@ -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.
@@ -16,7 +16,6 @@
package org.springframework.beans.factory.access;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanFactory;
/**
@@ -34,7 +33,7 @@ public interface BeanFactoryReference {
/**
* Return the {@link BeanFactory} instance held by this reference.
* @throws IllegalStateException if invoked after <code>release()</code> has been called
* @throws IllegalStateException if invoked after {@code release()} has been called
*/
BeanFactory getFactory();
@@ -42,18 +41,17 @@ public interface BeanFactoryReference {
* Indicate that the {@link BeanFactory} instance referred to by this object is not
* needed any longer by the client code which obtained the {@link BeanFactoryReference}.
* <p>Depending on the actual implementation of {@link BeanFactoryLocator}, and
* the actual type of <code>BeanFactory</code>, this may possibly not actually
* do anything; alternately in the case of a 'closeable' <code>BeanFactory</code>
* the actual type of {@code BeanFactory}, this may possibly not actually
* do anything; alternately in the case of a 'closeable' {@code BeanFactory}
* or derived class (such as {@link org.springframework.context.ApplicationContext})
* may 'close' it, or may 'close' it once no more references remain.
* <p>In an EJB usage scenario this would normally be called from
* <code>ejbRemove()</code> and <code>ejbPassivate()</code>.
* {@code ejbRemove()} and {@code ejbPassivate()}.
* <p>This is safe to call multiple times.
* @throws FatalBeanException if the <code>BeanFactory</code> cannot be released
* @see BeanFactoryLocator
* @see org.springframework.context.access.ContextBeanFactoryReference
* @see org.springframework.context.ConfigurableApplicationContext#close()
*/
void release() throws FatalBeanException;
void release();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -265,7 +265,7 @@ public class InitDestroyAnnotationBeanPostProcessor
}
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
synchronized(this.initMethods) {
synchronized (this.initMethods) {
for (Iterator<LifecycleElement> it = this.initMethods.iterator(); it.hasNext();) {
String methodIdentifier = it.next().getIdentifier();
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
@@ -276,7 +276,7 @@ public class InitDestroyAnnotationBeanPostProcessor
}
}
}
synchronized(this.destroyMethods) {
synchronized (this.destroyMethods) {
for (Iterator<LifecycleElement> it = this.destroyMethods.iterator(); it.hasNext();) {
String methodIdentifier = it.next().getIdentifier();
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
@@ -1,202 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.config;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A container object holding a map of attributes and optionally destruction callbacks. The callbacks will be invoked,
* if an attribute is being removed or if the holder is cleaned out.
*
* @author Micha Kiener
* @since 3.1
*/
public class DestructionAwareAttributeHolder implements Serializable {
/** The map containing the registered attributes. */
private final Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();
/**
* The optional map having any destruction callbacks registered using the
* name of the bean as the key.
*/
private Map<String, Runnable> registeredDestructionCallbacks;
/**
* Returns the map representation of the registered attributes directly. Be
* aware to synchronize any invocations to it on the map object itself to
* avoid concurrent modification exceptions.
*
* @return the attributes as a map representation
*/
public Map<String, Object> getAttributeMap() {
return attributes;
}
/**
* Returns the attribute having the specified name, if available,
* <code>null</code> otherwise.
*
* @param name
* the name of the attribute to be returned
* @return the attribute value or <code>null</code> if not available
*/
@SuppressWarnings("unchecked")
public Object getAttribute(String name) {
return attributes.get(name);
}
/**
* Puts the given object with the specified name as an attribute to the
* underlying map.
*
* @param name
* the name of the attribute
* @param value
* the value to be stored
* @return any previously object stored under the same name, if any,
* <code>null</code> otherwise
*/
@SuppressWarnings("unchecked")
public Object setAttribute(String name, Object value) {
return attributes.put(name, value);
}
/**
* Remove the object with the given <code>name</code> from the underlying
* scope.
* <p>
* Returns <code>null</code> if no object was found; otherwise returns the
* removed <code>Object</code>.
* <p>
* Note that an implementation should also remove a registered destruction
* callback for the specified object, if any. It does, however, <i>not</i>
* need to <i>execute</i> a registered destruction callback in this case,
* since the object will be destroyed by the caller (if appropriate).
* <p>
* <b>Note: This is an optional operation.</b> Implementations may throw
* {@link UnsupportedOperationException} if they do not support explicitly
* removing an object.
*
* @param name
* the name of the object to remove
* @return the removed object, or <code>null</code> if no object was present
* @see #registerDestructionCallback
*/
@SuppressWarnings("unchecked")
public Object removeAttribute(String name) {
Object value = attributes.remove(name);
// check for a destruction callback to be invoked
Runnable callback = getDestructionCallback(name, true);
if (callback != null) {
callback.run();
}
return value;
}
/**
* Clears the map by removing all registered attribute values and invokes
* every destruction callback registered.
*/
public void clear() {
synchronized (this) {
// step through the attribute map and invoke destruction callbacks,
// if any
if (registeredDestructionCallbacks != null) {
for (Runnable runnable : registeredDestructionCallbacks.values()) {
runnable.run();
}
registeredDestructionCallbacks.clear();
}
}
// clear out the registered attribute map
attributes.clear();
}
/**
* Register a callback to be executed on destruction of the specified object
* in the scope (or at destruction of the entire scope, if the scope does
* not destroy individual objects but rather only terminates in its
* entirety).
* <p>
* <b>Note: This is an optional operation.</b> This method will only be
* called for scoped beans with actual destruction configuration
* (DisposableBean, destroy-method, DestructionAwareBeanPostProcessor).
* Implementations should do their best to execute a given callback at the
* appropriate time. If such a callback is not supported by the underlying
* runtime environment at all, the callback <i>must be ignored and a
* corresponding warning should be logged</i>.
* <p>
* Note that 'destruction' refers to to automatic destruction of the object
* as part of the scope's own lifecycle, not to the individual scoped object
* having been explicitly removed by the application. If a scoped object
* gets removed via this facade's {@link #removeAttribute(String)} method,
* any registered destruction callback should be removed as well, assuming
* that the removed object will be reused or manually destroyed.
*
* @param name
* the name of the object to execute the destruction callback for
* @param callback
* the destruction callback to be executed. Note that the
* passed-in Runnable will never throw an exception, so it can
* safely be executed without an enclosing try-catch block.
* Furthermore, the Runnable will usually be serializable,
* provided that its target object is serializable as well.
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.support.AbstractBeanDefinition#getDestroyMethodName()
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor
*/
public void registerDestructionCallback(String name, Runnable callback) {
if (registeredDestructionCallbacks == null) {
registeredDestructionCallbacks = new ConcurrentHashMap<String, Runnable>();
}
registeredDestructionCallbacks.put(name, callback);
}
/**
* Returns the destruction callback, if any registered for the attribute
* with the given name or <code>null</code> if no such callback was
* registered.
*
* @param name
* the name of the registered callback requested
* @param remove
* <code>true</code>, if the callback should be removed after
* this call, <code>false</code>, if it stays
* @return the callback, if found, <code>null</code> otherwise
*/
public Runnable getDestructionCallback(String name, boolean remove) {
if (registeredDestructionCallbacks == null) {
return null;
}
if (remove) {
return registeredDestructionCallbacks.remove(name);
}
return registeredDestructionCallbacks.get(name);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@@ -101,7 +101,7 @@ public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean<Object
/**
* Set the name of the target bean.
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
* <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
* always will be (because if the target bean were a singleton, then said singleton
* bean could simply be injected straight into the dependent object, thus obviating
* the need for the extra level of indirection afforded by this factory approach).
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@@ -46,7 +46,7 @@ public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider> {
/**
* Set the name of the target bean.
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
* <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
* always will be (because if the target bean were a singleton, then said singleton
* bean could simply be injected straight into the dependent object, thus obviating
* the need for the extra level of indirection afforded by this factory approach).
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 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.
@@ -27,7 +27,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
@@ -36,8 +35,8 @@ import org.springframework.util.StringUtils;
/**
* A {@link FactoryBean} implementation that takes an interface which must have one or more
* methods with the signatures <code>MyType xxx()</code> or <code>MyType xxx(MyIdType id)</code>
* (typically, <code>MyService getService()</code> or <code>MyService getService(String id)</code>)
* methods with the signatures {@code MyType xxx()} or {@code MyType xxx(MyIdType id)}
* (typically, {@code MyService getService()} or {@code MyService getService(String id)})
* and creates a dynamic proxy which implements that interface, delegating to an
* underlying {@link org.springframework.beans.factory.BeanFactory}.
*
@@ -51,7 +50,7 @@ import org.springframework.util.StringUtils;
* setter or constructor injection of the target bean is preferable.</b>
*
* <p>On invocation of the no-arg factory method, or the single-arg factory
* method with a String id of <code>null</code> or empty String, if exactly
* method with a String id of {@code null} or empty String, if exactly
* <b>one</b> bean in the factory matches the return type of the factory
* method, that bean is returned, otherwise a
* {@link org.springframework.beans.factory.NoSuchBeanDefinitionException}
@@ -64,7 +63,7 @@ import org.springframework.util.StringUtils;
*
* <p>A factory method argument will usually be a String, but can also be an
* int or a custom enumeration type, for example, stringified via
* <code>toString</code>. The resulting String can be used as bean name as-is,
* {@code toString}. The resulting String can be used as bean name as-is,
* provided that corresponding beans are defined in the bean factory.
* Alternatively, {@link #setServiceMappings(java.util.Properties) a custom mapping}
* between service ids and bean names can be defined.
@@ -99,7 +98,7 @@ import org.springframework.util.StringUtils;
*
*&lt;/beans></pre>
*
* <p>The attendant <code>MyClientBean</code> class implementation might then
* <p>The attendant {@code MyClientBean} class implementation might then
* look something like this:
*
* <pre class="code">package a.b.c;
@@ -151,7 +150,7 @@ import org.springframework.util.StringUtils;
*
*&lt;/beans></pre>
*
* <p>The attendant <code>MyClientBean</code> class implementation might then
* <p>The attendant {@code MyClientBean} class implementation might then
* look something like this:
*
* <pre class="code">package a.b.c;
@@ -202,8 +201,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
/**
* Set the service locator interface to use, which must have one or more methods with
* the signatures <code>MyType xxx()</code> or <code>MyType xxx(MyIdType id)</code>
* (typically, <code>MyService getService()</code> or <code>MyService getService(String id)</code>).
* the signatures {@code MyType xxx()} or {@code MyType xxx(MyIdType id)}
* (typically, {@code MyService getService()} or {@code MyService getService(String id)}).
* See the {@link ServiceLocatorFactoryBean class-level Javadoc} for
* information on the semantics of such methods.
*/
@@ -214,8 +213,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
/**
* Set the exception class that the service locator should throw if service
* lookup failed. The specified exception class must have a constructor
* with one of the following parameter types: <code>(String, Throwable)</code>
* or <code>(Throwable)</code> or <code>(String)</code>.
* with one of the following parameter types: {@code (String, Throwable)}
* or {@code (Throwable)} or {@code (String)}.
* <p>If not specified, subclasses of Spring's BeansException will be thrown,
* for example NoSuchBeanDefinitionException. As those are unchecked, the
* caller does not need to handle them, so it might be acceptable that
@@ -236,7 +235,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
* Set mappings between service ids (passed into the service locator)
* and bean names (in the bean factory). Service ids that are not defined
* here will be treated as bean names as-is.
* <p>The empty string as service id key defines the mapping for <code>null</code> and
* <p>The empty string as service id key defines the mapping for {@code null} and
* empty string, and for factory methods without parameter. If not defined,
* a single matching bean will be retrieved from the bean factory.
* @param serviceMappings mappings between service ids and bean names,
@@ -271,8 +270,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
* Determine the constructor to use for the given service locator exception
* class. Only called in case of a custom service locator exception.
* <p>The default implementation looks for a constructor with one of the
* following parameter types: <code>(String, Throwable)</code>
* or <code>(Throwable)</code> or <code>(String)</code>.
* following parameter types: {@code (String, Throwable)}
* or {@code (Throwable)} or {@code (String)}.
* @param exceptionClass the exception class
* @return the constructor to use
* @see #setServiceLocatorExceptionClass
@@ -364,12 +363,12 @@ public class ServiceLocatorFactoryBean implements FactoryBean<Object>, BeanFacto
try {
String beanName = tryGetBeanName(args);
if (StringUtils.hasLength(beanName)) {
// Service locator for a specific bean name.
// Service locator for a specific bean name
return beanFactory.getBean(beanName, serviceLocatorMethodReturnType);
}
else {
// Service locator for a bean type.
return BeanFactoryUtils.beanOfTypeIncludingAncestors(beanFactory, serviceLocatorMethodReturnType);
// Service locator for a bean type
return beanFactory.getBean(serviceLocatorMethodReturnType);
}
}
catch (BeansException ex) {
@@ -576,35 +576,36 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (this.logger.isInfoEnabled()) {
this.logger.info("Pre-instantiating singletons in " + this);
}
List<String> beanNames;
synchronized (this.beanDefinitionMap) {
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
beanNames = new ArrayList<String>(this.beanDefinitionNames);
}
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
@@ -650,9 +651,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
resetBeanDefinition(beanName);
}
resetBeanDefinition(beanName);
}
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
@@ -668,9 +669,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
this.beanDefinitionNames.remove(beanName);
this.frozenBeanDefinitionNames = null;
resetBeanDefinition(beanName);
}
resetBeanDefinition(beanName);
}
/**
@@ -685,9 +686,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
synchronized (getSingletonMutex()) {
destroySingleton(beanName);
}
destroySingleton(beanName);
// Remove any assumptions about by-type mappings
this.singletonBeanNamesByType.clear();
@@ -98,7 +98,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
private final Set<String> singletonsCurrentlyInCreation = Collections.synchronizedSet(new HashSet<String>());
/** Names of beans currently excluded from in creation checks */
private final Set<String> inCreationCheckExclusions = new HashSet<String>();
private final Set<String> inCreationCheckExclusions = Collections.synchronizedSet(new HashSet<String>());
/** List of suppressed Exceptions, available for associating related causes */
private Set<Exception> suppressedExceptions;
@@ -437,11 +437,12 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
this.singletonsCurrentlyInDestruction = true;
}
String[] disposableBeanNames;
synchronized (this.disposableBeans) {
String[] disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]);
}
disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
}
for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
destroySingleton(disposableBeanNames[i]);
}
this.containedBeanMap.clear();
@@ -1541,6 +1541,24 @@ public final class BeanWrapperTests {
assertEquals(TestEnum.TEST_VALUE, consumer.getEnumValue());
}
@Test
public void cornerSpr10115() {
Spr10115Bean foo = new Spr10115Bean();
BeanWrapperImpl bwi = new BeanWrapperImpl();
bwi.setWrappedInstance(foo);
bwi.setPropertyValue("prop1", "val1");
assertEquals("val1", Spr10115Bean.prop1);
}
static class Spr10115Bean {
private static String prop1;
public static void setProp1(String prop1) {
Spr10115Bean.prop1 = prop1;
}
}
private static class Foo {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 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,14 @@
package org.springframework.beans;
import static org.junit.Assert.*;
import java.util.ArrayList;
import org.junit.Test;
import test.beans.TestBean;
import org.springframework.core.OverridingClassLoader;
import test.beans.TestBean;
import static org.junit.Assert.*;
/**
* @author Juergen Hoeller
@@ -30,7 +32,7 @@ import test.beans.TestBean;
public final class CachedIntrospectionResultsTests {
@Test
public void testAcceptClassLoader() throws Exception {
public void acceptAndClearClassLoader() throws Exception {
BeanWrapper bw = new BeanWrapperImpl(TestBean.class);
assertTrue(bw.isWritableProperty("name"));
assertTrue(bw.isWritableProperty("age"));
@@ -50,4 +52,12 @@ public final class CachedIntrospectionResultsTests {
assertTrue(CachedIntrospectionResults.classCache.containsKey(TestBean.class));
}
@Test
public void clearClassLoaderForSystemClassLoader() throws Exception {
BeanUtils.getPropertyDescriptors(ArrayList.class);
assertTrue(CachedIntrospectionResults.classCache.containsKey(ArrayList.class));
CachedIntrospectionResults.clearClassLoader(ArrayList.class.getClassLoader());
assertFalse(CachedIntrospectionResults.classCache.containsKey(ArrayList.class));
}
}
@@ -23,23 +23,24 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.ExtendedBeanInfo.PropertyDescriptorComparator;
import org.springframework.core.JdkVersion;
import org.springframework.util.ClassUtils;
import test.beans.TestBean;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
/**
* Unit tests for {@link ExtendedBeanInfo}.
*
@@ -128,12 +129,32 @@ public class ExtendedBeanInfoTests {
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
}
@Test
public void standardReadAndNonStandardIndexedWriteMethod() throws IntrospectionException {
@SuppressWarnings("unused") class C {
public String[] getFoo() { return null; }
public C setFoo(int i, String foo) { return this; }
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "foo"), is(trueUntilJdk17()));
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(false));
assertThat(hasIndexedWriteMethodForProperty(ebi, "foo"), is(true));
}
@Test
public void standardReadMethodsAndOverloadedNonStandardWriteMethods() throws Exception {
@SuppressWarnings("unused") class C {
@@ -150,7 +171,7 @@ public class ExtendedBeanInfoTests {
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(trueUntilJdk17()));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
@@ -225,7 +246,7 @@ public class ExtendedBeanInfoTests {
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
@@ -268,13 +289,13 @@ public class ExtendedBeanInfoTests {
assertThat(hasReadMethodForProperty(bi, "bar"), is(true));
assertThat(hasWriteMethodForProperty(bi, "bar"), is(false));
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(bi, "bar"), is(true));
assertThat(hasWriteMethodForProperty(bi, "bar"), is(true));
assertThat(hasWriteMethodForProperty(bi, "bar"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
@@ -291,7 +312,7 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
@@ -312,7 +333,7 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
@@ -329,7 +350,7 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
@@ -350,7 +371,7 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
@@ -367,7 +388,7 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(false));
@@ -508,15 +529,14 @@ public class ExtendedBeanInfoTests {
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foos"), is(true));
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
}
@Ignore // see comments at SPR-9702
@Test
public void cornerSpr9702() throws IntrospectionException {
{ // baseline with standard write method
@@ -563,6 +583,20 @@ public class ExtendedBeanInfoTests {
}
}
/**
* Prior to SPR-10111 (a follow-up fix for SPR-9702), this method would throw an
* IntrospectionException regarding a "type mismatch between indexed and non-indexed
* methods" intermittently (approximately one out of every four times) under JDK 7
* due to non-deterministic results from {@link Class#getDeclaredMethods()}.
* See http://bugs.sun.com/view_bug.do?bug_id=7023180
* @see #cornerSpr9702()
*/
@Test
public void cornerSpr10111() throws Exception {
new ExtendedBeanInfo(Introspector.getBeanInfo(BigDecimal.class));
}
@Test
public void subclassWriteMethodWithCovariantReturnType() throws IntrospectionException {
@SuppressWarnings("unused") class B {
@@ -579,10 +613,10 @@ public class ExtendedBeanInfoTests {
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(true));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
@@ -598,7 +632,7 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(true));
@@ -619,9 +653,67 @@ public class ExtendedBeanInfoTests {
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(ebi.getPropertyDescriptors(), equalTo(bi.getPropertyDescriptors()));
assertThat(ebi.getPropertyDescriptors().length, equalTo(bi.getPropertyDescriptors().length));
assertThat(ebi.getPropertyDescriptors().length, equalTo(1));
assertThat(ebi.getPropertyDescriptors()[0].getName(), equalTo("class"));
}
@Test
public void overloadedNonStandardWriteMethodsOnly_orderA() throws IntrospectionException, SecurityException, NoSuchMethodException {
@SuppressWarnings("unused") class C {
public Object setFoo(String p) { return new Object(); }
public Object setFoo(int p) { return new Object(); }
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
if (pd.getName().equals("foo")) {
assertThat(pd.getWriteMethod(), is(C.class.getMethod("setFoo", String.class)));
return;
}
}
fail("never matched write method");
}
@Test
public void overloadedNonStandardWriteMethodsOnly_orderB() throws IntrospectionException, SecurityException, NoSuchMethodException {
@SuppressWarnings("unused") class C {
public Object setFoo(int p) { return new Object(); }
public Object setFoo(String p) { return new Object(); }
}
BeanInfo bi = Introspector.getBeanInfo(C.class);
assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(bi, "foo"), is(false));
assertThat(hasReadMethodForProperty(ebi, "foo"), is(false));
assertThat(hasWriteMethodForProperty(ebi, "foo"), is(true));
for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
if (pd.getName().equals("foo")) {
assertThat(pd.getWriteMethod(), is(C.class.getMethod("setFoo", String.class)));
return;
}
}
fail("never matched write method");
}
/**
@@ -645,7 +737,7 @@ public class ExtendedBeanInfoTests {
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
@@ -653,15 +745,15 @@ public class ExtendedBeanInfoTests {
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
assertThat(hasReadMethodForProperty(ebi, "dateFormat"), is(false));
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(false));
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(true));
assertThat(hasIndexedReadMethodForProperty(ebi, "dateFormat"), is(false));
assertThat(hasIndexedWriteMethodForProperty(ebi, "dateFormat"), is(true));
assertThat(hasIndexedWriteMethodForProperty(ebi, "dateFormat"), is(trueUntilJdk17()));
}
@Test
public void propertyCountsMatch() throws IntrospectionException {
BeanInfo bi = Introspector.getBeanInfo(TestBean.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(ebi.getPropertyDescriptors().length, equalTo(bi.getPropertyDescriptors().length));
}
@@ -673,7 +765,7 @@ public class ExtendedBeanInfoTests {
public ExtendedTestBean setFoo(String s) { return this; }
}
BeanInfo bi = Introspector.getBeanInfo(ExtendedTestBean.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
boolean found = false;
for (PropertyDescriptor pd : ebi.getPropertyDescriptors()) {
@@ -692,7 +784,7 @@ public class ExtendedBeanInfoTests {
@Test
public void propertyDescriptorOrderIsEqual() throws IntrospectionException {
BeanInfo bi = Introspector.getBeanInfo(TestBean.class);
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
for (int i = 0; i < bi.getPropertyDescriptors().length; i++) {
assertThat("element " + i + " in BeanInfo and ExtendedBeanInfo propertyDescriptor arrays do not match",
@@ -739,7 +831,9 @@ public class ExtendedBeanInfoTests {
private boolean hasIndexedWriteMethodForProperty(BeanInfo beanInfo, String propertyName) {
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
if (pd.getName().equals(propertyName)) {
assertThat(propertyName + " property is not indexed", pd, instanceOf(IndexedPropertyDescriptor.class));
if (!(pd instanceof IndexedPropertyDescriptor)) {
return false;
}
return ((IndexedPropertyDescriptor)pd).getIndexedWriteMethod() != null;
}
}
@@ -749,7 +843,9 @@ public class ExtendedBeanInfoTests {
private boolean hasIndexedReadMethodForProperty(BeanInfo beanInfo, String propertyName) {
for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
if (pd.getName().equals(propertyName)) {
assertThat(propertyName + " property is not indexed", pd, instanceOf(IndexedPropertyDescriptor.class));
if (!(pd instanceof IndexedPropertyDescriptor)) {
return false;
}
return ((IndexedPropertyDescriptor)pd).getIndexedReadMethod() != null;
}
}
@@ -830,7 +926,7 @@ public class ExtendedBeanInfoTests {
}
// and now demonstrate that we've indeed fixed the problem
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
BeanInfo ebi = new ExtendedBeanInfo(bi);
assertThat(hasReadMethodForProperty(bi, "targetMethod"), is(true));
assertThat(hasWriteMethodForProperty(bi, "targetMethod"), is(false));
@@ -855,7 +951,7 @@ public class ExtendedBeanInfoTests {
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
}
{
ExtendedBeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
@@ -863,4 +959,27 @@ public class ExtendedBeanInfoTests {
}
}
@Test
public void shouldSupportStaticWriteMethod() throws IntrospectionException {
{
BeanInfo bi = Introspector.getBeanInfo(WithStaticWriteMethod.class);
assertThat(hasReadMethodForProperty(bi, "prop1"), is(false));
assertThat(hasWriteMethodForProperty(bi, "prop1"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "prop1"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "prop1"), is(false));
}
{
BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(WithStaticWriteMethod.class));
assertThat(hasReadMethodForProperty(bi, "prop1"), is(false));
assertThat(hasWriteMethodForProperty(bi, "prop1"), is(true));
assertThat(hasIndexedReadMethodForProperty(bi, "prop1"), is(false));
assertThat(hasIndexedWriteMethodForProperty(bi, "prop1"), is(false));
}
}
static class WithStaticWriteMethod {
@SuppressWarnings("unused")
public static void setProp1(String prop1) {
}
}
}
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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.
@@ -35,6 +35,7 @@ import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.internet.MimeUtility;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
@@ -241,7 +242,7 @@ public class MimeMessageHelper {
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int, String)
*/
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, String encoding)
throws MessagingException {
throws MessagingException {
this(mimeMessage, (multipart ? MULTIPART_MODE_MIXED_RELATED : MULTIPART_MODE_NO), encoding);
}
@@ -283,7 +284,7 @@ public class MimeMessageHelper {
* @see #MULTIPART_MODE_MIXED_RELATED
*/
public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode, String encoding)
throws MessagingException {
throws MessagingException {
this.mimeMessage = mimeMessage;
createMimeMultiparts(mimeMessage, multipartMode);
@@ -355,7 +356,7 @@ public class MimeMessageHelper {
/**
* Set the given MimeMultipart objects for use by this MimeMessageHelper.
* @param root the root MimeMultipart object, which attachments will be added to;
* or <code>null</code> to indicate no multipart at all
* or {@code null} to indicate no multipart at all
* @param main the main MimeMultipart object, which text(s) and inline elements
* will be added to (can be the same as the root multipart object, or an element
* nested underneath the root multipart element)
@@ -380,8 +381,8 @@ public class MimeMessageHelper {
private void checkMultipart() throws IllegalStateException {
if (!isMultipart()) {
throw new IllegalStateException("Not in multipart mode - " +
"create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " +
"if you need to set alternative texts or add inline elements or attachments.");
"create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " +
"if you need to set alternative texts or add inline elements or attachments.");
}
}
@@ -420,7 +421,7 @@ public class MimeMessageHelper {
* Determine the default encoding for the given MimeMessage.
* @param mimeMessage the passed-in MimeMessage
* @return the default encoding associated with the MimeMessage,
* or <code>null</code> if none found
* or {@code null} if none found
*/
protected String getDefaultEncoding(MimeMessage mimeMessage) {
if (mimeMessage instanceof SmartMimeMessage) {
@@ -456,12 +457,12 @@ public class MimeMessageHelper {
}
/**
* Set the Java Activation Framework <code>FileTypeMap</code> to use
* Set the Java Activation Framework {@code FileTypeMap} to use
* for determining the content type of inline content and attachments
* that get added to the message.
* <p>Default is the <code>FileTypeMap</code> that the underlying
* <p>Default is the {@code FileTypeMap} that the underlying
* MimeMessage carries, if any, or the Activation Framework's default
* <code>FileTypeMap</code> instance else.
* {@code FileTypeMap} instance else.
* @see #addInline
* @see #addAttachment
* @see #getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
@@ -474,7 +475,7 @@ public class MimeMessageHelper {
}
/**
* Return the <code>FileTypeMap</code> used by this MimeMessageHelper.
* Return the {@code FileTypeMap} used by this MimeMessageHelper.
*/
public FileTypeMap getFileTypeMap() {
return this.fileTypeMap;
@@ -485,7 +486,7 @@ public class MimeMessageHelper {
* Set whether to validate all addresses which get passed to this helper.
* Default is "false".
* <p>Note that this is by default just available for JavaMail >= 1.3.
* You can override the default <code>validateAddress method</code> for
* You can override the default {@code validateAddress method} for
* validation on older JavaMail versions (or for custom validation).
* @see #validateAddress
*/
@@ -503,7 +504,7 @@ public class MimeMessageHelper {
/**
* Validate the given mail address.
* Called by all of MimeMessageHelper's address setters and adders.
* <p>Default implementation invokes <code>InternetAddress.validate()</code>,
* <p>Default implementation invokes {@code InternetAddress.validate()},
* provided that address validation is activated for the helper instance.
* <p>Note that this method will just work on JavaMail >= 1.3. You can override
* it for validation on older JavaMail versions or for custom validation.
@@ -546,7 +547,7 @@ public class MimeMessageHelper {
public void setFrom(String from, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(from, "From address must not be null");
setFrom(getEncoding() != null ?
new InternetAddress(from, personal, getEncoding()) : new InternetAddress(from, personal));
new InternetAddress(from, personal, getEncoding()) : new InternetAddress(from, personal));
}
public void setReplyTo(InternetAddress replyTo) throws MessagingException {
@@ -608,8 +609,8 @@ public class MimeMessageHelper {
public void addTo(String to, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(to, "To address must not be null");
addTo(getEncoding() != null ?
new InternetAddress(to, personal, getEncoding()) :
new InternetAddress(to, personal));
new InternetAddress(to, personal, getEncoding()) :
new InternetAddress(to, personal));
}
@@ -653,8 +654,8 @@ public class MimeMessageHelper {
public void addCc(String cc, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(cc, "Cc address must not be null");
addCc(getEncoding() != null ?
new InternetAddress(cc, personal, getEncoding()) :
new InternetAddress(cc, personal));
new InternetAddress(cc, personal, getEncoding()) :
new InternetAddress(cc, personal));
}
@@ -698,8 +699,8 @@ public class MimeMessageHelper {
public void addBcc(String bcc, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(bcc, "Bcc address must not be null");
addBcc(getEncoding() != null ?
new InternetAddress(bcc, personal, getEncoding()) :
new InternetAddress(bcc, personal));
new InternetAddress(bcc, personal, getEncoding()) :
new InternetAddress(bcc, personal));
}
private InternetAddress parseAddress(String address) throws MessagingException {
@@ -730,7 +731,7 @@ public class MimeMessageHelper {
/**
* Set the sent-date of the message.
* @param sentDate the date to set (never <code>null</code>)
* @param sentDate the date to set (never {@code null})
* @throws MessagingException in case of errors
*/
public void setSentDate(Date sentDate) throws MessagingException {
@@ -758,7 +759,7 @@ public class MimeMessageHelper {
* Set the given text directly as content in non-multipart mode
* or as default body part in multipart mode.
* Always applies the default content type "text/plain".
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> <code>setText</code>;
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param text the text for the message
* @throws MessagingException in case of errors
@@ -771,7 +772,7 @@ public class MimeMessageHelper {
* Set the given text directly as content in non-multipart mode
* or as default body part in multipart mode.
* The "html" flag determines the content type to apply.
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> <code>setText</code>;
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param text the text for the message
* @param html whether to apply content type "text/html" for an
@@ -798,7 +799,7 @@ public class MimeMessageHelper {
/**
* Set the given plain text and HTML text as alternatives, offering
* both options to the email client. Requires multipart mode.
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> <code>setText</code>;
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param plainText the plain text for the message
* @param htmlText the HTML text for the message
@@ -860,16 +861,16 @@ public class MimeMessageHelper {
/**
* Add an inline element to the MimeMessage, taking the content from a
* <code>javax.activation.DataSource</code>.
* {@code javax.activation.DataSource}.
* <p>Note that the InputStream returned by the DataSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* <code>getInputStream()</code> multiple times.
* <p><b>NOTE:</b> Invoke <code>addInline</code> <i>after</i> {@link #setText};
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "&lt;myId&gt;".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param dataSource the <code>javax.activation.DataSource</code> to take
* @param dataSource the {@code javax.activation.DataSource} to take
* the content from, determining the InputStream and the content type
* @throws MessagingException in case of errors
* @see #addInline(String, java.io.File)
@@ -889,11 +890,11 @@ public class MimeMessageHelper {
/**
* Add an inline element to the MimeMessage, taking the content from a
* <code>java.io.File</code>.
* {@code java.io.File}.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
* <p><b>NOTE:</b> Invoke <code>addInline</code> <i>after</i> {@link #setText};
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "&lt;myId&gt;".
@@ -913,14 +914,14 @@ public class MimeMessageHelper {
/**
* Add an inline element to the MimeMessage, taking the content from a
* <code>org.springframework.core.io.Resource</code>.
* {@code org.springframework.core.io.Resource}.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
* <p>Note that the InputStream returned by the Resource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* <code>getInputStream()</code> multiple times.
* <p><b>NOTE:</b> Invoke <code>addInline</code> <i>after</i> {@link #setText};
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "&lt;myId&gt;".
@@ -939,14 +940,14 @@ public class MimeMessageHelper {
/**
* Add an inline element to the MimeMessage, taking the content from an
* <code>org.springframework.core.InputStreamResource</code>, and
* {@code org.springframework.core.InputStreamResource}, and
* specifying the content type explicitly.
* <p>You can determine the content type for any given filename via a Java
* Activation Framework's FileTypeMap, for example the one held by this helper.
* <p>Note that the InputStream returned by the InputStreamSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* <code>getInputStream()</code> multiple times.
* <p><b>NOTE:</b> Invoke <code>addInline</code> <i>after</i> <code>setText</code>;
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "&lt;myId&gt;".
@@ -960,7 +961,7 @@ public class MimeMessageHelper {
* @see #addInline(String, javax.activation.DataSource)
*/
public void addInline(String contentId, InputStreamSource inputStreamSource, String contentType)
throws MessagingException {
throws MessagingException {
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
@@ -974,13 +975,13 @@ public class MimeMessageHelper {
/**
* Add an attachment to the MimeMessage, taking the content from a
* <code>javax.activation.DataSource</code>.
* {@code javax.activation.DataSource}.
* <p>Note that the InputStream returned by the DataSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* <code>getInputStream()</code> multiple times.
* {@code getInputStream()} multiple times.
* @param attachmentFilename the name of the attachment as it will
* appear in the mail (the content type will be determined by this)
* @param dataSource the <code>javax.activation.DataSource</code> to take
* @param dataSource the {@code javax.activation.DataSource} to take
* the content from, determining the InputStream and the content type
* @throws MessagingException in case of errors
* @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
@@ -989,16 +990,21 @@ public class MimeMessageHelper {
public void addAttachment(String attachmentFilename, DataSource dataSource) throws MessagingException {
Assert.notNull(attachmentFilename, "Attachment filename must not be null");
Assert.notNull(dataSource, "DataSource must not be null");
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
mimeBodyPart.setFileName(attachmentFilename);
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
getRootMimeMultipart().addBodyPart(mimeBodyPart);
try {
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
mimeBodyPart.setFileName(MimeUtility.encodeText(attachmentFilename));
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
getRootMimeMultipart().addBodyPart(mimeBodyPart);
}
catch (UnsupportedEncodingException ex) {
throw new MessagingException("Failed to encode attachment filename", ex);
}
}
/**
* Add an attachment to the MimeMessage, taking the content from a
* <code>java.io.File</code>.
* {@code java.io.File}.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
@@ -1018,13 +1024,13 @@ public class MimeMessageHelper {
/**
* Add an attachment to the MimeMessage, taking the content from an
* <code>org.springframework.core.io.InputStreamResource</code>.
* {@code org.springframework.core.io.InputStreamResource}.
* <p>The content type will be determined by the given filename for
* the attachment. Thus, any content source will be fine, including
* temporary files with arbitrary filenames.
* <p>Note that the InputStream returned by the InputStreamSource
* implementation needs to be a <i>fresh one on each call</i>, as
* JavaMail will invoke <code>getInputStream()</code> multiple times.
* JavaMail will invoke {@code getInputStream()} multiple times.
* @param attachmentFilename the name of the attachment as it will
* appear in the mail
* @param inputStreamSource the resource to take the content from
@@ -1035,7 +1041,7 @@ public class MimeMessageHelper {
* @see org.springframework.core.io.Resource
*/
public void addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
throws MessagingException {
throws MessagingException {
String contentType = getFileTypeMap().getContentType(attachmentFilename);
addAttachment(attachmentFilename, inputStreamSource, contentType);
@@ -1043,10 +1049,10 @@ public class MimeMessageHelper {
/**
* Add an attachment to the MimeMessage, taking the content from an
* <code>org.springframework.core.io.InputStreamResource</code>.
* {@code org.springframework.core.io.InputStreamResource}.
* <p>Note that the InputStream returned by the InputStreamSource
* implementation needs to be a <i>fresh one on each call</i>, as
* JavaMail will invoke <code>getInputStream()</code> multiple times.
* JavaMail will invoke {@code getInputStream()} multiple times.
* @param attachmentFilename the name of the attachment as it will
* appear in the mail
* @param inputStreamSource the resource to take the content from
@@ -1059,7 +1065,7 @@ public class MimeMessageHelper {
*/
public void addAttachment(
String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
throws MessagingException {
throws MessagingException {
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
@@ -1079,7 +1085,7 @@ public class MimeMessageHelper {
* @return the Activation Framework DataSource
*/
protected DataSource createDataSource(
final InputStreamSource inputStreamSource, final String contentType, final String name) {
final InputStreamSource inputStreamSource, final String contentType, final String name) {
return new DataSource() {
public InputStream getInputStream() throws IOException {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -43,10 +43,15 @@ public class TimerManagerTaskScheduler extends TimerManagerAccessor implements T
private volatile ErrorHandler errorHandler;
/**
* Provide an {@link ErrorHandler} strategy.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public ScheduledFuture schedule(Runnable task, Trigger trigger) {
return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -65,26 +65,6 @@ import org.springframework.util.Assert;
* {@link org.springframework.jca.work.glassfish.GlassFishWorkManagerTaskExecutor}
* classes which are the direct equivalent of this CommonJ adapter class.
*
* <p>A similar facility is available on WebSphere 5.1, under the name
* "Asynch Beans". Its central interface is called WorkManager too and is
* also obtained from JNDI, just like a standard CommonJ WorkManager.
* However, this WorkManager variant is notably different: The central
* execution method is called "startWork" instead of "schedule",
* and takes a slightly different Work interface as parameter.
*
* <p>Support for this WebSphere 5.1 variant can be built with this class
* and its helper DelegatingWork as template: Call the WorkManager's
* <code>startWork(Work)</code> instead of <code>schedule(Work)</code>
* in the <code>execute(Runnable)</code> implementation. Furthermore,
* for simplicity's sake, drop the entire "Implementation of the CommonJ
* WorkManager interface" section (and the corresponding
* <code>implements WorkManager</code> clause at the class level).
* Of course, you also need to change all <code>commonj.work</code> imports in
* your WorkManagerTaskExecutor and DelegatingWork variants to the corresponding
* WebSphere API imports (<code>com.ibm.websphere.asynchbeans.WorkManager</code>
* and <code>com.ibm.websphere.asynchbeans.Work</code>, respectively).
* This should be sufficient to get a TaskExecutor adapter for WebSphere 5.
*
* @author Juergen Hoeller
* @since 2.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -95,8 +95,8 @@ public class SchedulerAccessorBean extends SchedulerAccessor implements BeanFact
if (this.beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory lbf = (ListableBeanFactory) this.beanFactory;
String[] beanNames = lbf.getBeanNamesForType(Scheduler.class);
for (int i = 0; i < beanNames.length; i++) {
Scheduler schedulerBean = (Scheduler) lbf.getBean(beanNames[i]);
for (String beanName : beanNames) {
Scheduler schedulerBean = (Scheduler) lbf.getBean(beanName);
if (schedulerName.equals(schedulerBean.getSchedulerName())) {
return schedulerBean;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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,6 +20,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -47,12 +48,12 @@ import org.springframework.util.CollectionUtils;
* <p>The optional "configLocation" property sets the location of a FreeMarker
* properties file, within the current application. FreeMarker properties can be
* overridden via "freemarkerSettings". All of these properties will be set by
* calling FreeMarker's <code>Configuration.setSettings()</code> method and are
* calling FreeMarker's {@code Configuration.setSettings()} method and are
* subject to constraints set by FreeMarker.
*
* <p>The "freemarkerVariables" property can be used to specify a Map of
* shared variables that will be applied to the Configuration via the
* <code>setAllSharedVariables()</code> method. Like <code>setSettings()</code>,
* {@code setAllSharedVariables()} method. Like {@code setSettings()},
* these entries are subject to FreeMarker constraints.
*
* <p>The simplest way to use this class is to specify a "templateLoaderPath";
@@ -109,7 +110,7 @@ public class FreeMarkerConfigurationFactory {
/**
* Set properties that contain well-known FreeMarker keys which will be
* passed to FreeMarker's <code>Configuration.setSettings</code> method.
* passed to FreeMarker's {@code Configuration.setSettings} method.
* @see freemarker.template.Configuration#setSettings
*/
public void setFreemarkerSettings(Properties settings) {
@@ -118,7 +119,7 @@ public class FreeMarkerConfigurationFactory {
/**
* Set a Map that contains well-known FreeMarker objects which will be passed
* to FreeMarker's <code>Configuration.setAllSharedVariables()</code> method.
* to FreeMarker's {@code Configuration.setAllSharedVariables()} method.
* @see freemarker.template.Configuration#setAllSharedVariables
*/
public void setFreemarkerVariables(Map<String, Object> variables) {
@@ -138,7 +139,7 @@ public class FreeMarkerConfigurationFactory {
}
/**
* Set a List of <code>TemplateLoader<code>s that will be used to search
* Set a List of {@code TemplateLoader}s that will be used to search
* for templates. For example, one or more custom loaders such as database
* loaders could be configured and injected here.
* @deprecated as of Spring 2.0.1, in favor of the "preTemplateLoaders"
@@ -147,14 +148,14 @@ public class FreeMarkerConfigurationFactory {
* @see #setPostTemplateLoaders
*/
@Deprecated
public void setTemplateLoaders(TemplateLoader[] templateLoaders) {
public void setTemplateLoaders(TemplateLoader... templateLoaders) {
if (templateLoaders != null) {
this.templateLoaders.addAll(Arrays.asList(templateLoaders));
}
}
/**
* Set a List of <code>TemplateLoader<code>s that will be used to search
* Set a List of {@code TemplateLoader}s that will be used to search
* for templates. For example, one or more custom loaders such as database
* loaders could be configured and injected here.
* <p>The {@link TemplateLoader TemplateLoaders} specified here will be
@@ -164,12 +165,12 @@ public class FreeMarkerConfigurationFactory {
* @see #setTemplateLoaderPaths
* @see #postProcessTemplateLoaders
*/
public void setPreTemplateLoaders(TemplateLoader[] preTemplateLoaders) {
public void setPreTemplateLoaders(TemplateLoader... preTemplateLoaders) {
this.preTemplateLoaders = Arrays.asList(preTemplateLoaders);
}
/**
* Set a List of <code>TemplateLoader<code>s that will be used to search
* Set a List of {@code TemplateLoader}s that will be used to search
* for templates. For example, one or more custom loaders such as database
* loaders can be configured.
* <p>The {@link TemplateLoader TemplateLoaders} specified here will be
@@ -179,7 +180,7 @@ public class FreeMarkerConfigurationFactory {
* @see #setTemplateLoaderPaths
* @see #postProcessTemplateLoaders
*/
public void setPostTemplateLoaders(TemplateLoader[] postTemplateLoaders) {
public void setPostTemplateLoaders(TemplateLoader... postTemplateLoaders) {
this.postTemplateLoaders = Arrays.asList(postTemplateLoaders);
}
@@ -198,20 +199,20 @@ public class FreeMarkerConfigurationFactory {
* pseudo URLs are supported, as understood by ResourceEditor. Allows for
* relative paths when running in an ApplicationContext.
* <p>Will define a path for the default FreeMarker template loader.
* If a specified resource cannot be resolved to a <code>java.io.File</code>,
* If a specified resource cannot be resolved to a {@code java.io.File},
* a generic SpringTemplateLoader will be used, without modification detection.
* <p>To enforce the use of SpringTemplateLoader, i.e. to not resolve a path
* as file system resource in any case, turn off the "preferFileSystemAccess"
* flag. See the latter's javadoc for details.
* <p>If you wish to specify your own list of TemplateLoaders, do not set this
* property and instead use <code>setTemplateLoaders(List templateLoaders)</code>
* property and instead use {@code setTemplateLoaders(List templateLoaders)}
* @see org.springframework.core.io.ResourceEditor
* @see org.springframework.context.ApplicationContext#getResource
* @see freemarker.template.Configuration#setDirectoryForTemplateLoading
* @see SpringTemplateLoader
* @see #setTemplateLoaders
*/
public void setTemplateLoaderPaths(String[] templateLoaderPaths) {
public void setTemplateLoaderPaths(String... templateLoaderPaths) {
this.templateLoaderPaths = templateLoaderPaths;
}
@@ -229,7 +230,7 @@ public class FreeMarkerConfigurationFactory {
* Return the Spring ResourceLoader to use for loading FreeMarker template files.
*/
protected ResourceLoader getResourceLoader() {
return resourceLoader;
return this.resourceLoader;
}
/**
@@ -252,7 +253,7 @@ public class FreeMarkerConfigurationFactory {
* Return whether to prefer file system access for template loading.
*/
protected boolean isPreferFileSystemAccess() {
return preferFileSystemAccess;
return this.preferFileSystemAccess;
}
@@ -293,25 +294,27 @@ public class FreeMarkerConfigurationFactory {
config.setDefaultEncoding(this.defaultEncoding);
}
List<TemplateLoader> templateLoaders = new LinkedList<TemplateLoader>(this.templateLoaders);
// Register template loaders that are supposed to kick in early.
if (this.preTemplateLoaders != null) {
this.templateLoaders.addAll(this.preTemplateLoaders);
templateLoaders.addAll(this.preTemplateLoaders);
}
// Register default template loaders.
if (this.templateLoaderPaths != null) {
for (String path : this.templateLoaderPaths) {
this.templateLoaders.add(getTemplateLoaderForPath(path));
templateLoaders.add(getTemplateLoaderForPath(path));
}
}
postProcessTemplateLoaders(this.templateLoaders);
postProcessTemplateLoaders(templateLoaders);
// Register template loaders that are supposed to kick in late.
if (this.postTemplateLoaders != null) {
this.templateLoaders.addAll(this.postTemplateLoaders);
templateLoaders.addAll(this.postTemplateLoaders);
}
TemplateLoader loader = getAggregateTemplateLoader(this.templateLoaders);
TemplateLoader loader = getAggregateTemplateLoader(templateLoaders);
if (loader != null) {
config.setTemplateLoader(loader);
}
@@ -323,7 +326,7 @@ public class FreeMarkerConfigurationFactory {
/**
* Return a new Configuration object. Subclasses can override this for
* custom initialization, or for using a mock object for testing.
* <p>Called by <code>createConfiguration()</code>.
* <p>Called by {@code createConfiguration()}.
* @return the Configuration object
* @throws IOException if a config file wasn't found
* @throws TemplateException on FreeMarker initialization failure
@@ -374,7 +377,7 @@ public class FreeMarkerConfigurationFactory {
* To be overridden by subclasses that want to to register custom
* TemplateLoader instances after this factory created its default
* template loaders.
* <p>Called by <code>createConfiguration()</code>. Note that specified
* <p>Called by {@code createConfiguration()}. Note that specified
* "postTemplateLoaders" will be registered <i>after</i> any loaders
* registered by this callback; as a consequence, they are are <i>not</i>
* included in the given List.
@@ -411,7 +414,7 @@ public class FreeMarkerConfigurationFactory {
* To be overridden by subclasses that want to to perform custom
* post-processing of the Configuration object after this factory
* performed its default initialization.
* <p>Called by <code>createConfiguration()</code>.
* <p>Called by {@code createConfiguration()}.
* @param config the current Configuration object
* @throws IOException if a config file wasn't found
* @throws TemplateException on FreeMarker initialization failure
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -39,6 +39,7 @@ import org.springframework.util.Assert;
* {@code CacheOperationSource}.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 3.1
*/
@SuppressWarnings("serial")
@@ -71,6 +72,16 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
this.annotationParsers.add(new SpringCacheAnnotationParser());
}
/**
* Create a custom AnnotationCacheOperationSource.
* @param annotationParser the CacheAnnotationParser to use
*/
public AnnotationCacheOperationSource(CacheAnnotationParser annotationParser) {
this.publicMethodsOnly = true;
Assert.notNull(annotationParser, "CacheAnnotationParser must not be null");
this.annotationParsers = Collections.singleton(annotationParser);
}
/**
* Create a custom AnnotationCacheOperationSource.
* @param annotationParsers the CacheAnnotationParser to use
@@ -83,6 +94,16 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
this.annotationParsers = parsers;
}
/**
* Create a custom AnnotationCacheOperationSource.
* @param annotationParsers the CacheAnnotationParser to use
*/
public AnnotationCacheOperationSource(Set<CacheAnnotationParser> annotationParsers) {
this.publicMethodsOnly = true;
Assert.notEmpty(annotationParsers, "At least one CacheAnnotationParser needs to be specified");
this.annotationParsers = annotationParsers;
}
@Override
protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
@@ -106,7 +127,6 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
*/
protected Collection<CacheOperation> determineCacheOperations(AnnotatedElement ae) {
Collection<CacheOperation> ops = null;
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
Collection<CacheOperation> annOps = annotationParser.parseCacheAnnotations(ae);
if (annOps != null) {
@@ -126,4 +146,24 @@ public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperati
protected boolean allowPublicMethodsOnly() {
return this.publicMethodsOnly;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AnnotationCacheOperationSource)) {
return false;
}
AnnotationCacheOperationSource otherCos = (AnnotationCacheOperationSource) other;
return (this.annotationParsers.equals(otherCos.annotationParsers) &&
this.publicMethodsOnly == otherCos.publicMethodsOnly);
}
@Override
public int hashCode() {
return this.annotationParsers.hashCode();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -135,7 +135,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
return ops;
}
private static <T extends Annotation> Collection<T> getAnnotations(AnnotatedElement ae, Class<T> annotationType) {
private <T extends Annotation> Collection<T> getAnnotations(AnnotatedElement ae, Class<T> annotationType) {
Collection<T> anns = new ArrayList<T>(2);
// look at raw annotation
@@ -154,4 +154,15 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
return (anns.isEmpty() ? null : anns);
}
}
@Override
public boolean equals(Object other) {
return (this == other || other instanceof SpringCacheAnnotationParser);
}
@Override
public int hashCode() {
return SpringCacheAnnotationParser.class.hashCode();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -47,8 +47,7 @@ abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut
return false;
}
CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other;
return ObjectUtils.nullSafeEquals(getCacheOperationSource(),
otherPc.getCacheOperationSource());
return ObjectUtils.nullSafeEquals(getCacheOperationSource(), otherPc.getCacheOperationSource());
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -39,16 +39,16 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
*/
class ExpressionEvaluator {
private SpelExpressionParser parser = new SpelExpressionParser();
private final SpelExpressionParser parser = new SpelExpressionParser();
// shared param discoverer since it caches data internally
private ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private final ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>();
private final Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>();
private Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>();
private final Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>();
private Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>();
private final Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>();
public EvaluationContext createEvaluationContext(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,12 +26,10 @@ import java.util.concurrent.ConcurrentMap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
/**
* Abstract base class implementing the common {@link CacheManager}
* methods. Useful for 'static' environments where the backing caches do
* not change.
* Abstract base class implementing the common {@link CacheManager} methods.
* Useful for 'static' environments where the backing caches do not change.
*
* @author Costin Leau
* @author Juergen Hoeller
@@ -46,10 +44,10 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
public void afterPropertiesSet() {
Collection<? extends Cache> caches = loadCaches();
Assert.notEmpty(caches, "loadCaches must not return an empty Collection");
this.cacheMap.clear();
// preserve the initial order of the cache names
this.cacheMap.clear();
this.cacheNames.clear();
for (Cache cache : caches) {
this.cacheMap.put(cache.getName(), cache);
this.cacheNames.add(cache.getName());
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* 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.
@@ -40,7 +40,35 @@ import org.springframework.cache.CacheManager;
public class NoOpCacheManager implements CacheManager {
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private Set<String> names = new LinkedHashSet<String>();
private final Set<String> cacheNames = new LinkedHashSet<String>();
/**
* This implementation always returns a {@link Cache} implementation that will not store items.
* Additionally, the request cache will be remembered by the manager for consistency.
*/
public Cache getCache(String name) {
Cache cache = this.caches.get(name);
if (cache == null) {
this.caches.putIfAbsent(name, new NoOpCache(name));
synchronized (this.cacheNames) {
this.cacheNames.add(name);
}
}
return this.caches.get(name);
}
/**
* This implementation returns the name of the caches previously requested.
*/
public Collection<String> getCacheNames() {
synchronized (this.cacheNames) {
return Collections.unmodifiableSet(this.cacheNames);
}
}
private static class NoOpCache implements Cache {
@@ -61,7 +89,7 @@ public class NoOpCacheManager implements CacheManager {
}
public String getName() {
return name;
return this.name;
}
public Object getNativeCache() {
@@ -72,30 +100,4 @@ public class NoOpCacheManager implements CacheManager {
}
}
/**
* {@inheritDoc}
*
* This implementation always returns a {@link Cache} implementation that will not
* store items. Additionally, the request cache will be remembered by the manager for consistency.
*/
public Cache getCache(String name) {
Cache cache = caches.get(name);
if (cache == null) {
caches.putIfAbsent(name, new NoOpCache(name));
synchronized (names) {
names.add(name);
}
}
return caches.get(name);
}
/**
* {@inheritDoc}
*
* This implementation returns the name of the caches previously requested.
*/
public Collection<String> getCacheNames() {
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.
@@ -39,12 +39,13 @@ import static org.springframework.context.annotation.MetadataUtils.*;
*/
public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
protected Class<? extends Annotation> scopeAnnotationType = Scope.class;
private final ScopedProxyMode defaultProxyMode;
protected Class<? extends Annotation> scopeAnnotationType = Scope.class;
/**
* Create a new instance of the <code>AnnotationScopeMetadataResolver</code> class.
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* @see #AnnotationScopeMetadataResolver(ScopedProxyMode)
* @see ScopedProxyMode#NO
*/
@@ -53,7 +54,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
}
/**
* Create a new instance of the <code>AnnotationScopeMetadataResolver</code> class.
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
* @param defaultProxyMode the desired scoped-proxy mode
*/
public AnnotationScopeMetadataResolver(ScopedProxyMode defaultProxyMode) {
@@ -77,8 +78,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes =
attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
AnnotationAttributes attributes = attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
@@ -25,6 +25,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -120,6 +121,13 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
}
/**
* Return the ResourceLoader that this component provider uses.
*/
public final ResourceLoader getResourceLoader() {
return this.resourcePatternResolver;
}
/**
* Set the Environment to use when resolving placeholders and evaluating
* {@link Profile @Profile}-annotated component classes.
@@ -134,13 +142,6 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
return this.environment;
}
/**
* Return the ResourceLoader that this component provider uses.
*/
public final ResourceLoader getResourceLoader() {
return this.resourcePatternResolver;
}
/**
* Set the resource pattern to use when scanning the classpath.
* This value will be appended to each base package name.
@@ -513,10 +513,6 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
protected boolean shareable = true;
private volatile boolean cached = false;
private volatile Object cachedFieldValue;
public ResourceElement(Member member, PropertyDescriptor pd) {
super(member, pd);
}
@@ -729,4 +725,4 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
}
}
}
@@ -54,8 +54,7 @@ class ComponentScanAnnotationParser {
private final BeanNameGenerator beanNameGenerator;
public ComponentScanAnnotationParser(
ResourceLoader resourceLoader, Environment environment,
public ComponentScanAnnotationParser(ResourceLoader resourceLoader, Environment environment,
BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {
this.resourceLoader = resourceLoader;
@@ -67,7 +66,7 @@ class ComponentScanAnnotationParser {
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan) {
ClassPathBeanDefinitionScanner scanner =
new ClassPathBeanDefinitionScanner(registry, componentScan.getBoolean("useDefaultFilters"));
new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"));
Assert.notNull(this.environment, "Environment must not be null");
scanner.setEnvironment(this.environment);
@@ -77,14 +76,14 @@ class ComponentScanAnnotationParser {
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
boolean useInheritedGenerator = BeanNameGenerator.class.equals(generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator
? this.beanNameGenerator
: BeanUtils.instantiateClass(generatorClass));
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
scanner.setScopedProxyMode(scopedProxyMode);
} else {
}
else {
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
}
@@ -121,7 +120,7 @@ class ComponentScanAnnotationParser {
throw new IllegalStateException("At least one base package must be specified");
}
return scanner.doScan(basePackages.toArray(new String[]{}));
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
@@ -153,4 +152,5 @@ class ComponentScanAnnotationParser {
}
return typeFilters;
}
}
@@ -56,7 +56,6 @@ class ConfigurationClassEnhancer {
DisposableBeanMethodInterceptor.class, NoOp.class };
private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() {
public int accept(Method candidateMethod) {
// Set up the callback filter to return the index of the BeanMethodInterceptor when
// handling a @Bean-annotated method; otherwise, return index of the NoOp callback.
@@ -72,7 +71,6 @@ class ConfigurationClassEnhancer {
private static final Callback DISPOSABLE_BEAN_METHOD_INTERCEPTOR = new DisposableBeanMethodInterceptor();
private final Callback[] callbackInstances;
@@ -162,6 +160,7 @@ class ConfigurationClassEnhancer {
private static class GetObjectMethodInterceptor implements MethodInterceptor {
private final ConfigurableBeanFactory beanFactory;
private final String beanName;
public GetObjectMethodInterceptor(ConfigurableBeanFactory beanFactory, String beanName) {
@@ -296,7 +295,8 @@ class ConfigurationClassEnhancer {
this.beanFactory.setCurrentlyInCreation(beanName, false);
}
return this.beanFactory.getBean(beanName);
} finally {
}
finally {
if (alreadyInCreation) {
this.beanFactory.setCurrentlyInCreation(beanName, true);
}
@@ -347,6 +347,6 @@ class ConfigurationClassEnhancer {
Enhancer.registerCallbacks(fbSubclass, callbackInstances);
return fbSubclass.newInstance();
}
}
}
@@ -16,15 +16,16 @@
package org.springframework.context.annotation;
import static org.springframework.context.annotation.MetadataUtils.attributesFor;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
@@ -51,8 +52,6 @@ import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
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
@@ -221,10 +220,9 @@ class ConfigurationClassParser {
}
// process any @Import annotations
List<AnnotationAttributes> imports =
findAllAnnotationAttributes(Import.class, metadata.getClassName(), true);
for (AnnotationAttributes importAnno : imports) {
processImport(configClass, importAnno.getStringArray("value"), true);
Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>());
if (imports != null && !imports.isEmpty()) {
processImport(configClass, imports.toArray(new String[imports.size()]), true);
}
// process any @ImportResource annotations
@@ -252,6 +250,16 @@ class ConfigurationClassParser {
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();
@@ -264,45 +272,36 @@ class ConfigurationClassParser {
}
/**
* Return a list of attribute maps for all declarations of the given annotation
* on the given annotated class using the given MetadataReaderFactory to introspect
* annotation metadata. Meta-annotations are ordered first in the list, and if the
* target annotation is declared directly on the class, its map of attributes will be
* ordered last in the list.
* @param targetAnnotation the annotation to search for, both locally and as a meta-annotation
* @param annotatedClassName the class to inspect
* @param classValuesAsString whether class attributes should be returned as strings
* Recursively collect all declared {@code @Import} values. Unlike most
* meta-annotations it is valid to have several {@code @Import}s declared with
* different values, the usual process or returning values from the first
* meta-annotation on a class is not sufficient.
* <p>For example, it is common for a {@code @Configuration} class to declare direct
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
* annotation.
* @param className the class name to search
* @param imports the imports collected so far or {@code null}
* @param visited used to track visited classes to prevent infinite recursion (must not be null)
* @return a set of all {@link Import#value() import values} or {@code null}
* @throws IOException if there is any problem reading metadata from the named class
*/
private List<AnnotationAttributes> findAllAnnotationAttributes(
Class<? extends Annotation> targetAnnotation, String annotatedClassName,
boolean classValuesAsString) throws IOException {
List<AnnotationAttributes> allAttribs = new ArrayList<AnnotationAttributes>();
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(annotatedClassName);
AnnotationMetadata metadata = reader.getAnnotationMetadata();
String targetAnnotationType = targetAnnotation.getName();
for (String annotationType : metadata.getAnnotationTypes()) {
if (annotationType.equals(targetAnnotationType)) {
continue;
private Set<String> getImports(String className, Set<String> imports,
Set<String> visited) throws IOException {
if (visited.add(className)) {
AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata();
for (String annotationType : metadata.getAnnotationTypes()) {
imports = getImports(annotationType, imports, visited);
}
AnnotationMetadata metaAnnotations =
this.metadataReaderFactory.getMetadataReader(annotationType).getAnnotationMetadata();
AnnotationAttributes targetAttribs =
AnnotationAttributes.fromMap(metaAnnotations.getAnnotationAttributes(targetAnnotationType, classValuesAsString));
if (targetAttribs != null) {
allAttribs.add(targetAttribs);
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (value != null && value.length > 0) {
imports = (imports == null ? new LinkedHashSet<String>() : imports);
imports.addAll(Arrays.asList(value));
}
}
}
AnnotationAttributes localAttribs =
AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(targetAnnotationType, classValuesAsString));
if (localAttribs != null) {
allAttribs.add(localAttribs);
}
return allAttribs;
return imports;
}
private void processImport(ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports) throws IOException {
@@ -317,7 +316,8 @@ class ConfigurationClassParser {
if (new AssignableTypeFilter(ImportSelector.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportSelector -> delegate to it to determine imports
try {
ImportSelector selector = BeanUtils.instantiateClass(Class.forName(candidate), ImportSelector.class);
ImportSelector selector = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportSelector.class);
processImport(configClass, selector.selectImports(importingClassMetadata), false);
}
catch (ClassNotFoundException ex) {
@@ -327,7 +327,8 @@ class ConfigurationClassParser {
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, metadataReaderFactory)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
try {
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(Class.forName(candidate), ImportBeanDefinitionRegistrar.class);
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportBeanDefinitionRegistrar.class);
registrar.registerBeanDefinitions(importingClassMetadata, registry);
}
catch (ClassNotFoundException ex) {
@@ -439,5 +440,4 @@ class ConfigurationClassParser {
new Location(importStack.peek().getResource(), metadata));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -53,7 +53,8 @@ import java.lang.annotation.Target;
public @interface Import {
/**
* The @{@link Configuration} and/or {@link ImportSelector} classes to import.
* The @{@link Configuration}, {@link ImportSelector} and/or
* {@link ImportBeanDefinitionRegistrar} classes to import.
*/
Class<?>[] value();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@@ -113,7 +113,9 @@ public abstract class AbstractApplicationEventMulticaster implements Application
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener> getApplicationListeners() {
return this.defaultRetriever.getApplicationListeners();
synchronized (this.defaultRetriever) {
return this.defaultRetriever.getApplicationListeners();
}
}
/**
@@ -135,26 +137,30 @@ public abstract class AbstractApplicationEventMulticaster implements Application
else {
retriever = new ListenerRetriever(true);
LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
Set<ApplicationListener> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
for (ApplicationListener listener : this.defaultRetriever.applicationListeners) {
if (supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListeners.add(listener);
listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListeners.add(listener);
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
if (!this.defaultRetriever.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.defaultRetriever.applicationListenerBeans) {
ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
}
OrderComparator.sort(allListeners);
this.retrieverCache.put(cacheKey, retriever);
return allListeners;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 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,12 +67,12 @@ public class MessageSourceResourceBundle extends ResourceBundle {
/**
* This implementation resolves the code in the MessageSource.
* Returns <code>null</code> if the message could not be resolved.
* Returns {@code null} if the message could not be resolved.
*/
@Override
protected Object handleGetObject(String code) {
protected Object handleGetObject(String key) {
try {
return this.messageSource.getMessage(code, null, this.locale);
return this.messageSource.getMessage(key, null, this.locale);
}
catch (NoSuchMessageException ex) {
return null;
@@ -80,17 +80,34 @@ public class MessageSourceResourceBundle extends ResourceBundle {
}
/**
* This implementation returns <code>null</code>, as a MessageSource does
* not allow for enumerating the defined message codes.
* This implementation checks whether the target MessageSource can resolve
* a message for the given key, translating {@code NoSuchMessageException}
* accordingly. In contrast to ResourceBundle's default implementation in
* JDK 1.6, this does not rely on the capability to enumerate message keys.
*/
@Override
public boolean containsKey(String key) {
try {
this.messageSource.getMessage(key, null, this.locale);
return true;
}
catch (NoSuchMessageException ex) {
return false;
}
}
/**
* This implementation throws {@code UnsupportedOperationException},
* as a MessageSource does not allow for enumerating the defined message codes.
*/
@Override
public Enumeration<String> getKeys() {
return null;
throw new UnsupportedOperationException("MessageSourceResourceBundle does not support enumerating its keys");
}
/**
* This implementation exposes the specified Locale for introspection
* through the standard <code>ResourceBundle.getLocale()</code> method.
* through the standard {@code ResourceBundle.getLocale()} method.
*/
@Override
public Locale getLocale() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 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.
@@ -34,13 +34,13 @@ import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
/**
* EJB3-compliant interceptor class that injects Spring beans into
* fields and methods which are annotated with <code>@Autowired</code>.
* fields and methods which are annotated with {@code @Autowired}.
* Performs injection after construction as well as after activation
* of a passivated bean.
*
* <p>To be applied through an <code>@Interceptors</code> annotation in
* <p>To be applied through an {@code @Interceptors} annotation in
* the EJB Session Bean or Message-Driven Bean class, or through an
* <code>interceptor-binding</code> XML element in the EJB deployment descriptor.
* {@code interceptor-binding} XML element in the EJB deployment descriptor.
*
* <p>Delegates to Spring's {@link AutowiredAnnotationBeanPostProcessor}
* underneath, allowing for customization of its specific settings through
@@ -60,7 +60,7 @@ import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
*
* <p><b>WARNING: Do not define the same bean as Spring-managed bean and as
* EJB3 session bean in the same deployment unit.</b> In particular, be
* careful when using the <code>&lt;context:component-scan&gt;</code> feature
* careful when using the {@code &lt;context:component-scan&gt;} feature
* in combination with the deployment of Spring-based EJB3 session beans:
* Make sure that the EJB3 session beans are <i>not</i> autodetected as
* Spring-managed beans as well, using appropriate package restrictions.
@@ -71,8 +71,6 @@ import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
* @see org.springframework.context.access.ContextSingletonBeanFactoryLocator
* @see #getBeanFactoryLocatorKey
* @see org.springframework.ejb.support.AbstractEnterpriseBean#setBeanFactoryLocator
* @see org.springframework.ejb.support.AbstractEnterpriseBean#setBeanFactoryLocatorKey
*/
public class SpringBeanAutowiringInterceptor {
@@ -99,9 +97,15 @@ public class SpringBeanAutowiringInterceptor {
invocationContext.proceed();
}
catch (RuntimeException ex) {
doReleaseBean(invocationContext.getTarget());
throw ex;
}
catch (Error err) {
doReleaseBean(invocationContext.getTarget());
throw err;
}
catch (Exception ex) {
doReleaseBean(invocationContext.getTarget());
// Cannot declare a checked exception on WebSphere here - so we need to wrap.
throw new EJBException(ex);
}
@@ -130,7 +134,7 @@ public class SpringBeanAutowiringInterceptor {
/**
* Determine the BeanFactory for autowiring the given target bean.
* @param target the target bean to autowire
* @return the BeanFactory to use (never <code>null</code>)
* @return the BeanFactory to use (never {@code null})
* @see #getBeanFactoryReference
*/
protected BeanFactory getBeanFactory(Object target) {
@@ -146,7 +150,7 @@ public class SpringBeanAutowiringInterceptor {
* <p>The default implementation delegates to {@link #getBeanFactoryLocator}
* and {@link #getBeanFactoryLocatorKey}.
* @param target the target bean to autowire
* @return the BeanFactoryReference to use (never <code>null</code>)
* @return the BeanFactoryReference to use (never {@code null})
* @see #getBeanFactoryLocator
* @see #getBeanFactoryLocatorKey
* @see org.springframework.beans.factory.access.BeanFactoryLocator#useBeanFactory(String)
@@ -163,7 +167,7 @@ public class SpringBeanAutowiringInterceptor {
* <p>The default implementation exposes Spring's default
* {@link ContextSingletonBeanFactoryLocator}.
* @param target the target bean to autowire
* @return the BeanFactoryLocator to use (never <code>null</code>)
* @return the BeanFactoryLocator to use (never {@code null})
* @see org.springframework.context.access.ContextSingletonBeanFactoryLocator#getInstance()
*/
protected BeanFactoryLocator getBeanFactoryLocator(Object target) {
@@ -174,11 +178,11 @@ public class SpringBeanAutowiringInterceptor {
* Determine the BeanFactoryLocator key to use. This typically indicates
* the bean name of the ApplicationContext definition in
* <strong>classpath*:beanRefContext.xml</strong> resource files.
* <p>The default is <code>null</code>, indicating the single
* <p>The default is {@code null}, indicating the single
* ApplicationContext defined in the locator. This must be overridden
* if more than one shared ApplicationContext definition is available.
* @param target the target bean to autowire
* @return the BeanFactoryLocator key to use (or <code>null</code> for
* @return the BeanFactoryLocator key to use (or {@code null} for
* referring to the single ApplicationContext defined in the locator)
*/
protected String getBeanFactoryLocatorKey(Object target) {
@@ -3,20 +3,20 @@
*
* <p>Base classes to make implementing EJB 2.x beans simpler and less error-prone,
* as well as guaranteeing a Spring BeanFactory is available to such EJBs.
* This promotes good practice, with EJB services used for transaction
* This promotes good EJB practice, with EJB services used for transaction
* management, thread management, and (possibly) remoting, while
* business logic is implemented in easily testable POJOs.</p>
*
*
* <p>In this model, the EJB is a facade, with as many POJO helpers
* behind the BeanFactory as required.</p>
*
* <p>Note that the default behavior is to look for an EJB enviroment variable
*
* <p>Note that the default behavior is to look for an EJB environment variable
* with name <code>ejb/BeanFactoryPath</code> that specifies the
* location <i>on the classpath</i> of an XML bean factory definition
* file (such as <code>/com/mycom/mypackage/mybeans.xml</code>).
* If this JNDI key is missing, your EJB subclass won't successfully
* initialize in the container.</p>
*
*
* <p><b>Check out the <code>org.springframework.ejb.interceptor</code>
* package for equivalent support for the EJB 3 component model</b>,
* providing annotation-based autowiring using an EJB 3 interceptor.</p>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* 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.
@@ -24,12 +24,15 @@ import org.springframework.util.ClassUtils;
/**
* {@link LoadTimeWeaver} implementation for OC4J's instrumentable ClassLoader.
*
* <p><b>NOTE:</b> Requires Oracle OC4J version 10.1.3.1 or higher.
* Requires Oracle OC4J version 10.1.3.1 or higher.
*
* <p>Many thanks to <a href="mailto:mike.keith@oracle.com">Mike Keith</a>
* for his assistance.
*
* <p><b>NOTE:</b> This class will be deprecated as of Spring 3.2, in favor of
* {@link org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver}
* since Oracle end-of-lifed OC4J in favor of WebLogic.
*
* @author Costin Leau
* @author Juergen Hoeller
* @since 2.0
@@ -38,10 +41,11 @@ public class OC4JLoadTimeWeaver implements LoadTimeWeaver {
private final OC4JClassLoaderAdapter classLoader;
/**
* Creates a new instance of thie {@link OC4JLoadTimeWeaver} class
* using the default {@link ClassLoader class loader}.
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
*/
public OC4JLoadTimeWeaver() {
this(ClassUtils.getDefaultClassLoader());
@@ -57,18 +61,20 @@ public class OC4JLoadTimeWeaver implements LoadTimeWeaver {
this.classLoader = new OC4JClassLoaderAdapter(classLoader);
}
public void addTransformer(ClassFileTransformer transformer) {
Assert.notNull(transformer, "Transformer must not be null");
// Since OC4J 10.1.3's PolicyClassLoader is going to be removed,
// we rely on the ClassLoaderUtilities API instead.
classLoader.addTransformer(transformer);
this.classLoader.addTransformer(transformer);
}
public ClassLoader getInstrumentableClassLoader() {
return classLoader.getClassLoader();
return this.classLoader.getClassLoader();
}
public ClassLoader getThrowawayClassLoader() {
return classLoader.getThrowawayClassLoader();
return this.classLoader.getThrowawayClassLoader();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 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,6 +16,7 @@
package org.springframework.jmx.support;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
@@ -92,19 +93,19 @@ public class MBeanRegistrationSupport {
private static final Constants constants = new Constants(MBeanRegistrationSupport.class);
/**
* <code>Log</code> instance for this class.
* {@code Log} instance for this class.
*/
protected final Log logger = LogFactory.getLog(getClass());
/**
* The <code>MBeanServer</code> instance being used to register beans.
* The {@code MBeanServer} instance being used to register beans.
*/
protected MBeanServer server;
/**
* The beans that have been registered by this exporter.
*/
protected final Set<ObjectName> registeredBeans = new LinkedHashSet<ObjectName>();
protected final Set<ObjectName> registeredBeans = Collections.synchronizedSet(new LinkedHashSet<ObjectName>());
/**
* The action take when registering an MBean and finding that it already exists.
@@ -114,16 +115,16 @@ public class MBeanRegistrationSupport {
/**
* Specify the <code>MBeanServer</code> instance with which all beans should
* be registered. The <code>MBeanExporter</code> will attempt to locate an
* existing <code>MBeanServer</code> if none is supplied.
* Specify the {@code MBeanServer} instance with which all beans should
* be registered. The {@code MBeanExporter} will attempt to locate an
* existing {@code MBeanServer} if none is supplied.
*/
public void setServer(MBeanServer server) {
this.server = server;
}
/**
* Return the <code>MBeanServer</code> that the beans will be registered with.
* Return the {@code MBeanServer} that the beans will be registered with.
*/
public final MBeanServer getServer() {
return this.server;
@@ -205,10 +206,9 @@ public class MBeanRegistrationSupport {
* Unregisters all beans that have been registered by an instance of this class.
*/
protected void unregisterBeans() {
for (ObjectName objectName : this.registeredBeans) {
for (ObjectName objectName : new LinkedHashSet<ObjectName>(this.registeredBeans)) {
doUnregister(objectName);
}
this.registeredBeans.clear();
}
/**
@@ -234,6 +234,7 @@ public class MBeanRegistrationSupport {
logger.error("Could not unregister MBean [" + objectName + "]", ex);
}
}
this.registeredBeans.remove(objectName);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 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,7 +19,7 @@ package org.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
@@ -54,7 +54,7 @@ import org.springframework.util.ReflectionUtils;
* Spring's unchecked RemoteAccessException.
*
* <p>The JNDI environment can be specified as "jndiEnvironment" property,
* or be configured in a <code>jndi.properties</code> file or as system properties.
* or be configured in a {@code jndi.properties} file or as system properties.
* For example:
*
* <pre class="code">&lt;property name="jndiEnvironment"&gt;
@@ -88,6 +88,8 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
private boolean refreshStubOnConnectFailure = false;
private boolean exposeAccessContext = false;
private Object cachedStub;
private final Object stubMonitor = new Object();
@@ -166,6 +168,18 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
this.refreshStubOnConnectFailure = refreshStubOnConnectFailure;
}
/**
* Set whether to expose the JNDI environment context for all access to the target
* RMI stub, i.e. for all method invocations on the exposed object reference.
* <p>Default is "false", i.e. to only expose the JNDI context for object lookup.
* Switch this flag to "true" in order to expose the JNDI environment (including
* the authorization context) for each RMI invocation, as needed by WebLogic
* for RMI stubs with authorization requirements.
*/
public void setExposeAccessContext(boolean exposeAccessContext) {
this.exposeAccessContext = exposeAccessContext;
}
@Override
public void afterPropertiesSet() throws NamingException {
@@ -190,8 +204,8 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
else if (getServiceInterface() != null) {
boolean isImpl = getServiceInterface().isInstance(remoteObj);
logger.debug("Using service interface [" + getServiceInterface().getName() +
"] for JNDI RMI object [" + getJndiName() + "] - " +
(!isImpl ? "not " : "") + "directly implemented");
"] for JNDI RMI object [" + getJndiName() + "] - " +
(!isImpl ? "not " : "") + "directly implemented");
}
}
if (this.cacheStub) {
@@ -268,13 +282,15 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
* @see java.rmi.NoSuchObjectException
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Object stub = null;
Object stub;
try {
stub = getStub();
}
catch (NamingException ex) {
throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex);
}
Context ctx = (this.exposeAccessContext ? getJndiTemplate().getContext() : null);
try {
return doInvoke(invocation, stub);
}
@@ -297,6 +313,9 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
throw ex;
}
}
finally {
getJndiTemplate().releaseContext(ctx);
}
}
/**
@@ -354,7 +373,7 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
* @see #invoke
*/
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
Object freshStub = null;
Object freshStub;
synchronized (this.stubMonitor) {
this.cachedStub = null;
freshStub = lookupStub();
@@ -426,7 +445,7 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
* @see org.springframework.remoting.support.RemoteInvocation
*/
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "RMI invoker proxy for service URL [" + getJndiName() + "]";
@@ -52,6 +52,39 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mode" default="proxy">
<xsd:annotation>
<xsd:documentation><![CDATA[
Should annotated beans be proxied using Spring's AOP framework,
or should they rather be weaved with an AspectJ async execution aspect?
AspectJ weaving requires spring-aspects.jar on the classpath,
as well as load-time weaving (or compile-time weaving) enabled.
Note: The weaving-based aspect requires the @Async annotation to be
defined on the concrete class. Annotations in interfaces will not work
in that case (they will rather only work with interface-based proxies)!
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="proxy"/>
<xsd:enumeration value="aspectj"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Are class-based (CGLIB) proxies to be created? By default, standard
Java interface-based proxies are created.
Note: Class-based proxies require the @Async annotation to be defined
on the concrete class. Annotations in interfaces will not work in
that case (they will rather only work with interface-based proxies)!
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
@@ -35,7 +35,7 @@ import org.springframework.util.ReflectionUtils;
/**
* @author Costin Leau
*/
public class AnnotationCacheOperationSourceTest {
public class AnnotationCacheOperationSourceTests {
private AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
@@ -25,10 +25,14 @@ import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor;
import org.springframework.util.Assert;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
@@ -77,6 +81,24 @@ public class ImportAwareTests {
assertThat(foo, is("xyz"));
}
@Test
public void importRegistrar() throws Exception {
ImportedRegistrar.called = false;
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ImportingRegistrarConfig.class);
ctx.refresh();
assertNotNull(ctx.getBean("registrarImportedBean"));
}
@Test
public void importRegistrarWithImport() throws Exception {
ImportedRegistrar.called = false;
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ImportingRegistrarConfigWithImport.class);
ctx.refresh();
assertNotNull(ctx.getBean("registrarImportedBean"));
assertNotNull(ctx.getBean(ImportedConfig.class));
}
@Configuration
@Import(ImportedConfig.class)
@@ -131,4 +153,35 @@ public class ImportAwareTests {
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
}
}
@Configuration
@EnableImportRegistrar
static class ImportingRegistrarConfig {
}
@Configuration
@EnableImportRegistrar
@Import(ImportedConfig.class)
static class ImportingRegistrarConfigWithImport {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ImportedRegistrar.class)
public @interface EnableImportRegistrar {
}
static class ImportedRegistrar implements ImportBeanDefinitionRegistrar {
static boolean called;
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName(String.class.getName());
registry.registerBeanDefinition("registrarImportedBean", beanDefinition );
Assert.state(called == false, "ImportedRegistrar called twice");
called = 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.
@@ -115,8 +115,8 @@ public class ResourceBundleMessageSourceTests extends TestCase {
if (alwaysUseMessageFormat) {
pvs.add("alwaysUseMessageFormat", Boolean.TRUE);
}
Class clazz = reloadable ?
(Class) ReloadableResourceBundleMessageSource.class : ResourceBundleMessageSource.class;
Class<?> clazz = reloadable ?
(Class<?>) ReloadableResourceBundleMessageSource.class : ResourceBundleMessageSource.class;
ac.registerSingleton("messageSource", clazz, pvs);
ac.refresh();
@@ -340,6 +340,17 @@ public class ResourceBundleMessageSourceTests extends TestCase {
assertEquals(0, filenames.size());
}
public void testMessageSourceResourceBundle() {
ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
ms.setBasename("org/springframework/context/support/messages");
MessageSourceResourceBundle rbe = new MessageSourceResourceBundle(ms, Locale.ENGLISH);
assertEquals("message1", rbe.getString("code1"));
assertTrue(rbe.containsKey("code1"));
MessageSourceResourceBundle rbg = new MessageSourceResourceBundle(ms, Locale.GERMAN);
assertEquals("nachricht2", rbg.getString("code2"));
assertTrue(rbg.containsKey("code2"));
}
@Override
protected void tearDown() throws Exception {
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_16) {
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -91,7 +90,7 @@ public abstract class BridgeMethodResolver {
* Searches for the bridged method in the given candidates.
* @param candidateMethods the List of candidate Methods
* @param bridgeMethod the bridge method
* @return the bridged method, or <code>null</code> if none found
* @return the bridged method, or {@code null} if none found
*/
private static Method searchCandidates(List<Method> candidateMethods, Method bridgeMethod) {
if (candidateMethods.isEmpty()) {
@@ -114,7 +113,7 @@ public abstract class BridgeMethodResolver {
}
/**
* Returns <code>true</code> if the supplied '<code>candidateMethod</code>' can be
* Returns {@code true} if the supplied '{@code candidateMethod}' can be
* consider a validate candidate for the {@link Method} that is {@link Method#isBridge() bridged}
* by the supplied {@link Method bridge Method}. This method performs inexpensive
* checks and can be used quickly filter for a set of possible matches.
@@ -145,7 +144,7 @@ public abstract class BridgeMethodResolver {
private static Method findGenericDeclaration(Method bridgeMethod) {
// Search parent types for method that has same signature as bridge.
Class superclass = bridgeMethod.getDeclaringClass().getSuperclass();
while (!Object.class.equals(superclass)) {
while (superclass != null && !Object.class.equals(superclass)) {
Method method = searchForMatch(superclass, bridgeMethod);
if (method != null && !method.isBridge()) {
return method;
@@ -166,10 +165,10 @@ public abstract class BridgeMethodResolver {
}
/**
* Returns <code>true</code> if the {@link Type} signature of both the supplied
* Returns {@code true} if the {@link Type} signature of both the supplied
* {@link Method#getGenericParameterTypes() generic Method} and concrete {@link Method}
* are equal after resolving all {@link TypeVariable TypeVariables} using the supplied
* TypeVariable Map, otherwise returns <code>false</code>.
* TypeVariable Map, otherwise returns {@code false}.
*/
private static boolean isResolvedTypeMatch(
Method genericMethod, Method candidateMethod, Map<TypeVariable, Type> typeVariableMap) {
@@ -205,7 +204,7 @@ public abstract class BridgeMethodResolver {
/**
* If the supplied {@link Class} has a declared {@link Method} whose signature matches
* that of the supplied {@link Method}, then this matching {@link Method} is returned,
* otherwise <code>null</code> is returned.
* otherwise {@code null} is returned.
*/
private static Method searchForMatch(Class type, Method bridgeMethod) {
return ReflectionUtils.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes());
@@ -219,8 +218,6 @@ public abstract class BridgeMethodResolver {
* @return whether signatures match as described
*/
public static boolean isVisibilityBridgeMethodPair(Method bridgeMethod, Method bridgedMethod) {
Assert.isTrue(bridgeMethod != null);
Assert.isTrue(bridgedMethod != null);
if (bridgeMethod == bridgedMethod) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,12 +39,11 @@ import org.springframework.util.ClassUtils;
/**
* Implementation of {@link ParameterNameDiscoverer} that uses the LocalVariableTable
* information in the method attributes to discover parameter names. Returns
* <code>null</code> if the class file was compiled without debug information.
* {@code null} if the class file was compiled without debug information.
*
* <p>Uses ObjectWeb's ASM library for analyzing class files. Each discoverer
* instance caches the ASM discovered information for each introspected Class, in a
* thread-safe manner. It is recommended to reuse discoverer instances
* as far as possible.
* <p>Uses ObjectWeb's ASM library for analyzing class files. Each discoverer instance
* caches the ASM discovered information for each introspected Class, in a thread-safe
* manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
*
* @author Adrian Colyer
* @author Costin Leau
@@ -64,15 +63,15 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
public String[] getParameterNames(Method method) {
Class<?> declaringClass = method.getDeclaringClass();
Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
Class<?> declaringClass = originalMethod.getDeclaringClass();
Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);
if (map == null) {
// initialize cache
map = inspectClass(declaringClass);
this.parameterNamesCache.put(declaringClass, map);
}
if (map != NO_DEBUG_INFO_MAP) {
return map.get(method);
return map.get(originalMethod);
}
return null;
}
@@ -82,14 +81,12 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
Class<?> declaringClass = ctor.getDeclaringClass();
Map<Member, String[]> map = this.parameterNamesCache.get(declaringClass);
if (map == null) {
// initialize cache
map = inspectClass(declaringClass);
this.parameterNamesCache.put(declaringClass, map);
}
if (map != NO_DEBUG_INFO_MAP) {
return map.get(ctor);
}
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -269,7 +269,6 @@ public class MethodParameter {
* @param annotationType the annotation type to look for
* @return the annotation object, or <code>null</code> if not found
*/
@SuppressWarnings("unchecked")
public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType) {
return getAnnotatedElement().getAnnotation(annotationType);
}
@@ -311,14 +310,14 @@ public class MethodParameter {
* Return true if the parameter has at least one annotation, false if it has none.
*/
public boolean hasParameterAnnotations() {
return getParameterAnnotations().length != 0;
return (getParameterAnnotations().length != 0);
}
/**
* Return true if the parameter has the given annotation type, and false if it doesn't.
*/
public <T extends Annotation> boolean hasParameterAnnotation(Class<T> annotationType) {
return getParameterAnnotation(annotationType) != null;
return (getParameterAnnotation(annotationType) != null);
}
/**
@@ -417,6 +416,38 @@ public class MethodParameter {
return this.typeIndexesPerLevel;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof MethodParameter) {
MethodParameter other = (MethodParameter) obj;
if (this.parameterIndex != other.parameterIndex) {
return false;
}
else if (this.getMember().equals(other.getMember())) {
return true;
}
else {
return false;
}
}
return false;
}
@Override
public int hashCode() {
int result = this.hash;
if (result == 0) {
result = getMember().hashCode();
result = 31 * result + this.parameterIndex;
this.hash = result;
}
return result;
}
/**
* Create a new MethodParameter for the given method or constructor.
@@ -439,37 +470,4 @@ public class MethodParameter {
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof MethodParameter) {
MethodParameter other = (MethodParameter) obj;
if (this.parameterIndex != other.parameterIndex) {
return false;
}
else if (this.getMember().equals(other.getMember())) {
return true;
}
else {
return false;
}
}
return false;
}
@Override
public int hashCode() {
int result = this.hash;
if (result == 0) {
result = getMember().hashCode();
result = 31 * result + this.parameterIndex;
this.hash = result;
}
return result;
}
}
@@ -30,15 +30,15 @@ import org.springframework.util.StringUtils;
* {@link Resource} implementation for class path resources.
* Uses either a given ClassLoader or a given Class for loading resources.
*
* <p>Supports resolution as <code>java.io.File</code> if the class path
* <p>Supports resolution as {@code java.io.File} if the class path
* resource resides in the file system, but not for resources in a JAR.
* Always supports resolution as URL.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 28.12.2003
* @see java.lang.ClassLoader#getResourceAsStream(String)
* @see java.lang.Class#getResourceAsStream(String)
* @see ClassLoader#getResourceAsStream(String)
* @see Class#getResourceAsStream(String)
*/
public class ClassPathResource extends AbstractFileResolvingResource {
@@ -69,8 +69,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
* resource access methods will not accept it.
* @param path the absolute path within the classpath
* @param classLoader the class loader to load the resource with,
* or <code>null</code> for the thread context class loader
* @see java.lang.ClassLoader#getResourceAsStream(String)
* or {@code null} for the thread context class loader
* @see ClassLoader#getResourceAsStream(String)
*/
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
@@ -205,18 +205,14 @@ public class ClassPathResource extends AbstractFileResolvingResource {
*/
public String getDescription() {
StringBuilder builder = new StringBuilder("class path resource [");
String pathToUse = path;
if (this.clazz != null && !pathToUse.startsWith("/")) {
builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
builder.append('/');
}
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
builder.append(pathToUse);
builder.append(']');
return builder.toString();
@@ -232,9 +228,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
if (obj instanceof ClassPathResource) {
ClassPathResource otherRes = (ClassPathResource) obj;
return (this.path.equals(otherRes.path)
&& ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) && ObjectUtils.nullSafeEquals(
this.clazz, otherRes.clazz));
return (this.path.equals(otherRes.path) &&
ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&
ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));
}
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,11 @@ import org.springframework.util.StringUtils;
/**
* Subclass of {@link PropertiesPropertySource} that loads a {@link Properties}
* object from a given {@link org.springframework.core.io.Resource} or resource location such as
* {@code "classpath:/com/myco/foo.properties"} or {@code "file:/path/to/file.properties"}.
* {@code "classpath:/com/myco/foo.properties"} or {@code "file:/path/to/file.xml"}.
* Both traditional and XML-based properties file formats are supported, however in order
* for XML processing to take effect, the underlying {@code Resource}'s
* {@link org.springframework.core.io.Resource#getFilename() getFilename()} method must
* return non-{@code null} and end in ".xml".
*
* @author Chris Beams
* @since 3.1
@@ -99,7 +103,13 @@ public class ResourcePropertySource extends PropertiesPropertySource {
private static Properties loadPropertiesForResource(Resource resource) throws IOException {
Properties props = new Properties();
InputStream is = resource.getInputStream();
props.load(is);
String filename = resource.getFilename();
if (filename != null && filename.endsWith(".xml")) {
props.loadFromXML(is);
}
else {
props.load(is);
}
try {
is.close();
} catch (IOException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* 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.
@@ -40,7 +40,7 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
private final Map<Resource, MetadataReader> classReaderCache =
private final Map<Resource, MetadataReader> metadataReaderCache =
new LinkedHashMap<Resource, MetadataReader>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {
@@ -95,11 +95,11 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
if (getCacheLimit() <= 0) {
return super.getMetadataReader(resource);
}
synchronized (this.classReaderCache) {
MetadataReader metadataReader = this.classReaderCache.get(resource);
synchronized (this.metadataReaderCache) {
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
metadataReader = super.getMetadataReader(resource);
this.classReaderCache.put(resource, metadataReader);
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -21,14 +21,14 @@ package org.springframework.util;
* errors that occur during asynchronous execution of tasks that have been
* submitted to a TaskScheduler. In such cases, it may not be possible to
* throw the error to the original caller.
*
*
* @author Mark Fisher
* @since 3.0.
* @since 3.0
*/
public interface ErrorHandler {
/**
* Handle the given error, possibly rethrowing it as a fatal exception
* Handle the given error, possibly rethrowing it as a fatal exception.
*/
void handleError(Throwable t);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -34,6 +34,7 @@ public class MethodParameterTests {
private MethodParameter intReturnType;
@Before
public void setUp() throws NoSuchMethodException {
Method method = getClass().getMethod("method", String.class, Long.TYPE);
@@ -42,8 +43,6 @@ public class MethodParameterTests {
intReturnType = new MethodParameter(method, -1);
}
@Test
public void testEquals() throws NoSuchMethodException {
assertEquals(stringParameter, stringParameter);
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties version="1.0">
<entry key="foo">bar</entry>
</properties>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,10 @@ public class ResourcePropertySourceTests {
private static final String PROPERTIES_LOCATION = "classpath:" + PROPERTIES_PATH;
private static final String PROPERTIES_RESOURCE_DESCRIPTION = "class path resource [" + PROPERTIES_PATH + "]";
private static final String XML_PROPERTIES_PATH = "org/springframework/core/io/example.xml";
private static final String XML_PROPERTIES_LOCATION = "classpath:" + XML_PROPERTIES_PATH;
private static final String XML_PROPERTIES_RESOURCE_DESCRIPTION = "class path resource [" + XML_PROPERTIES_PATH + "]";
@Test
public void withLocationAndGeneratedName() throws IOException {
PropertySource<?> ps = new ResourcePropertySource(PROPERTIES_LOCATION);
@@ -46,6 +50,13 @@ public class ResourcePropertySourceTests {
assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION));
}
@Test
public void xmlWithLocationAndGeneratedName() throws IOException {
PropertySource<?> ps = new ResourcePropertySource(XML_PROPERTIES_LOCATION);
assertEquals(ps.getProperty("foo"), "bar");
assertThat(ps.getName(), is(XML_PROPERTIES_RESOURCE_DESCRIPTION));
}
@Test
public void withLocationAndExplicitName() throws IOException {
PropertySource<?> ps = new ResourcePropertySource("ps1", PROPERTIES_LOCATION);
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -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.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -36,11 +38,13 @@ import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* Simple PropertyAccessor that uses reflection to access properties for reading and writing. A property can be accessed
* if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written).
*
* Simple PropertyAccessor that uses reflection to access properties for reading and writing.
* A property can be accessed if it is accessible as a field on the object or through a
* getter (if being read) or a setter (if being written).
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Phillip Webb
* @since 3.0
*/
public class ReflectivePropertyAccessor implements PropertyAccessor {
@@ -48,7 +52,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
protected final Map<CacheKey, InvokerPair> readerCache = new ConcurrentHashMap<CacheKey, InvokerPair>();
protected final Map<CacheKey, Member> writerCache = new ConcurrentHashMap<CacheKey, Member>();
protected final Map<CacheKey, TypeDescriptor> typeDescriptorCache = new ConcurrentHashMap<CacheKey, TypeDescriptor>();
@@ -85,7 +89,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
Field field = findField(name, type, target);
if (field != null) {
TypeDescriptor typeDescriptor = new TypeDescriptor(field);
this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor));
this.readerCache.put(cacheKey, new InvokerPair(field, typeDescriptor));
this.typeDescriptorCache.put(cacheKey, typeDescriptor);
return true;
}
@@ -252,7 +256,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
throw new AccessException("Neither setter nor field found for property '" + name + "'");
}
private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) {
if (target == null) {
return null;
@@ -263,15 +267,15 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return TypeDescriptor.valueOf(Integer.TYPE);
}
CacheKey cacheKey = new CacheKey(type, name);
TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey);
TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey);
if (typeDescriptor == null) {
// attempt to populate the cache entry
try {
if (canRead(context, target, name)) {
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
}
else if (canWrite(context, target, name)) {
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
typeDescriptor = this.typeDescriptorCache.get(cacheKey);
}
}
catch (AccessException ex) {
@@ -283,7 +287,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private Method findGetterForProperty(String propertyName, Class<?> clazz, Object target) {
Method method = findGetterForProperty(propertyName, clazz, target instanceof Class);
if(method == null && target instanceof Class) {
if (method == null && target instanceof Class) {
method = findGetterForProperty(propertyName, target.getClass(), false);
}
return method;
@@ -291,7 +295,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private Method findSetterForProperty(String propertyName, Class<?> clazz, Object target) {
Method method = findSetterForProperty(propertyName, clazz, target instanceof Class);
if(method == null && target instanceof Class) {
if (method == null && target instanceof Class) {
method = findSetterForProperty(propertyName, target.getClass(), false);
}
return method;
@@ -299,18 +303,19 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
private Field findField(String name, Class<?> clazz, Object target) {
Field field = findField(name, clazz, target instanceof Class);
if(field == null && target instanceof Class) {
if (field == null && target instanceof Class) {
field = findField(name, target.getClass(), false);
}
return field;
}
/**
* Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix
* 'get' and the rest of the name is the same as the property name (with the first character uppercased).
* Find a getter method for the specified property.
* <p>A getter is defined as a method whose name start with the prefix 'get' and the
* rest of the name is the same as the property name (with the first character uppercased).
*/
protected Method findGetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
Method[] ms = clazz.getMethods();
Method[] ms = getSortedClassMethods(clazz);
// Try "get*" method...
String getterName = "get" + StringUtils.capitalize(propertyName);
for (Method method : ms) {
@@ -323,7 +328,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
getterName = "is" + StringUtils.capitalize(propertyName);
for (Method method : ms) {
if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 &&
boolean.class.equals(method.getReturnType()) &&
(boolean.class.equals(method.getReturnType()) || Boolean.class.equals(method.getReturnType())) &&
(!mustBeStatic || Modifier.isStatic(method.getModifiers()))) {
return method;
}
@@ -335,7 +340,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
* Find a setter method for the specified property.
*/
protected Method findSetterForProperty(String propertyName, Class<?> clazz, boolean mustBeStatic) {
Method[] methods = clazz.getMethods();
Method[] methods = getSortedClassMethods(clazz);
String setterName = "set" + StringUtils.capitalize(propertyName);
for (Method method : methods) {
if (method.getName().equals(setterName) && method.getParameterTypes().length == 1 &&
@@ -346,6 +351,19 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return null;
}
/**
* Returns class methods ordered with non bridge methods appearing higher.
*/
private Method[] getSortedClassMethods(Class<?> clazz) {
Method[] methods = clazz.getMethods();
Arrays.sort(methods, new Comparator<Method>() {
public int compare(Method o1, Method o2) {
return (o1.isBridge() == o2.isBridge()) ? 0 : (o1.isBridge() ? 1 : -1);
}
});
return methods;
}
/**
* Find a field of a certain name on a specified class
*/
@@ -356,58 +374,26 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return field;
}
}
// We'll search superclasses and implemented interfaces explicitly,
// although it shouldn't be necessary - however, see SPR-10125.
if (clazz.getSuperclass() != null) {
Field field = findField(name, clazz.getSuperclass(), mustBeStatic);
if (field != null) {
return field;
}
}
for (Class<?> implementedInterface : clazz.getInterfaces()) {
Field field = findField(name, implementedInterface, mustBeStatic);
if (field != null) {
return field;
}
}
return null;
}
/**
* Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the
* value returned by the reflective call.
*/
private static class InvokerPair {
final Member member;
final TypeDescriptor typeDescriptor;
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
this.member = member;
this.typeDescriptor = typeDescriptor;
}
}
private static class CacheKey {
private final Class clazz;
private final String name;
public CacheKey(Class clazz, String name) {
this.clazz = clazz;
this.name = name;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CacheKey)) {
return false;
}
CacheKey otherKey = (CacheKey) other;
return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name));
}
@Override
public int hashCode() {
return this.clazz.hashCode() * 29 + this.name.hashCode();
}
}
/**
* Attempt to create an optimized property accessor tailored for a property of a particular name on
* a particular class. The general ReflectivePropertyAccessor will always work but is not optimal
* a particular class. The general ReflectivePropertyAccessor will always work but is not optimal
* due to the need to lookup which reflective member (method/field) to use each time read() is called.
* This method will just return the ReflectivePropertyAccessor instance if it is unable to build
* something more optimal.
@@ -456,37 +442,90 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
}
return this;
}
/**
* An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property
* on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that
* may be invoked to access different properties on different classes. This optimal accessor exists because looking up
* the appropriate reflective object by class/name on each read is not cheap.
* Captures the member (method/field) to call reflectively to access a property value
* and the type descriptor for the value returned by the reflective call.
*/
static class OptimalPropertyAccessor implements PropertyAccessor {
private static class InvokerPair {
final Member member;
final TypeDescriptor typeDescriptor;
public InvokerPair(Member member, TypeDescriptor typeDescriptor) {
this.member = member;
this.typeDescriptor = typeDescriptor;
}
}
private static class CacheKey {
private final Class clazz;
private final String name;
public CacheKey(Class clazz, String name) {
this.clazz = clazz;
this.name = name;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CacheKey)) {
return false;
}
CacheKey otherKey = (CacheKey) other;
return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name));
}
@Override
public int hashCode() {
return this.clazz.hashCode() * 29 + this.name.hashCode();
}
}
/**
* An optimized form of a PropertyAccessor that will use reflection but only knows
* how to access a particular property on a particular class. This is unlike the
* general ReflectivePropertyResolver which manages a cache of methods/fields that
* may be invoked to access different properties on different classes. This optimal
* accessor exists because looking up the appropriate reflective object by class/name
* on each read is not cheap.
*/
private static class OptimalPropertyAccessor implements PropertyAccessor {
private final Member member;
private final TypeDescriptor typeDescriptor;
private final boolean needsToBeMadeAccessible;
OptimalPropertyAccessor(InvokerPair target) {
this.member = target.member;
this.member = target.member;
this.typeDescriptor = target.typeDescriptor;
if (this.member instanceof Field) {
Field field = (Field)member;
needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()))
&& !field.isAccessible();
Field field = (Field) this.member;
this.needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) ||
!Modifier.isPublic(field.getDeclaringClass().getModifiers())) && !field.isAccessible();
}
else {
Method method = (Method)member;
needsToBeMadeAccessible = ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible());
Method method = (Method) this.member;
this.needsToBeMadeAccessible = ((!Modifier.isPublic(method.getModifiers()) ||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible());
}
}
public Class[] getSpecificTargetClasses() {
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
}
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
if (target == null) {
return false;
@@ -495,8 +534,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (type.isArray()) {
return false;
}
if (member instanceof Method) {
Method method = (Method)member;
if (this.member instanceof Method) {
Method method = (Method) this.member;
String getterName = "get" + StringUtils.capitalize(name);
if (getterName.equals(method.getName())) {
return true;
@@ -505,31 +544,31 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
return getterName.equals(method.getName());
}
else {
Field field = (Field)member;
Field field = (Field) this.member;
return field.getName().equals(name);
}
}
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
if (member instanceof Method) {
if (this.member instanceof Method) {
try {
if (needsToBeMadeAccessible) {
ReflectionUtils.makeAccessible((Method) member);
if (this.needsToBeMadeAccessible) {
ReflectionUtils.makeAccessible((Method) this.member);
}
Object value = ((Method) member).invoke(target);
return new TypedValue(value, typeDescriptor.narrow(value));
Object value = ((Method) this.member).invoke(target);
return new TypedValue(value, this.typeDescriptor.narrow(value));
}
catch (Exception ex) {
throw new AccessException("Unable to access property '" + name + "' through getter", ex);
}
}
if (member instanceof Field) {
}
if (this.member instanceof Field) {
try {
if (needsToBeMadeAccessible) {
ReflectionUtils.makeAccessible((Field)member);
if (this.needsToBeMadeAccessible) {
ReflectionUtils.makeAccessible((Field) this.member);
}
Object value = ((Field)member).get(target);
return new TypedValue(value, typeDescriptor.narrow(value));
Object value = ((Field) this.member).get(target);
return new TypedValue(value, this.typeDescriptor.narrow(value));
}
catch (Exception ex) {
throw new AccessException("Unable to access field: " + name, ex);
@@ -538,12 +577,11 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
throw new AccessException("Neither getter nor field found for property '" + name + "'");
}
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
public boolean canWrite(EvaluationContext context, Object target, String name) {
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
}
public void write(EvaluationContext context, Object target, String name, Object newValue)
throws AccessException {
public void write(EvaluationContext context, Object target, String name, Object newValue) {
throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor");
}
}
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-instrument-tomcat</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -431,11 +431,11 @@
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.1.GA/com.springsource.org.hibernate-3.3.1.GA.jar!/" />
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.2.GA/com.springsource.org.hibernate-3.3.2.GA.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.1.GA/com.springsource.org.hibernate-sources-3.3.1.GA.jar!/" />
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.2.GA/com.springsource.org.hibernate-sources-3.3.2.GA.jar!/" />
</SOURCES>
</library>
</orderEntry>
@@ -69,7 +69,7 @@
<dependency org="org.eclipse.persistence" name="com.springsource.org.eclipse.persistence" rev="1.0.1" conf="test->compile"/>
<dependency org="org.eclipse.persistence" name="com.springsource.org.eclipse.persistence.jpa" rev="1.0.1" conf="test->compile"/>
<dependency org="org.freemarker" name="com.springsource.freemarker" rev="2.3.15" conf="test->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.3.1.GA" conf="test->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.3.2.GA" conf="test->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.4.0.GA" conf="test->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations.common" rev="3.3.0.ga" conf="test->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.ejb" rev="3.4.0.GA" conf="test->compile"/>
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-integration-tests</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ public class PreparedStatementCreatorFactory {
/** The SQL, which won't change when the parameters change */
private final String sql;
/** List of SqlParameter objects. May not be <code>null</code>. */
/** List of SqlParameter objects. May not be {@code null}. */
private final List<SqlParameter> declaredParameters;
private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
@@ -144,15 +144,15 @@ public class PreparedStatementCreatorFactory {
/**
* Return a new PreparedStatementSetter for the given parameters.
* @param params list of parameters (may be <code>null</code>)
* @param params list of parameters (may be {@code null})
*/
public PreparedStatementSetter newPreparedStatementSetter(List params) {
public PreparedStatementSetter newPreparedStatementSetter(List<?> params) {
return new PreparedStatementCreatorImpl(params != null ? params : Collections.emptyList());
}
/**
* Return a new PreparedStatementSetter for the given parameters.
* @param params the parameter array (may be <code>null</code>)
* @param params the parameter array (may be {@code null})
*/
public PreparedStatementSetter newPreparedStatementSetter(Object[] params) {
return new PreparedStatementCreatorImpl(params != null ? Arrays.asList(params) : Collections.emptyList());
@@ -160,7 +160,7 @@ public class PreparedStatementCreatorFactory {
/**
* Return a new PreparedStatementCreator for the given parameters.
* @param params list of parameters (may be <code>null</code>)
* @param params list of parameters (may be {@code null})
*/
public PreparedStatementCreator newPreparedStatementCreator(List<?> params) {
return new PreparedStatementCreatorImpl(params != null ? params : Collections.emptyList());
@@ -168,7 +168,7 @@ public class PreparedStatementCreatorFactory {
/**
* Return a new PreparedStatementCreator for the given parameters.
* @param params the parameter array (may be <code>null</code>)
* @param params the parameter array (may be {@code null})
*/
public PreparedStatementCreator newPreparedStatementCreator(Object[] params) {
return new PreparedStatementCreatorImpl(params != null ? Arrays.asList(params) : Collections.emptyList());
@@ -178,7 +178,7 @@ public class PreparedStatementCreatorFactory {
* Return a new PreparedStatementCreator for the given parameters.
* @param sqlToUse the actual SQL statement to use (if different from
* the factory's, for example because of named parameter expanding)
* @param params the parameter array (may be <code>null</code>)
* @param params the parameter array (may be {@code null})
*/
public PreparedStatementCreator newPreparedStatementCreator(String sqlToUse, Object[] params) {
return new PreparedStatementCreatorImpl(
@@ -225,7 +225,7 @@ public class PreparedStatementCreatorFactory {
}
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement ps = null;
PreparedStatement ps;
if (generatedKeysColumnNames != null || returnGeneratedKeys) {
try {
if (generatedKeysColumnNames != null) {
@@ -263,7 +263,7 @@ public class PreparedStatementCreatorFactory {
int sqlColIndx = 1;
for (int i = 0; i < this.parameters.size(); i++) {
Object in = this.parameters.get(i);
SqlParameter declaredParameter = null;
SqlParameter declaredParameter;
// SqlParameterValue overrides declared parameter metadata, in particular for
// independence from the declared parameter position in case of named parameters.
if (in instanceof SqlParameterValue) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* 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.
@@ -28,8 +28,8 @@ import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.util.ReflectionUtils;
/**
* ResultSetExtractor implementation that returns a Spring SqlRowSet
* representation for each given ResultSet.
* {@link ResultSetExtractor} implementation that returns a Spring {@link SqlRowSet}
* representation for each given {@link ResultSet}.
*
* <p>The default implementation uses a standard JDBC CachedRowSet underneath.
* This means that JDBC RowSet support needs to be available at runtime:
@@ -88,8 +88,9 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
/**
* Create a new CachedRowSet instance, to be populated by
* the <code>createSqlRowSet</code> implementation.
* <p>The default implementation creates a new instance of
* Sun's <code>com.sun.rowset.CachedRowSetImpl</code> class.
* <p>The default implementation uses JDBC 4.1's RowSetProvider
* when running on JDK 7 or higher, falling back to Sun's
* <code>com.sun.rowset.CachedRowSetImpl</code> class on older JDKs.
* @return a new CachedRowSet instance
* @throws SQLException if thrown by JDBC methods
* @see #createSqlRowSet
@@ -101,6 +102,17 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
return (CachedRowSet) ReflectionUtils.invokeJdbcMethod(createCachedRowSet, rowSetFactory);
}
else {
return SunCachedRowSetFactory.createCachedRowSet();
}
}
/**
* Inner class to avoid a hard dependency on Sun's CachedRowSetImpl class.
*/
private static class SunCachedRowSetFactory {
public static CachedRowSet createCachedRowSet() throws SQLException {
return new CachedRowSetImpl();
}
}
@@ -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.
@@ -93,7 +93,7 @@ public abstract class StatementCreatorUtils {
/**
* Derive a default SQL type from the given Java type.
* @param javaType the Java type to translate
* @return the corresponding SQL type, or <code>null</code> if none found
* @return the corresponding SQL type, or {@code null} if none found
*/
public static int javaTypeToSqlParameterType(Class javaType) {
Integer sqlType = javaTypeToSqlTypeMap.get(javaType);
@@ -233,7 +233,7 @@ public abstract class StatementCreatorUtils {
try {
pmd = ps.getParameterMetaData();
}
catch (AbstractMethodError err) {
catch (Throwable ex) {
// JDBC driver not compliant with JDBC 3.0
// -> proceed with database-specific checks
}
@@ -381,7 +381,7 @@ public abstract class StatementCreatorUtils {
}
/**
* Check whether the given value is a <code>java.util.Date</code>
* Check whether the given value is a {@code java.util.Date}
* (but not one of the JDBC-specific subclasses).
*/
private static boolean isDateValue(Class inValueType) {
@@ -394,7 +394,7 @@ public abstract class StatementCreatorUtils {
/**
* Clean up all resources held by parameter values which were passed to an
* execute method. This is for example important for closing LOB values.
* @param paramValues parameter values supplied. May be <code>null</code>.
* @param paramValues parameter values supplied. May be {@code null}.
* @see DisposableSqlTypeValue#cleanup()
* @see org.springframework.jdbc.core.support.SqlLobValue#cleanup()
*/
@@ -407,7 +407,7 @@ public abstract class StatementCreatorUtils {
/**
* Clean up all resources held by parameter values which were passed to an
* execute method. This is for example important for closing LOB values.
* @param paramValues parameter values supplied. May be <code>null</code>.
* @param paramValues parameter values supplied. May be {@code null}.
* @see DisposableSqlTypeValue#cleanup()
* @see org.springframework.jdbc.core.support.SqlLobValue#cleanup()
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 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.
@@ -109,7 +109,7 @@ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
/**
* This implementation delegates to <code>getConnectionFromDriver</code>,
* This implementation delegates to {@code getConnectionFromDriver},
* using the default username and password of this DataSource.
* @see #getConnectionFromDriver(String, String)
* @see #setUsername
@@ -120,7 +120,7 @@ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
}
/**
* This implementation delegates to <code>getConnectionFromDriver</code>,
* This implementation delegates to {@code getConnectionFromDriver},
* using the given username and password.
* @see #getConnectionFromDriver(String, String)
*/
@@ -139,14 +139,18 @@ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
* @see java.sql.Driver#connect(String, java.util.Properties)
*/
protected Connection getConnectionFromDriver(String username, String password) throws SQLException {
Properties props = new Properties(getConnectionProperties());
Properties mergedProps = new Properties();
Properties connProps = getConnectionProperties();
if (connProps != null) {
mergedProps.putAll(connProps);
}
if (username != null) {
props.setProperty("user", username);
mergedProps.setProperty("user", username);
}
if (password != null) {
props.setProperty("password", password);
mergedProps.setProperty("password", password);
}
return getConnectionFromDriver(props);
return getConnectionFromDriver(mergedProps);
}
/**
@@ -118,10 +118,10 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
}
/**
* Flag to indicate that a failed SQL <code>DROP</code> statement can be ignored.
* Flag to indicate that a failed SQL {@code DROP} statement can be ignored.
* <p>This is useful for non-embedded databases whose SQL dialect does not support an
* <code>IF EXISTS</code> clause in a <code>DROP</code>. The default is false so that if the
* populator runs accidentally, it will fail fast when the script starts with a <code>DROP</code>.
* {@code IF EXISTS} clause in a {@code DROP}. The default is false so that if the
* populator runs accidentally, it will fail fast when the script starts with a {@code DROP}.
*/
public void setIgnoreFailedDrops(boolean ignoreFailedDrops) {
this.ignoreFailedDrops = ignoreFailedDrops;
@@ -151,10 +151,10 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
* @param connection the JDBC Connection with which to perform JDBC operations
* @param resource the resource (potentially associated with a specific encoding) to load the SQL script from
* @param continueOnError whether or not to continue without throwing an exception in the event of an error
* @param ignoreFailedDrops whether of not to continue in the event of specifically an error on a <code>DROP</code>
* @param ignoreFailedDrops whether of not to continue in the event of specifically an error on a {@code DROP}
*/
private void executeSqlScript(Connection connection, EncodedResource resource,
boolean continueOnError, boolean ignoreFailedDrops) throws SQLException {
private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError,
boolean ignoreFailedDrops) throws SQLException {
if (logger.isInfoEnabled()) {
logger.info("Executing SQL script from " + resource);
@@ -219,25 +219,30 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
/**
* Read a script from the given resource and build a String containing the lines.
* @param resource the resource to be read
* @return <code>String</code> containing the script lines
* @return {@code String} containing the script lines
* @throws IOException in case of I/O errors
*/
private String readScript(EncodedResource resource) throws IOException {
LineNumberReader lnr = new LineNumberReader(resource.getReader());
String currentStatement = lnr.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
if (StringUtils.hasText(currentStatement) &&
(this.commentPrefix != null && !currentStatement.startsWith(this.commentPrefix))) {
if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n');
try {
String currentStatement = lnr.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
if (StringUtils.hasText(currentStatement) &&
(this.commentPrefix != null && !currentStatement.startsWith(this.commentPrefix))) {
if (scriptBuilder.length() > 0) {
scriptBuilder.append('\n');
}
scriptBuilder.append(currentStatement);
}
scriptBuilder.append(currentStatement);
currentStatement = lnr.readLine();
}
currentStatement = lnr.readLine();
maybeAddSeparatorToScript(scriptBuilder);
return scriptBuilder.toString();
}
finally {
lnr.close();
}
maybeAddSeparatorToScript(scriptBuilder);
return scriptBuilder.toString();
}
private void maybeAddSeparatorToScript(StringBuilder scriptBuilder) {
@@ -248,7 +253,8 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
if (trimmed.length() == this.separator.length()) {
return;
}
// separator ends in whitespace, so we might want to see if the script is trying to end the same way
// separator ends in whitespace, so we might want to see if the script is trying
// to end the same way
if (scriptBuilder.lastIndexOf(trimmed) == scriptBuilder.length() - trimmed.length()) {
scriptBuilder.append(this.separator.substring(trimmed.length()));
}
@@ -290,8 +296,8 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
}
/**
* Split an SQL script into separate statements delimited with the provided delimiter
* character. Each individual statement will be added to the provided {@code List}.
* Split an SQL script into separate statements delimited by the provided delimiter
* string. Each individual statement will be added to the provided {@code List}.
* @param script the SQL script
* @param delim character delimiting each statement (typically a ';' character)
* @param statements the List that will contain the individual statements
+3
View File
@@ -20,6 +20,9 @@
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-1.3.0.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.pool/1.3.0/com.springsource.org.apache.commons.pool-sources-1.3.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.jackson/com.springsource.org.codehaus.jackson.mapper/1.4.2/com.springsource.org.codehaus.jackson.mapper-1.4.2.jar" sourcepath="/IVY_CACHE/org.codehaus.jackson/com.springsource.org.codehaus.jackson.mapper/1.4.2/com.springsource.org.codehaus.jackson.mapper-sources-1.4.2.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.codehaus.jackson/com.springsource.org.codehaus.jackson/1.4.2/com.springsource.org.codehaus.jackson-1.4.2.jar" sourcepath="/IVY_CACHE/org.codehaus.jackson/com.springsource.org.codehaus.jackson/1.4.2/com.springsource.org.codehaus.jackson-sources-1.4.2.jar"/>
<classpathentry kind="var" path="IVY_CACHE/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-databind/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-databind-2.0.2.jar" sourcepath="IVY_CACHE/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-databind/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-databind-2.0.2-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-core/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-core-2.0.2.jar" sourcepath="IVY_CACHE/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-core/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-core-2.0.2-sources.jar"/>
<classpathentry kind="var" path="IVY_CACHE/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-annotations/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-annotations-2.0.2.jar" sourcepath="IVY_CACHE/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-annotations/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-annotations-2.0.2-sources.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.oxm"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
+2
View File
@@ -38,6 +38,8 @@
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
<dependency org="org.codehaus.jackson" name="com.springsource.org.codehaus.jackson.mapper" rev="1.4.2"
conf="optional, jackson->compile"/>
<dependency org="com.fasterxml.jackson.core" name="com.springsource.com.fasterxml.jackson.core.jackson-databind" rev="2.0.2"
conf="optional, jackson->compile"/>
<dependency org="org.springframework" name="org.springframework.aop" rev="latest.integration"
conf="compile->compile"/>
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration"
+33
View File
@@ -77,6 +77,39 @@
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$IVY_CACHE$/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-core/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-core-2.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$IVY_CACHE$/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-core/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-core-sources-2.0.2.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$IVY_CACHE$/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-databind/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-databind-2.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$IVY_CACHE$/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-databind/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-databind-sources-2.0.2.jar!/" />
</SOURCES>
</library>
</orderEntry>
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$IVY_CACHE$/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-annotations/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-annotations-2.0.2.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$IVY_CACHE$/com.fasterxml.jackson.core/com.springsource.com.fasterxml.jackson.core.jackson-annotations/2.0.2/com.springsource.com.fasterxml.jackson.core.jackson-annotations-sources-2.0.2.jar!/" />
</SOURCES>
</library>
</orderEntry>
</component>
<component name="copyright">
<Base>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* 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.
@@ -736,7 +736,7 @@ public class JmsTemplate extends JmsDestinationAccessor implements JmsOperations
JmsResourceHolder resourceHolder =
(JmsResourceHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
if (resourceHolder != null && resourceHolder.hasTimeout()) {
timeout = resourceHolder.getTimeToLiveInMillis();
timeout = Math.min(timeout, resourceHolder.getTimeToLiveInMillis());
}
Message message = doReceive(consumer, timeout);
if (session.getTransacted()) {
@@ -214,6 +214,7 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess
wasRunning = this.running;
this.running = false;
this.active = false;
this.pausedTasks.clear();
this.lifecycleMonitor.notifyAll();
}
@@ -297,9 +297,10 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
* to scale the consumption of messages coming in from a queue. However,
* note that any ordering guarantees are lost once multiple consumers are
* registered. In general, stick with 1 consumer for low-volume queues.
* <p><b>Do not raise the number of concurrent consumers for a topic.</b>
* This would lead to concurrent consumption of the same message,
* which is hardly ever desirable.
* <p><b>Do not raise the number of concurrent consumers for a topic,
* unless vendor-specific setup measures clearly allow for it.</b>
* With regular setup, this would lead to concurrent consumption
* of the same message, which is hardly ever desirable.
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
* @see #setMaxConcurrentConsumers
*/
@@ -336,9 +337,10 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
* to scale the consumption of messages coming in from a queue. However,
* note that any ordering guarantees are lost once multiple consumers are
* registered. In general, stick with 1 consumer for low-volume queues.
* <p><b>Do not raise the number of concurrent consumers for a topic.</b>
* This would lead to concurrent consumption of the same message,
* which is hardly ever desirable.
* <p><b>Do not raise the number of concurrent consumers for a topic,
* unless vendor-specific setup measures clearly allow for it.</b>
* With regular setup, this would lead to concurrent consumption
* of the same message, which is hardly ever desirable.
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
* @see #setConcurrentConsumers
*/
@@ -470,16 +472,6 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
}
}
@Override
protected void validateConfiguration() {
super.validateConfiguration();
synchronized (this.lifecycleMonitor) {
if (isSubscriptionDurable() && this.concurrentConsumers != 1) {
throw new IllegalArgumentException("Only 1 concurrent consumer supported for durable subscription");
}
}
}
//-------------------------------------------------------------------------
// Implementation of AbstractMessageListenerContainer's template methods
@@ -535,6 +527,7 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
logger.debug("Waiting for shutdown of message listener invokers");
try {
synchronized (this.lifecycleMonitor) {
// Waiting for AsyncMessageListenerInvokers to deactivate themselves...
while (this.activeInvokerCount > 0) {
if (logger.isDebugEnabled()) {
logger.debug("Still waiting for shutdown of " + this.activeInvokerCount +
@@ -542,6 +535,11 @@ public class DefaultMessageListenerContainer extends AbstractPollingMessageListe
}
this.lifecycleMonitor.wait();
}
// Clear remaining scheduled invokers, possibly left over as paused tasks...
for (AsyncMessageListenerInvoker scheduledInvoker : this.scheduledInvokers) {
scheduledInvoker.clearResources();
}
this.scheduledInvokers.clear();
}
}
catch (InterruptedException ex) {
@@ -0,0 +1,370 @@
/*
* 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.jms.support.converter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import javax.jms.BytesMessage;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Message converter that uses the Jackson 2 library to convert messages to and from JSON.
* Maps an object to a {@link javax.jms.BytesMessage}, or to a {@link javax.jms.TextMessage} if the
* {@link #setTargetType targetType} is set to {@link org.springframework.jms.support.converter.MessageType#TEXT}.
* Converts from a {@link javax.jms.TextMessage} or {@link javax.jms.BytesMessage} to an object.
*
* @author Mark Pollack
* @author Dave Syer
* @author Juergen Hoeller
* @since 3.1.4
*/
public class MappingJackson2MessageConverter implements MessageConverter {
/**
* The default encoding used for writing to text messages: UTF-8.
*/
public static final String DEFAULT_ENCODING = "UTF-8";
private ObjectMapper objectMapper = new ObjectMapper();
private MessageType targetType = MessageType.BYTES;
private String encoding = DEFAULT_ENCODING;
private String encodingPropertyName;
private String typeIdPropertyName;
private Map<String, Class<?>> idClassMappings = new HashMap<String, Class<?>>();
private Map<Class<?>, String> classIdMappings = new HashMap<Class<?>, String>();
/**
* Specify the {@link org.codehaus.jackson.map.ObjectMapper} to use instead of using the default.
*/
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "ObjectMapper must not be null");
this.objectMapper = objectMapper;
}
/**
* Specify whether {@link #toMessage(Object, javax.jms.Session)} should marshal to a
* {@link javax.jms.BytesMessage} or a {@link javax.jms.TextMessage}.
* <p>The default is {@link org.springframework.jms.support.converter.MessageType#BYTES}, i.e. this converter marshals to
* a {@link javax.jms.BytesMessage}. Note that the default version of this converter
* supports {@link org.springframework.jms.support.converter.MessageType#BYTES} and {@link org.springframework.jms.support.converter.MessageType#TEXT} only.
* @see org.springframework.jms.support.converter.MessageType#BYTES
* @see org.springframework.jms.support.converter.MessageType#TEXT
*/
public void setTargetType(MessageType targetType) {
Assert.notNull(targetType, "MessageType must not be null");
this.targetType = targetType;
}
/**
* Specify the encoding to use when converting to and from text-based
* message body content. The default encoding will be "UTF-8".
* <p>When reading from a a text-based message, an encoding may have been
* suggested through a special JMS property which will then be preferred
* over the encoding set on this MessageConverter instance.
* @see #setEncodingPropertyName
*/
public void setEncoding(String encoding) {
this.encoding = encoding;
}
/**
* Specify the name of the JMS message property that carries the encoding from
* bytes to String and back is BytesMessage is used during the conversion process.
* <p>Default is none. Setting this property is optional; if not set, UTF-8 will
* be used for decoding any incoming bytes message.
* @see #setEncoding
*/
public void setEncodingPropertyName(String encodingPropertyName) {
this.encodingPropertyName = encodingPropertyName;
}
/**
* Specify the name of the JMS message property that carries the type id for the
* contained object: either a mapped id value or a raw Java class name.
* <p>Default is none. <b>NOTE: This property needs to be set in order to allow
* for converting from an incoming message to a Java object.</b>
* @see #setTypeIdMappings
*/
public void setTypeIdPropertyName(String typeIdPropertyName) {
this.typeIdPropertyName = typeIdPropertyName;
}
/**
* Specify mappings from type ids to Java classes, if desired.
* This allows for synthetic ids in the type id message property,
* instead of transferring Java class names.
* <p>Default is no custom mappings, i.e. transferring raw Java class names.
* @param typeIdMappings a Map with type id values as keys and Java classes as values
*/
public void setTypeIdMappings(Map<String, Class<?>> typeIdMappings) {
this.idClassMappings = new HashMap<String, Class<?>>();
for (Map.Entry<String, Class<?>> entry : typeIdMappings.entrySet()) {
String id = entry.getKey();
Class<?> clazz = entry.getValue();
this.idClassMappings.put(id, clazz);
this.classIdMappings.put(clazz, id);
}
}
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
Message message;
try {
switch (this.targetType) {
case TEXT:
message = mapToTextMessage(object, session, this.objectMapper);
break;
case BYTES:
message = mapToBytesMessage(object, session, this.objectMapper);
break;
default:
message = mapToMessage(object, session, this.objectMapper, this.targetType);
}
}
catch (IOException ex) {
throw new MessageConversionException("Could not map JSON object [" + object + "]", ex);
}
setTypeIdOnMessage(object, message);
return message;
}
public Object fromMessage(Message message) throws JMSException, MessageConversionException {
try {
JavaType targetJavaType = getJavaTypeForMessage(message);
return convertToObject(message, targetJavaType);
}
catch (IOException ex) {
throw new MessageConversionException("Failed to convert JSON message content", ex);
}
}
/**
* Map the given object to a {@link javax.jms.TextMessage}.
* @param object the object to be mapped
* @param session current JMS session
* @param objectMapper the mapper to use
* @return the resulting message
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws java.io.IOException in case of I/O errors
* @see javax.jms.Session#createBytesMessage
* @see org.springframework.oxm.Marshaller#marshal(Object, javax.xml.transform.Result)
*/
protected TextMessage mapToTextMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
StringWriter writer = new StringWriter();
objectMapper.writeValue(writer, object);
return session.createTextMessage(writer.toString());
}
/**
* Map the given object to a {@link javax.jms.BytesMessage}.
* @param object the object to be mapped
* @param session current JMS session
* @param objectMapper the mapper to use
* @return the resulting message
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws java.io.IOException in case of I/O errors
* @see javax.jms.Session#createBytesMessage
* @see org.springframework.oxm.Marshaller#marshal(Object, javax.xml.transform.Result)
*/
protected BytesMessage mapToBytesMessage(Object object, Session session, ObjectMapper objectMapper)
throws JMSException, IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(bos, this.encoding);
objectMapper.writeValue(writer, object);
BytesMessage message = session.createBytesMessage();
message.writeBytes(bos.toByteArray());
if (this.encodingPropertyName != null) {
message.setStringProperty(this.encodingPropertyName, this.encoding);
}
return message;
}
/**
* Template method that allows for custom message mapping.
* Invoked when {@link #setTargetType} is not {@link org.springframework.jms.support.converter.MessageType#TEXT} or
* {@link org.springframework.jms.support.converter.MessageType#BYTES}.
* <p>The default implementation throws an {@link IllegalArgumentException}.
* @param object the object to marshal
* @param session the JMS Session
* @param objectMapper the mapper to use
* @param targetType the target message type (other than TEXT or BYTES)
* @return the resulting message
* @throws javax.jms.JMSException if thrown by JMS methods
* @throws java.io.IOException in case of I/O errors
*/
protected Message mapToMessage(Object object, Session session, ObjectMapper objectMapper, MessageType targetType)
throws JMSException, IOException {
throw new IllegalArgumentException("Unsupported message type [" + targetType +
"]. MappingJacksonMessageConverter by default only supports TextMessages and BytesMessages.");
}
/**
* Set a type id for the given payload object on the given JMS Message.
* <p>The default implementation consults the configured type id mapping and
* sets the resulting value (either a mapped id or the raw Java class name)
* into the configured type id message property.
* @param object the payload object to set a type id for
* @param message the JMS Message to set the type id on
* @throws javax.jms.JMSException if thrown by JMS methods
* @see #getJavaTypeForMessage(javax.jms.Message)
* @see #setTypeIdPropertyName(String)
* @see #setTypeIdMappings(java.util.Map)
*/
protected void setTypeIdOnMessage(Object object, Message message) throws JMSException {
if (this.typeIdPropertyName != null) {
String typeId = this.classIdMappings.get(object.getClass());
if (typeId == null) {
typeId = object.getClass().getName();
}
message.setStringProperty(this.typeIdPropertyName, typeId);
}
}
/**
* Convenience method to dispatch to converters for individual message types.
*/
private Object convertToObject(Message message, JavaType targetJavaType) throws JMSException, IOException {
if (message instanceof TextMessage) {
return convertFromTextMessage((TextMessage) message, targetJavaType);
}
else if (message instanceof BytesMessage) {
return convertFromBytesMessage((BytesMessage) message, targetJavaType);
}
else {
return convertFromMessage(message, targetJavaType);
}
}
/**
* Convert a TextMessage to a Java Object with the specified type.
* @param message the input message
* @param targetJavaType the target type
* @return the message converted to an object
* @throws javax.jms.JMSException if thrown by JMS
* @throws java.io.IOException in case of I/O errors
*/
protected Object convertFromTextMessage(TextMessage message, JavaType targetJavaType)
throws JMSException, IOException {
String body = message.getText();
return this.objectMapper.readValue(body, targetJavaType);
}
/**
* Convert a BytesMessage to a Java Object with the specified type.
* @param message the input message
* @param targetJavaType the target type
* @return the message converted to an object
* @throws javax.jms.JMSException if thrown by JMS
* @throws java.io.IOException in case of I/O errors
*/
protected Object convertFromBytesMessage(BytesMessage message, JavaType targetJavaType)
throws JMSException, IOException {
String encoding = this.encoding;
if (this.encodingPropertyName != null && message.propertyExists(this.encodingPropertyName)) {
encoding = message.getStringProperty(this.encodingPropertyName);
}
byte[] bytes = new byte[(int) message.getBodyLength()];
message.readBytes(bytes);
try {
String body = new String(bytes, encoding);
return this.objectMapper.readValue(body, targetJavaType);
}
catch (UnsupportedEncodingException ex) {
throw new MessageConversionException("Cannot convert bytes to String", ex);
}
}
/**
* Template method that allows for custom message mapping.
* Invoked when {@link #setTargetType} is not {@link org.springframework.jms.support.converter.MessageType#TEXT} or
* {@link org.springframework.jms.support.converter.MessageType#BYTES}.
* <p>The default implementation throws an {@link IllegalArgumentException}.
* @param message the input message
* @param targetJavaType the target type
* @return the message converted to an object
* @throws javax.jms.JMSException if thrown by JMS
* @throws java.io.IOException in case of I/O errors
*/
protected Object convertFromMessage(Message message, JavaType targetJavaType)
throws JMSException, IOException {
throw new IllegalArgumentException("Unsupported message type [" + message.getClass() +
"]. MappingJacksonMessageConverter by default only supports TextMessages and BytesMessages.");
}
/**
* Determine a Jackson JavaType for the given JMS Message,
* typically parsing a type id message property.
* <p>The default implementation parses the configured type id property name
* and consults the configured type id mapping. This can be overridden with
* a different strategy, e.g. doing some heuristics based on message origin.
* @param message the JMS Message to set the type id on
* @throws javax.jms.JMSException if thrown by JMS methods
* @see #setTypeIdOnMessage(Object, javax.jms.Message)
* @see #setTypeIdPropertyName(String)
* @see #setTypeIdMappings(java.util.Map)
*/
protected JavaType getJavaTypeForMessage(Message message) throws JMSException {
String typeId = message.getStringProperty(this.typeIdPropertyName);
if (typeId == null) {
throw new MessageConversionException("Could not find type id property [" + this.typeIdPropertyName + "]");
}
Class mappedClass = this.idClassMappings.get(typeId);
if (mappedClass != null) {
return this.objectMapper.getTypeFactory().constructType(mappedClass);
}
try {
return this.objectMapper.getTypeFactory().constructType(
ClassUtils.forName(typeId, getClass().getClassLoader()));
}
catch (Throwable ex) {
throw new MessageConversionException("Failed to resolve type id [" + typeId + "]", ex);
}
}
}
@@ -0,0 +1,175 @@
/*
* 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.jms.support.converter;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.jms.BytesMessage;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
/**
* @author Arjen Poutsma
* @author Dave Syer
*/
public class MappingJackson2MessageConverterTests {
private MappingJackson2MessageConverter converter;
private Session sessionMock;
@Before
public void setUp() throws Exception {
sessionMock = createMock(Session.class);
converter = new MappingJackson2MessageConverter();
converter.setEncodingPropertyName("__encoding__");
converter.setTypeIdPropertyName("__typeid__");
}
@Test
public void toBytesMessage() throws Exception {
BytesMessage bytesMessageMock = createMock(BytesMessage.class);
Date toBeMarshalled = new Date();
expect(sessionMock.createBytesMessage()).andReturn(bytesMessageMock);
bytesMessageMock.setStringProperty("__encoding__", "UTF-8");
bytesMessageMock.setStringProperty("__typeid__", Date.class.getName());
bytesMessageMock.writeBytes(isA(byte[].class));
replay(sessionMock, bytesMessageMock);
converter.toMessage(toBeMarshalled, sessionMock);
verify(sessionMock, bytesMessageMock);
}
@Test
public void fromBytesMessage() throws Exception {
BytesMessage bytesMessageMock = createMock(BytesMessage.class);
Map<String, String> unmarshalled = Collections.singletonMap("foo", "bar");
final byte[] bytes = "{\"foo\":\"bar\"}".getBytes();
Capture<byte[]> captured = new Capture<byte[]>() {
@Override
public void setValue(byte[] value) {
super.setValue(value);
System.arraycopy(bytes, 0, value, 0, bytes.length);
}
};
expect(
bytesMessageMock.getStringProperty("__typeid__"))
.andReturn(Object.class.getName());
expect(
bytesMessageMock.propertyExists("__encoding__"))
.andReturn(false);
expect(bytesMessageMock.getBodyLength()).andReturn(
new Long(bytes.length));
expect(bytesMessageMock.readBytes(EasyMock.capture(captured)))
.andReturn(bytes.length);
replay(sessionMock, bytesMessageMock);
Object result = converter.fromMessage(bytesMessageMock);
assertEquals("Invalid result", result, unmarshalled);
verify(sessionMock, bytesMessageMock);
}
@Test
public void toTextMessageWithObject() throws Exception {
converter.setTargetType(MessageType.TEXT);
TextMessage textMessageMock = createMock(TextMessage.class);
Date toBeMarshalled = new Date();
textMessageMock.setStringProperty("__typeid__", Date.class.getName());
expect(sessionMock.createTextMessage(isA(String.class))).andReturn( textMessageMock);
replay(sessionMock, textMessageMock);
converter.toMessage(toBeMarshalled, sessionMock);
verify(sessionMock, textMessageMock);
}
@Test
public void toTextMessageWithMap() throws Exception {
converter.setTargetType(MessageType.TEXT);
TextMessage textMessageMock = createMock(TextMessage.class);
Map<String, String> toBeMarshalled = new HashMap<String, String>();
toBeMarshalled.put("foo", "bar");
textMessageMock.setStringProperty("__typeid__", HashMap.class.getName());
expect(sessionMock.createTextMessage(isA(String.class))).andReturn(
textMessageMock);
replay(sessionMock, textMessageMock);
converter.toMessage(toBeMarshalled, sessionMock);
verify(sessionMock, textMessageMock);
}
@Test
public void fromTextMessageAsObject() throws Exception {
TextMessage textMessageMock = createMock(TextMessage.class);
Map<String, String> unmarshalled = Collections.singletonMap("foo", "bar");
String text = "{\"foo\":\"bar\"}";
expect(
textMessageMock.getStringProperty("__typeid__"))
.andReturn(Object.class.getName());
expect(textMessageMock.getText()).andReturn(text);
replay(sessionMock, textMessageMock);
Object result = converter.fromMessage(textMessageMock);
assertEquals("Invalid result", result, unmarshalled);
verify(sessionMock, textMessageMock);
}
@Test
public void fromTextMessageAsMap() throws Exception {
TextMessage textMessageMock = createMock(TextMessage.class);
Map<String, String> unmarshalled = Collections.singletonMap("foo", "bar");
String text = "{\"foo\":\"bar\"}";
expect(
textMessageMock.getStringProperty("__typeid__"))
.andReturn(HashMap.class.getName());
expect(textMessageMock.getText()).andReturn(text);
replay(sessionMock, textMessageMock);
Object result = converter.fromMessage(textMessageMock);
assertEquals("Invalid result", result, unmarshalled);
verify(sessionMock, textMessageMock);
}
}
+1
View File
@@ -3,6 +3,7 @@ Bundle-Name: Spring JMS
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Template:
com.fasterxml.jackson.*;version="[2.0.0, 3.0.0)";resolution:=optional,
javax.jms.*;version="[1.1.0, 2.0.0)",
javax.naming.*;version="0";resolution:=optional,
javax.resource.*;version="[1.5.0, 2.0.0)";resolution:=optional,
+4 -4
View File
@@ -40,9 +40,9 @@
<dependency org="org.apache.openjpa" name="com.springsource.org.apache.openjpa" rev="1.1.0" conf="optional, openjpa->compile"/>
<dependency org="org.eclipse.persistence" name="com.springsource.org.eclipse.persistence" rev="1.0.1" conf="test->compile"/>
<dependency org="org.eclipse.persistence" name="com.springsource.org.eclipse.persistence.jpa" rev="1.0.1" conf="optional, eclipselink->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.3.1.GA" conf="optional, hibernate->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.4.0.GA" conf="optional, hibernate-jpa->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.ejb" rev="3.4.0.GA" conf="optional, hibernate-jpa->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate" rev="3.3.2.GA" conf="optional, hibernate->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.annotations" rev="3.4.0.GA-A" conf="optional, hibernate-jpa->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.ejb" rev="3.4.0.GA-A" conf="optional, hibernate-jpa->compile"/>
<dependency org="org.hibernate" name="com.springsource.org.hibernate.core" rev="4.1.0.Final" conf="optional, hibernate->compile"/>
<dependency org="javax.jdo" name="com.springsource.javax.jdo" rev="2.1.0" conf="provided, jdo->compile"/>
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="provided, jpa->compile"/>
@@ -62,7 +62,7 @@
<dependency org="org.easymock" name="com.springsource.org.easymock" rev="2.5.1" conf="test->compile"/>
<dependency org="org.hsqldb" name="com.springsource.org.hsqldb" rev="1.8.0.9" conf="test->compile"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->runtime"/>
<dependency org="org.slf4j" name="com.springsource.slf4j.jcl" rev="1.5.3" conf="test->runtime"/>
<dependency org="org.slf4j" name="com.springsource.slf4j.jcl" rev="1.6.1" conf="test->runtime"/>
</dependencies>
</ivy-module>
+2 -2
View File
@@ -177,11 +177,11 @@
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.1.GA/com.springsource.org.hibernate-3.3.1.GA.jar!/" />
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.2.GA/com.springsource.org.hibernate-3.3.2.GA.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.1.GA/com.springsource.org.hibernate-sources-3.3.1.GA.jar!/" />
<root url="jar://$IVY_CACHE$/org.hibernate/com.springsource.org.hibernate/3.3.2.GA/com.springsource.org.hibernate-sources-3.3.2.GA.jar!/java" />
</SOURCES>
</library>
</orderEntry>
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -30,7 +30,10 @@ import org.hibernate.cache.CacheProvider;
* @author Juergen Hoeller
* @since 2.5.1
* @see LocalSessionFactoryBean#setCacheProvider
* @deprecated as of Spring 3.0, following Hibernate 3.3's deprecation
* of the CacheProvider SPI
*/
@Deprecated
public class LocalCacheProviderProxy implements CacheProvider {
private final CacheProvider cacheProvider;
@@ -1,4 +1,3 @@
/**
*
* Package providing integration of
@@ -7,10 +6,13 @@
*
* <p>Contains an implementation of Spring's transaction SPI for local Hibernate transactions.
* This package is intentionally rather minimal, with no template classes or the like,
* in order to follow native Hibernate recommendations as closely as possible.
* in order to follow Hibernate recommendations as closely as possible. We recommend
* using Hibernate's native <code>sessionFactory.getCurrentSession()</code> style.
*
* <p><b>This package supports Hibernate 4.x only.</b>
* See the <code>org.springframework.orm.hibernate3</code> package for Hibernate 3.x support.
* See the {@code org.springframework.orm.hibernate3} package for Hibernate 3.x support.
* <b>Note:</b> Do not use HibernateTemplate or other classes from the hibernate3 package
* with Hibernate 4; this will lead to class definition exceptions at runtime.
*
*/
package org.springframework.orm.hibernate4;
@@ -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.
@@ -76,12 +76,14 @@ public abstract class EntityManagerFactoryUtils {
* Find an EntityManagerFactory with the given name in the given
* Spring application context (represented as ListableBeanFactory).
* <p>The specified unit name will be matched against the configured
* peristence unit, provided that a discovered EntityManagerFactory
* persistence unit, provided that a discovered EntityManagerFactory
* implements the {@link EntityManagerFactoryInfo} interface. If not,
* the persistence unit name will be matched against the Spring bean name,
* assuming that the EntityManagerFactory bean names follow that convention.
* <p>If no unit name has been given, this method will search for a default
* EntityManagerFactory through {@link ListableBeanFactory#getBean(Class)}.
* @param beanFactory the ListableBeanFactory to search
* @param unitName the name of the persistence unit (may be <code>null</code> or empty,
* @param unitName the name of the persistence unit (may be {@code null} or empty,
* in which case a single bean of type EntityManagerFactory will be searched for)
* @return the EntityManagerFactory
* @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
@@ -108,7 +110,8 @@ public abstract class EntityManagerFactoryUtils {
return beanFactory.getBean(unitName, EntityManagerFactory.class);
}
else {
return BeanFactoryUtils.beanOfType(beanFactory, EntityManagerFactory.class);
// Find unique EntityManagerFactory bean in the context, falling back to parent contexts.
return beanFactory.getBean(EntityManagerFactory.class);
}
}
@@ -116,9 +119,9 @@ public abstract class EntityManagerFactoryUtils {
* Obtain a JPA EntityManager from the given factory. Is aware of a
* corresponding EntityManager bound to the current thread,
* for example when using JpaTransactionManager.
* <p>Note: Will return <code>null</code> if no thread-bound EntityManager found!
* <p>Note: Will return {@code null} if no thread-bound EntityManager found!
* @param emf EntityManagerFactory to create the EntityManager with
* @return the EntityManager, or <code>null</code> if none found
* @return the EntityManager, or {@code null} if none found
* @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
* @see JpaTransactionManager
*/
@@ -132,11 +135,11 @@ public abstract class EntityManagerFactoryUtils {
* Obtain a JPA EntityManager from the given factory. Is aware of a
* corresponding EntityManager bound to the current thread,
* for example when using JpaTransactionManager.
* <p>Note: Will return <code>null</code> if no thread-bound EntityManager found!
* <p>Note: Will return {@code null} if no thread-bound EntityManager found!
* @param emf EntityManagerFactory to create the EntityManager with
* @param properties the properties to be passed into the <code>createEntityManager</code>
* call (may be <code>null</code>)
* @return the EntityManager, or <code>null</code> if none found
* @param properties the properties to be passed into the {@code createEntityManager}
* call (may be {@code null})
* @return the EntityManager, or {@code null} if none found
* @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
* @see JpaTransactionManager
*/
@@ -154,11 +157,11 @@ public abstract class EntityManagerFactoryUtils {
* Obtain a JPA EntityManager from the given factory. Is aware of a
* corresponding EntityManager bound to the current thread,
* for example when using JpaTransactionManager.
* <p>Same as <code>getEntityManager</code>, but throwing the original PersistenceException.
* <p>Same as {@code getEntityManager}, but throwing the original PersistenceException.
* @param emf EntityManagerFactory to create the EntityManager with
* @param properties the properties to be passed into the <code>createEntityManager</code>
* call (may be <code>null</code>)
* @return the EntityManager, or <code>null</code> if none found
* @param properties the properties to be passed into the {@code createEntityManager}
* call (may be {@code null})
* @return the EntityManager, or {@code null} if none found
* @throws javax.persistence.PersistenceException if the EntityManager couldn't be created
* @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
* @see JpaTransactionManager
@@ -254,8 +257,7 @@ public abstract class EntityManagerFactoryUtils {
/**
* Apply the current transaction timeout, if any, to the given JPA Query object.
* <p>This method sets the JPA 2.0 query hints "javax.persistence.lock.timeout"
* and "javax.persistence.query.timeout" accordingly.
* <p>This method sets the JPA 2.0 query hint "javax.persistence.query.timeout" accordingly.
* @param query the JPA Query object
* @param emf JPA EntityManagerFactory that the Query was created for
*/
@@ -263,33 +265,26 @@ public abstract class EntityManagerFactoryUtils {
EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
if (emHolder != null && emHolder.hasTimeout()) {
int timeoutValue = (int) emHolder.getTimeToLiveInMillis();
try {
query.setHint("javax.persistence.lock.timeout", timeoutValue);
}
catch (IllegalArgumentException ex) {
// oh well, at least we tried...
}
try {
query.setHint("javax.persistence.query.timeout", timeoutValue);
}
catch (IllegalArgumentException ex) {
// once again, at least we tried...
// oh well, at least we tried...
}
}
}
/**
* Convert the given runtime exception to an appropriate exception from the
* <code>org.springframework.dao</code> hierarchy.
* {@code org.springframework.dao} hierarchy.
* Return null if no translation is appropriate: any other exception may
* have resulted from user code, and should not be translated.
* <p>The most important cases like object not found or optimistic locking
* failure are covered here. For more fine-granular conversion, JpaAccessor and
* JpaTransactionManager support sophisticated translation of exceptions via a
* JpaDialect.
* @param ex runtime exception that occured
* <p>The most important cases like object not found or optimistic locking failure
* are covered here. For more fine-granular conversion, JpaTransactionManager etc
* support sophisticated translation of exceptions via a JpaDialect.
* @param ex runtime exception that occurred
* @return the corresponding DataAccessException instance,
* or <code>null</code> if the exception should not be translated
* or {@code null} if the exception should not be translated
*/
public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) {
// Following the JPA specification, a persistence provider can also
@@ -325,17 +320,17 @@ public abstract class EntityManagerFactoryUtils {
if (ex instanceof PersistenceException) {
return new JpaSystemException((PersistenceException) ex);
}
// If we get here, we have an exception that resulted from user code,
// rather than the persistence provider, so we return null to indicate
// that translation should not occur.
return null;
return null;
}
/**
* Close the given JPA EntityManager,
* catching and logging any cleanup exceptions thrown.
* @param em the JPA EntityManager to close (may be <code>null</code>)
* @param em the JPA EntityManager to close (may be {@code null})
* @see javax.persistence.EntityManager#close()
*/
public static void closeEntityManager(EntityManager em) {
+2 -2
View File
@@ -6,12 +6,12 @@
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<packaging>jar</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework</groupId>
<artifactId>spring-parent</artifactId>
<relativePath>../org.springframework.spring-parent</relativePath>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
@@ -1,7 +1,7 @@
/**
*
* Package providing integration of <a href="http://www.castor.org/xml-mapping.html">Castor</a> within Springs O/X Mapping
* Package providing integration of <a href="http://castor.codehaus.org/xml-mapping.html">Castor</a> within Springs O/X Mapping
* support
*
*/
@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.springframework.org/schema/oxm" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
targetNamespace="http://www.springframework.org/schema/oxm" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:annotation>
<xsd:documentation>
Defines the elements used in Spring's Object/XML Mapping integration.
</xsd:documentation>
</xsd:annotation>
<xsd:element name="jaxb1-marshaller">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation source="java:org.springframework.oxm.jaxb.Jaxb1Marshaller">
Defines a JAXB1 Marshaller.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.oxm.jaxb.Jaxb1Marshaller"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="contextPath" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>The JAXB Context path</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="validating" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation>Whether incoming XML should be validated.</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="jaxb2-marshaller">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation source="java:org.springframework.oxm.jaxb.Jaxb2Marshaller">
Defines a JAXB2 Marshaller.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.oxm.jaxb.Jaxb2Marshaller"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:sequence>
<xsd:element name="class-to-be-bound" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="name" type="classType" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="contextPath" type="xsd:string">
<xsd:annotation>
<xsd:documentation>The JAXB Context path</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="jibx-marshaller">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation source="java:org.springframework.oxm.jibx.JibxMarshaller">
Defines a JiBX Marshaller.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.oxm.jibx.JibxMarshaller"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="target-class" type="classType" use="required"/>
<xsd:attribute name="bindingName" type="xsd:string">
<xsd:annotation>
<xsd:documentation>The binding name used by this marshaller.</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="xmlbeans-marshaller">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation source="java:org.springframework.oxm.xmlbeans.XmlBeansMarshaller">
Defines a XMLBeans Marshaller.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="org.springframework.oxm.xmlbeans.XmlBeansMarshaller"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="options" type="xsd:string">
<xsd:annotation>
<xsd:documentation source="java:org.apache.xmlbeans.XmlOptions">
The bean name of the XmlOptions that is to be used for this marshaller. Typically a
XmlOptionsFactoryBean definition.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.apache.xmlbeans.XmlOptions"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="classType">
<xsd:annotation>
<xsd:documentation source="java:java.lang.Class">A class supported by a marshaller.</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="direct">
<tool:expected-type type="java.lang.Class"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string"/>
</xsd:simpleType>
</xsd:schema>
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.org/mapping.dtd">
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN" "http://castor.codehaus.org/mapping.dtd">
<mapping>
<description>Castor generated mapping file</description>
<class name="org.springframework.oxm.castor.Flights">
@@ -28,4 +28,4 @@
xmlns:tns="http://samples.springframework.org/flight"/>
</field>
</class>
</mapping>
</mapping>
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>org.springframework</groupId>
<artifactId>spring-library</artifactId>
<packaging>libd</packaging>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<name>Spring Framework</name>
<description>Spring is a layered Java/J2EE application platform, based on code published in Expert
One-on-One J2EE Design and Development by Rod Johnson (Wrox, 2002). </description>
+1 -1
View File
@@ -6,7 +6,7 @@
<artifactId>spring-parent</artifactId>
<packaging>pom</packaging>
<name>Spring Framework - Parent</name>
<version>3.1.3.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
<description>Spring Framework Parent</description>
<scm>
<url>https://fisheye.springframework.org/browse/spring-framework</url>

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