Compare commits

...

431 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
Spring Buildmaster 6c36240055 Release version 3.1.3.RELEASE 2012-10-31 18:12:45 +01:00
Chris Beams a844712908 Update release date in readme 2012-10-31 14:12:11 +01:00
Juergen Hoeller 03c3dc3dae Clarified ServletConfigAware behavior in case of no ServletConfig being available
Issue: SPR-9855
2012-10-31 09:02:48 +01:00
Juergen Hoeller 9caf672f21 Added proper synchronization and not-null check to SimpleMessageListenerContainer's doShutdown
Issue: SPR-9930
2012-10-31 08:53:29 +01:00
Juergen Hoeller 9d78f17176 Adapted PropertySourcesPropertyResolverTests for different error message format 2012-10-31 02:44:48 +01:00
Juergen Hoeller 245d3114a8 Final preparations for 3.1.3 release 2012-10-31 02:23:50 +01:00
Juergen Hoeller 4169898842 Fix circular placeholder prevention
Issue: SPR-5369
2012-10-31 02:18:43 +01:00
Juergen Hoeller e491d990de Minor polishing 2012-10-31 02:10:11 +01:00
Juergen Hoeller 6d6eaf8506 Added test for custom async annotation 2012-10-31 02:09:26 +01:00
Juergen Hoeller a6bcda25c2 Portlet mapping predicate compareTo implementations are transitive now
Also removed unused validateHandler code with dead cachedMappings HashMap.

Issue: SPR-9874
2012-10-31 01:41:19 +01:00
Juergen Hoeller 7702fb8513 Added "jtaDataSource" property to JPA LocalContainerEntityManagerFactoryBean (for default units)
Issue: SPR-9883
2012-10-31 01:08:03 +01:00
Juergen Hoeller b17d53ffae DispatcherPortlet uses a forward for rendering a view as resource response
Issue: SPR-9876
2012-10-31 00:50:46 +01:00
Phillip Webb 7f081a5eb4 Update changelog 2012-10-28 11:59:42 -07:00
Gareth Davis 983e2ce64f Allow 'arg-type' matches against element body
Allow the body of 'arg-type' XML elements to be used as an alternative to
'match' attribute when defining a 'replace-method' in XML configuration.

This change has been introduced primarily to support the samples printed
in the Apress 'Pro Spring' book.

Issue: SPR-9812
Backport-Issue: SPR-9929
Backport-Commit: 0709c033a0
2012-10-28 11:52:22 -07:00
Phillip Webb ea49c8b840 Polish whitespace 2012-10-28 11:13:46 -07:00
Chris Beams 2cfd15899d Fix split package introduced by @EnableSpringConfigured
Commit 6263c9abf9
@EnableSpringConfigured from beans.factory.aspectj =>
context.annotation within the spring-aspects module. This resolved a
package cycle but had the side-effect of causing a "split package" [1]
problem between spring-context and spring-aspects in OSGi-based
classloader environments because the context.annotation package now
exists in both modules.

The simplest and best solution from an OSGi perspective is to relocate
@EnableSpringConfigured and its supporting SpringConfiguredConfiguration
class into a new package. This commit moves both these types into
context.annotation.aspectj, following convention with other such
"aspectj"-qualified packages in the spring-aspects module.

As with the previous move, it is presumed this change will be low-impact
as the "spring-configured" approach to domain object injection is a
niche feature to begin with, and @EnableSpringConfigured has existed in
its current location only since 3.1.2 and this change is being made in
time for 3.1.3.

[1]: http://wiki.osgi.org/wiki/Split_Packages

Issue: SPR-9811, SPR-9441
Backport-Commit: 54db7387de
2012-10-26 14:06:47 +02:00
Sam Brannen d8dc4a257a Support comments in SQL scripts in JdbcTestUtils
Prior to this commit, utility methods in JdbcTestUtils interpreted SQL
comments as separate statements, resulting in an exception when such a
script is executed.

This commit addresses this issue by introducing a
readScript(lineNumberReader, String) method that accepts a comment
prefix. Comment lines are therefore no longer returned in the parsed
script. Furthermore, the existing readScript(lineNumberReader) method
now delegates to this new readScript() method, supplying "--" as the
default comment prefix.

Issue: SPR-9593
Backport-Commit: 4aaf014cc6
2012-10-26 10:45:56 +02:00
Chris Beams 00ed17dca0 Update Apache license header date
Issue: SPR-9853
Backport-Commit: 8a38891e15
2012-10-25 09:24:36 +02:00
Phillip Webb 410b9f933e Update changelog 2012-10-24 11:00:49 -07:00
Phillip Webb a0745c0c0a Support SQL exception translation for ORA-06550
Oracle error ORA-06550 will now raise a BadSqlGrammarException.

Issue: SPR-9853
Backport-Commit: ba5a148d8d
2012-10-24 10:46:06 -07:00
Phillip Webb cfdd50d8ab Polish whitespace 2012-10-24 10:45:29 -07:00
Phillip Webb e3136e65f4 Allow MapToMap conversion even w/out default ctor
MapToMap conversion now works when the target map does not have a
default constructor (as long as a new map copy is not required).

Issue: SPR-9284
Backport-Commit: 38c4393592
2012-10-24 19:31:24 +02:00
Phillip Webb ced6bb4569 Prevent memory leaks with @Configuration beans
Refactor ConfigurationClassEnhancer to allow cglib caching of
generated classes.  Prior to this commit each enhanced @Configuration
class would consume permgen space when created.

The CallbackFilter and Callback Types are now defined as static final
members so that they can be shared by all enhancers.  Only the
callbackInstances remain specific to a @Configuration class and
these are not used by cglib as part of the cache key.

Issue: SPR-9851
Backport-Commit: c8061393fb
2012-10-24 19:12:03 +02:00
Phillip Webb 4525527794 SpEL support for methods and properties on class …
Update the ReflectiveMethodResolver and ReflectivePropertyAccessor
to allow methods and properties of java.lang.Class to be resolved
when the target object is a class.

Issue: SPR-9017
Backport-Commit: d28592a6c6
2012-10-24 18:04:10 +02:00
Phillip Webb 98075c33c6 Chain exception cause on create failure
Propogate root cause of exceptions thrown from createCollection
and createMap.

Issue: SPR-9285
Backport-Commit: 2e48656906
2012-10-24 15:47:11 +02:00
Chris Beams 4cee691d09 Remove accidentally introduced SpEL test method
SpringEL300Tests's #testArray method was originally introduced with
SPR-9203, which has not yet been backported to 3.1.x. During the process
of backporting SPR-9486 functionality, this method was accidentally
introduced, causing false negative test failures. This commit removes
the offending test method.

Issue: SPR-9203, SPR-9486
2012-10-24 14:32:48 +02:00
Chris Beams 347737290e Update SpEL test to reflect native float support
Issue: SPR-9486
Backport-Commit: 59fb67e38d
2012-10-24 14:31:37 +02:00
Satyapal Reddy a94677e7b6 Add SpEL support for float literals
This change ensures that SpEL expressions involving floats are
supported natively as opposed to the previous behavior which required
conversion to double, leading to potential downstream conversion
ambiguities.

Issue: SPR-9486
Backport-Commit: be8f23d756
2012-10-24 14:09:33 +02:00
Phillip Webb ca386c13fc Close 'beans' tag in MVC namespace documentation
Issue: SPR-9898
Backport Issue: SPR-9906
2012-10-22 10:07:51 -07:00
Rossen Stoyanchev f9eacf9c1f Update changelog 2012-10-22 12:41:27 -04:00
Rossen Stoyanchev 88906d271b Improve regex for parsing query params
Previously UriComponentsBuilder used a regular expression for parsing
query name-value pairs where both name and value were expected to not
contain neither '&', not '='. The idea is that the presence of reserved
characters makes it impossible to guess correctly how to parse the
query string (e.g. a=b&c).

This change relaxes the constraint on query param values, allowing them
to contain '='. In effect '&' is the ultimate separator of name-value
pairs, and any '=' in values is ignored. For example "q=1USD=?EUR" is
interpreted as "q equals '1USD=?EUR'".

Issue: SPR-9832
2012-10-22 11:08:56 -04:00
Rossen Stoyanchev d8166d6155 Decode target parameters prior to saving a FlashMap
The target parameters for a FlashMap must be decoded to be able to
match them to the parameters of incoming requests given that the
HttpServletRequest returns decoded request parameters.

Issue: SPR-9657
Backport Issue: SPR-9701
2012-10-14 21:37:29 -04:00
Rossen Stoyanchev 4fccd1799a Fix issue with resolving Errors controller argument
The ErrorsMethodArgumentResolver expects the preceding @ModelAttribute
in the controller method signature to be the last one added in the
model -- an assumption that can break if a model attribute is added
earlier (e.g. through a @ModelAttribute method) and more attributes
are added as well. This fix ensures when an @ModelAttribute is resolved
as a controller method argument it has the highest index in the model.

Issue: SPR-9378
Backport Issue: SPR-9687
2012-10-14 21:28:45 -04:00
Chris Beams 9187eeff27 Make required spring-web's dependence on spring-aop
Prior to this commit spring-web's dependence on spring-aop was marked
optional, however spring-web's required dependence on spring-context
transitively forces a required dependence on spring-aop anyway.

This change marks spring-aop as a required dependency of spring-web,
which a) reflects the poms created by the 3.2 Gradle build and b) helps
solve dependency issues when using higher-level Spring projects such as
Spring Security.

Issue: SPR-9573
2012-10-12 14:24:59 -07:00
Juergen Hoeller 2ab55414e5 Polishing 2012-10-12 23:07:10 +02:00
Juergen Hoeller c90e2c6f10 Made AutoProxyCreatorTests less dependent on container's own interrogation of FactoryBeans
Issue: SPR-9857
2012-10-12 23:06:15 +02:00
Juergen Hoeller 506e9f50d0 LoadTimeWeaverAware beans are consistently being created early for JPA weaving to work reliably
Reverted change for @Bean methods that declare FactoryBean as their return type: The effects of trying to create the FactoryBean to find out about its implementation type are too far-reaching. It's better to recommend declaring a specific return type in the method signature if you want the container to specifically react to your implementation type.

Issue: SPR-9857
2012-10-12 22:56:08 +02:00
Juergen Hoeller 2564db2bfd LoadTimeWeaverAware beans are consistently being created early for JPA weaving to work reliably
Includes a change for factory methods that declare their return type as FactoryBean: When asked for a specific type match (e.g. LoadTimeWeaverAware), we do check early singleton instances as well (reusing the instances that we create for getObjectType checks). This is necessary in order to make @Bean method introspection as capable as XML bean definition introspection, even in case of the @Bean method using a generic FactoryBean declaration for its return type (instead of the FactoryBean impl class).

Issue: SPR-9857
2012-10-12 17:13:07 +02:00
Juergen Hoeller 13edc93f78 Only cache by-type lookups if configuration has been marked as frozen
Issue: SPR-9448
2012-10-12 16:44:04 +02:00
Juergen Hoeller 1d26c37b87 Mention matching bean names in exception message in case of non-unique EntityManagerFactory lookup 2012-10-12 16:26:23 +02:00
Juergen Hoeller ee8e178434 Only cache by-type lookups if configuration has been marked as frozen
Issue: SPR-9448
2012-10-12 16:24:52 +02:00
Juergen Hoeller 679e122326 LoadTimeWeaverAware beans are consistently being created early for JPA weaving to work reliably
Includes a change for factory methods that declare their return type as FactoryBean: When asked for a specific type match (e.g. LoadTimeWeaverAware), we do check early singleton instances as well (reusing the instances that we create for getObjectType checks). This is necessary in order to make @Bean method introspection as capable as XML bean definition introspection, even in case of the @Bean method using a generic FactoryBean declaration for its return type (instead of the FactoryBean impl class).

Issue: SPR-9857
2012-10-12 16:22:11 +02:00
Rossen Stoyanchev 7c1a2f37f2 Fix issue in message conversion
This change ensures that when the Accept and the Producible media types
are equally specific, we use the one from the Accept header, which may
for example carry a different charset.
2012-10-12 09:20:55 -04:00
Chris Beams 5e318e73f8 Update spring-web pom dependency on hessian
Previously, the spring-web pom still depended on the EBR-style
com.springsource artifactId for hessian.

It now depends on Maven Central-style com.caucho:hessian:3.2.1 naming.

Note that Hessian 3.2.1 acutally does not exist in Maven Central, but is
present in the SpringSource repository at http://repo.springsource.org.
In any case, the dependency is optional, so should not cause issues at
build time for applications dependent on spring-web.

Issue: SPR-9854
2012-10-11 15:30:58 -07:00
Juergen Hoeller 682b0f2c63 Jaxb2Marshaller has non-synchronized access to the JAXBContext once initialized
Also backporting "checkForXmlRootElement" property from 3.2 M2

Issue: SPR-9867
Issue: SPR-9757
2012-10-11 22:31:48 +02:00
Juergen Hoeller ad81ec922b OpDivide does not return a TypedValue for its operate result (consistent with OpMultiply)
Issue: SPR-9869
2012-10-11 21:39:12 +02:00
Juergen Hoeller 9862fbfc01 BeanWrapper does not fall back to String constructor if ConversionService attempt failed before
Issue: SPR-9865
2012-10-11 19:42:58 +02:00
Juergen Hoeller d7825586dc Provider injection into prototype beans works for method parameters as well
Issue: SPR-9630
2012-10-11 19:39:37 +02:00
Juergen Hoeller 9338080916 ResourceDatabasePopulator etc 2012-10-11 00:31:06 +02:00
Juergen Hoeller fd10e149f6 Backport "Remove default profile during environment merge"
Issue: SPR-9761
Issue: SPR-9762
2012-10-11 00:30:00 +02:00
Juergen Hoeller 1dd01a7a82 Fixed test failure on CI server (classpath search failing for some reason)
Issue: SPR-9797
2012-10-11 00:23:07 +02:00
Juergen Hoeller 3788635f51 JPA persistence.xml files may use jar-file entries relative to the unit root (as per the JPA spec)
Issue: SPR-9797
2012-10-10 23:33:52 +02:00
Juergen Hoeller 86ef22db49 Backported "Work around JDK7 String#substring performance regression"
Issue: SPR-9781
Issue: SPR-9784
2012-10-10 23:33:51 +02:00
Juergen Hoeller b2fce2f254 Backported "Register environment in all bean factories in a hierarchy"
Issue: SPR-9756
Issue: SPR-9764
2012-10-10 23:33:50 +02:00
Juergen Hoeller be2c2e9a86 Backported "Support opaque URIs in UriComponentsBuilder"
Issue: SPR-9798
Issue: SPR-9804
2012-10-10 23:33:50 +02:00
Rossen Stoyanchev 0047200b98 Fix NPE in AbstractMessageConverterMethodProcessor
Issue: SPR-9868
2012-10-10 09:02:50 -04:00
Juergen Hoeller 1641e082eb Further changes for 3.1.3 2012-10-10 14:28:19 +02:00
Juergen Hoeller baeac9ea6b Polishing 2012-10-10 14:28:18 +02:00
Juergen Hoeller bac05f568a Hibernate 4 LocalSessionFactoryBuilder sets thread context ClassLoader (for JBoss 7 compatibility)
Issue: SPR-9846
2012-10-10 14:28:17 +02:00
Juergen Hoeller cb7d689f92 Consistent "this." reference to local variable 2012-10-10 14:28:16 +02:00
Juergen Hoeller da8e2d6736 AbstractRoutingDataSource consistently implements JDBC 4.0's Wrapper interface as well
Issue: SPR-9856
2012-10-10 14:28:15 +02:00
Juergen Hoeller 6ed589d94b HttpComponentsHttpInvokerRequestExecutor explicitly releases connection on HttpComponents 4.2
Issue: SPR-9833
2012-10-10 14:28:14 +02:00
Chris Beams e70119733a Avoid further 'type mismatch' errors in ExtendedBeanInfo
This change fixes further cases under JDK 6 in which setting a bridged
(e.g. String-returning) read method can conflict with an existing
corresponding bridge write method that accepts an Object parameter.

This appears to be a implementation difference between JDKs 6 and 7,
where the JDK 6 Introspector adds bridge methods and JDK 7 does not.

The solution here is to consistently null-out any existing write method
before setting the read method. We were doing this elsewhere in
ExtendedBeanInfo already, but these two changes make the approach
consistent throuhout.

Issue: SPR-8806
Backport-Commit: 0c0a563a24
2012-10-09 20:16:30 -07:00
Sam Brannen 0824746255 Update Javadoc in ExtendedBeanInfo
- updated the link to the "indexed properties" section of the JavaBeans
   tutorial
2012-10-09 20:16:30 -07:00
Chris Beams 30d0bd309c Address various ExtendedBeanInfo bugs
- Ensure that ExtendedBeanInfoTests succeeds when building under JDK 7

 - Improve handling of read and write method registration where
   generic interfaces are involved, per SPR-9453

 - Add repro test for SPR-9702, in which EBI fails to register
   an indexed read method under certain circumstances

Issue: SPR-9778
Backport-Issue: SPR-9702, SPR-9414, SPR-9453
Backport-Commit: b50bb5071a
2012-10-09 20:15:54 -07:00
Rossen Stoyanchev ec2603de63 Fix issue in AnnotationMethodHandlerExceptionResolver
Caching of resovled exceptions introduced in SPR-7703 also introduced a
side effect whereby if exactly one exception was previously cached, any
other exception would appear as a match to the previously matched
@ExceptionHandler method.

This change ensures use of a fresh map when determining matching
@ExceptionHandler methods while also updating the cache.

Issue: SPR-9209
2012-10-06 22:03:31 -04:00
Rossen Stoyanchev 470c85ade0 Update MediaType's includes method
An additional update (after the last commit) of the "includes" and
"isCompatibleWith" methods of MediaType to accomodate wildcards
in media types with a suffix.

Issue: SPR-9841
2012-10-06 11:07:47 -04:00
Rossen Stoyanchev 01d8d64200 Recognize wildcards in media types with a suffix
The "includes" and "isCompatibleWith" methods of MediaType take into
account media types with suffices (e.g. application/soap+xml) including
wildcards with suffices (e.g. application/*+xml). However before this
change, the isWildcardSubtype() method returned true only for subtype
"*". Now a media type such as application/*+xml is also recognized as
having a wildcard subtype.

Issue: SPR-9841
2012-10-06 10:20:14 -04:00
Juergen Hoeller 2c8b7fe093 ClassUtils.getMostSpecificMethod uses Class.getMethod code path in case of a public method
This should be significantly faster than our standard algorithm, for a very common case. Motivated by SPR-9802, even if the fix there uses a different approach, with transaction name determination not calling getMostSpecificMethod at all anymore.

Issue: SPR-9802
2012-09-26 20:04:43 +02:00
Juergen Hoeller bbfc807b0c TransactionInterceptor avoids reflective method search for method identification
As of Spring 3.0.4, we were trying to expose the target method signature as transaction name. Unfortunately, the algorithm called the ClassUtils.getMostSpecificMethod helper method which performs a quite expensive reflective search. As of this commit, we're simply concatenating the target class name with the method name, accepting the use of the concrete target class (which is arguably more meaningful for monitoring anyway) even when the method implementation actually sits on a base class.

Issue: SPR-9802
2012-09-26 19:31:05 +02:00
Juergen Hoeller c81543e1a4 ResourceBundleMessageSource supports "defaultEncoding", "fallbackToSystemLocale", "cacheSeconds"
These features require Java 6 or higher due to their dependency on the ResourceBundle.Control class. To some degree, ResourceBundleMessageSource catches up with ReloadableResourceBundleMessageSource now. However, as noted in the javadoc, there are still severe limitations in the standard ResourceBundle class that justify an ongoing investment in our own ReloadableResourceBundleMessageSource (based on the Spring resource abstraction, with manual parsing of properties files).

Issue: SPR-7392
2012-09-26 16:46:25 +02:00
Juergen Hoeller 437ce9bb0e Calling cancel on a Future returned by a TaskScheduler works reliably now
Issue: SPR-9821
2012-09-25 13:54:33 +02:00
Juergen Hoeller b79260a017 Fixed potential race condition in concurrent calling of autowired methods on a prototype bean
Autowired methods might have been skipped on subsequent creation of further bean instances due to the 'skip' flag set to false outside of the synchronized block, with another thread entering the block and setting the flag to true in the meantime.

Issue: SPR-9806
2012-09-25 12:50:10 +02:00
Juergen Hoeller 0f522cfe6a Calling cancel on a Future returned by a TaskScheduler works reliably now
Issue: SPR-9821
2012-09-25 12:07:06 +02:00
Juergen Hoeller da75eaedbf Updated changelog for 3.1.3 alongside 3.2 RC1 2012-09-24 23:17:48 +02:00
Juergen Hoeller 69f2496cd7 ImportAwareBeanPostProcessor registered with ROLE_INFRASTRUCTURE 2012-09-24 11:27:40 +02:00
Juergen Hoeller e670975fde CookieGenerator supports "cookieHttpOnly" flag for Servlet 3.0
Issue: SPR-9794
2012-09-24 11:27:39 +02:00
Rossen Stoyanchev 41d9d737ac Cache AntPathStringMatcher instances
AntPathMatcher now caches AntPathStringMatcher instances by pattern
thus avoiding java.util.regex.Pattern recompilation.

Issue: SPR-9749
2012-09-10 17:04:12 -04:00
Juergen Hoeller c25cbe5522 @Import'ed configuration classes get properly registered in case of same class name (second try)
Issue: SPR-9243
2012-09-10 22:13:32 +02:00
Rossen Stoyanchev 8c64b47473 Update changelog 2012-09-10 15:19:47 -04:00
Rossen Stoyanchev 229537288a Backport fixes in HandlerMethod and sub-classes
Issue: SPR-9747, SPR-9748, SPR-9218, SPR-8946, SPR-9159
Backport Issue: SPR-9622
2012-09-10 15:01:41 -04:00
Juergen Hoeller bec5463640 @Import'ed configuration classes get properly registered in case of same class name
Issue: SPR-9243
2012-09-10 15:43:20 +02:00
Juergen Hoeller 7ebfd9e6a8 BeanFactoryAnnotationUtils throws NoSuchBeanDefinitionExceptions instead of IllegalStateExceptions
Issue: SPR-9652
2012-09-10 15:26:27 +02:00
Juergen Hoeller f9147d375f Expression detection properly handles cached String literals
Issue: SPR-9670
2012-09-10 11:10:16 +02:00
Juergen Hoeller 03dd7a57f0 MutablePropertySources log statements guarded by isDebugEnabled
Issue: SPR-9670
2012-09-10 11:05:29 +02:00
Juergen Hoeller 43bc3f19d9 Spring-backed DataSources consistently implement JDBC 4.0's Wrapper interface
Issue: SPR-9770
2012-09-10 10:41:11 +02:00
Juergen Hoeller 0cf4a2626b same-named unit from persistence.xml overrides in case of conflict with default unit
Issue: SPR-9741
2012-09-06 19:22:50 +02:00
Juergen Hoeller a0d0b37d10 polishing 2012-09-06 19:00:01 +02:00
Juergen Hoeller 5a149e4600 @Import'ed configuration classes get properly registered in case of same class name
Issue: SPR-9243
2012-09-06 18:59:45 +02:00
Juergen Hoeller 25a806a54e LinkedCaseInsensitiveMap checks for uniqueness of case-insensitive keys now
Issue: SPR-9754
2012-09-05 13:44:36 +02:00
Juergen Hoeller 33463a94e3 refined TypeConverterDelegate's ConversionService exception handling
Issue: SPR-9498
2012-09-05 01:00:10 +02:00
Juergen Hoeller a6f5d9eb93 initial changelog for 3.1.3 release 2012-09-04 22:39:03 +02:00
Juergen Hoeller f11ef28a4d refined IntelliJ formatting settings 2012-09-04 22:37:48 +02:00
Juergen Hoeller 52c10c52cd CollectionFactory should be aware of MultiValueMap
Issue: SPR-9498
2012-09-04 18:04:54 +02:00
Juergen Hoeller cb13353c1d don't make assumptions about equality if ConversionService has failed
Issue: SPR-9498
2012-09-04 18:04:02 +02:00
Juergen Hoeller 8b09b52720 media types in HTTP Accept headers can be parsed with single quotes (-> Android 2.x)
Issue: SPR-9734
2012-08-31 17:03:28 +02:00
Juergen Hoeller d7fd70fa08 deprecated SimpleJdbcTestUtils in favor of JdbcTestUtils; introduced "countRowsInTableWhere()" and "dropTables()" in JdbcTestUtils
Issue: SPR-9235
Issue: SPR-9664
2012-08-31 16:51:34 +02:00
Juergen Hoeller fbe955ab28 @Autowired-driven ObjectFactory/Provider resolution works in non-singleton beans as well
Issue: SPR-9181
2012-08-31 15:58:41 +02:00
Juergen Hoeller 26ee0c4842 aligned with recent changes in CommonAnnotationBeanPostProcessor; backported NPE check
Issue: SPR-9176
Issue: SPR-9627
Issue: SPR-9316
2012-08-31 11:55:10 +02:00
Juergen Hoeller 19718700cf @Resource processing properly works with scoped beans and prototypes again
Issue: SPR-9627
2012-08-31 11:49:32 +02:00
Juergen Hoeller 8599dfd74e added Hamcrest dependency to core module 2012-08-30 16:30:46 +02:00
Juergen Hoeller a3bfa754fd MessageSourceSupport uses locale-specific MessageFormat cache for default messages
Issue: SPR-9607
2012-08-30 16:30:08 +02:00
Juergen Hoeller 8e3a0070dc backported "toCode"/"toCodeForSuffix" fixes for handling of null prefix/suffix
Issue: SPR-9608
2012-08-29 22:22:22 +02:00
Juergen Hoeller f9cf5d1aa6 fixed Portlet request mapping priorities in cross-controller case
Issue: SPR-9303
Issue: SPR-9605
2012-08-29 22:22:21 +02:00
Rossen Stoyanchev f78bef906d Improve no-match handling for @RequestMapping methods
Issue: SPR-9603
2012-08-28 16:09:46 -04:00
Juergen Hoeller 7704d76144 minor IntelliJ settings update 2012-08-28 19:45:42 +02:00
Juergen Hoeller 3f48c71c77 Backported recent Jaxb2Marshaller changes
Issue: SPR-9152
2012-08-28 19:41:39 +02:00
Juergen Hoeller 576f6fd25c StaxEventContentHandler uses static inner class for Location adapter, in order to avoid leaks when caching events
Issue: SPR-9305
2012-08-28 19:22:20 +02:00
Juergen Hoeller 5204e11d9c Backported recent "cannotAcquireLockCodes" additions
Issue: SPR-9141
Issue: SPR-9681
2012-08-28 18:56:20 +02:00
Juergen Hoeller 30166981e2 ResourceUtils.useCachesIfNecessary() not correct handle JNLP connections
Issue: SPR-9547
2012-08-28 18:35:56 +02:00
Juergen Hoeller 617f0ef542 Fix typo in new-in-3.1.html page
Issue: SPR-9596
2012-08-28 18:26:28 +02:00
Juergen Hoeller dc400c7124 Typo in ApplicationContextAware and BeanNameAware section
Issue: SPR-9609
2012-08-28 18:25:29 +02:00
Rossen Stoyanchev a7e2297432 Use a default for INTROSPECT_TYPE_LEVEL_MAPPING
Usually this request attribute is set for all sub-classes of
AbstractUrlHandlerMapping and therefore whenever
AnnotationMethodHandlerAdapter is used. However, having a
default value to fall back on in AnnotationMethodHandlerAdapter
is still appropriate in general and also considering the Javadoc
of HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING.

Issue: SPR-9629
Backport-Issue: SPR-9633
2012-07-25 19:45:11 -04:00
Spring Buildmaster 671f97721f Increment version to 3.1.3.BUILD-SNAPSHOT 2012-07-07 20:05:06 +02:00
Spring Buildmaster 49f728eae8 Release version 3.1.2.RELEASE 2012-07-07 17:13:55 +02:00
Juergen Hoeller 16da15eca1 final preparations for 3.1.2 2012-07-06 22:48:43 +02:00
Juergen Hoeller efabc6bf18 added "jtaTransactionManager" property to Hibernate 4 LocalSessionFactoryBean/Builder
Issue: SPR-9480
2012-07-06 22:48:42 +02:00
Juergen Hoeller 98b281ea45 Add defaultCharset field to StringHttpMessageConverter
Before this change the StringHttpMessageConverter used a fixed charset "ISO-8859-1" if the requested content type did not specify one. This change adds a defaultCharset field and a constructor to configure it in StringHttpMessageConverter.

Issue: SPR-9487
2012-07-06 22:48:41 +02:00
Chris Beams 00a69394e6 Resolve nested placeholders via PropertyResolver
Prior to this change, PropertySourcesPropertyResolver (and therefore
all AbstractEnvironment) implementations failed to resolve nested
placeholders as in the following example:

    p1=v1
    p2=v2
    p3=${v1}:{$v2}

Calls to PropertySource#getProperty for keys 'p1' and 'v1' would
successfully return their respective values, but for 'p3' the return
value would be the unresolved placeholders. This behavior is
inconsistent with that of PropertyPlaceholderConfigurer.

PropertySourcesPropertyResolver #getProperty variants now resolve any
nested placeholders recursively, throwing IllegalArgumentException for
any unresolvable placeholders (as is the default behavior for
PropertyPlaceholderConfigurer). See SPR-9569 for an enhancement that
will intoduce an 'ignoreUnresolvablePlaceholders' switch to make this
behavior configurable.

This commit also improves error output in
PropertyPlaceholderHelper#parseStringValue by including the original
string in which an unresolvable placeholder was found.

Issue: SPR-9473, SPR-9569
2012-07-06 19:42:54 +02:00
Chris Beams 45f1438ef8 Add hamcrest to spring-aspects Eclipse classpath
Also remove spring project nature from spring-context to avoid error in
STS.
2012-07-06 15:52:00 +02:00
Juergen Hoeller e7b44e015a Cannot amend properties in RequestMappingHandlerMapping (e.g. useSuffixPatternMatch) using a bean post processor as ApplicationContextAwareProcessor always fires first initialising RequestMappingHandlerMapping
Issue: SPR-9371
2012-07-05 01:29:41 +02:00
Juergen Hoeller 23fe1e2934 Cannot amend properties in RequestMappingHandlerMapping (e.g. useSuffixPatternMatch) using a bean post processor as ApplicationContextAwareProcessor always fires first initialising RequestMappingHandlerMapping
Issue: SPR-9371
2012-07-05 01:20:43 +02:00
Juergen Hoeller 1f64b147b1 indentation configuration for further file types 2012-07-05 01:08:22 +02:00
Juergen Hoeller 5e4f3b3108 Cannot amend properties in RequestMappingHandlerMapping (e.g. useSuffixPatternMatch) using a bean post processor as ApplicationContextAwareProcessor always fires first initialising RequestMappingHandlerMapping
Issue: SPR-9371
2012-07-05 01:06:55 +02:00
Juergen Hoeller c87989477d preparations for 3.1.2 2012-07-05 00:51:17 +02:00
Juergen Hoeller 3b4210fa6f Cannot amend properties in RequestMappingHandlerMapping (e.g. useSuffixPatternMatch) using a bean post processor as ApplicationContextAwareProcessor always fires first initialising RequestMappingHandlerMapping
Issue: SPR-9371
2012-07-05 00:31:24 +02:00
Juergen Hoeller 79b86a7e3a DispatcherPortlet does not forward event exceptions to the render phase by default
Issue: SPR-9287
2012-07-05 00:19:32 +02:00
Juergen Hoeller b488ae6009 removed misleading "throws IllegalStateException" declaration
Issue: SPR-9561
2012-07-04 23:33:15 +02:00
Juergen Hoeller aeef8c87f6 added "repeatCount" bean property to Quartz SimpleTriggerFactoryBean
Issue: SPR-9521
2012-07-04 23:22:38 +02:00
Juergen Hoeller 556c6a79c5 Use BufferedInputStream in SimpleMetaDataReader to double performance
Issue: SPR-9528
2012-07-02 22:09:36 +02:00
Juergen Hoeller 0281158fcc Make 'Content-Disposition' header case insensitive
Issue: SPR-9149
2012-06-28 18:02:43 +02:00
Juergen Hoeller 100fa178dd XStreamMarshaller should convert XStream StreamException to Spring exception in case of unmarshalling an empty stream.
Issue: SPR-9536
2012-06-28 17:43:39 +02:00
Chris Beams a387d13d5f Reflect 3.2=>3.1.2 backports in @since tags etc
Issue: SPR-9443, SPR-6847, SPR-9446, SPR-9444, SPR-9439, SPR-9302,
       SPR-9507, SPR-9238, SPR-9397, SPR-9406, SPR-9502
2012-06-27 23:09:14 +02:00
Chris Beams 841d9533db Cache by-type lookups in DefaultListableBeanFactory
Prior to this change, by-type lookups using DLBF#getBeanNamesForType
required traversal of all bean definitions within the bean factory
in order to inspect their bean class for assignability to the target
type. These operations are comparatively expensive and when there are a
large number of beans registered within the container coupled with a
large number of by-type lookups at runtime, the performance impact can
be severe. The test introduced here demonstrates such a scenario clearly.

This performance problem is likely to manifest in large Spring-based
applications using non-singleton beans, particularly request-scoped
beans that may be created and wired many thousands of times per second.

This commit introduces a simple ConcurrentHashMap-based caching strategy
for by-type lookups; container-wide assignability checks happen only
once on the first by-type lookup and are afterwards cached by type
with the values in the map being an array of all bean names assignable
to that type. This means that at runtime when creating and autowiring
non-singleton beans, the cost of by-type lookups is reduced to that of
ConcurrentHashMap#get.

Issue: SPR-9448
Backport-Issue: SPR-6870
Backport-Commit: 4c7a1c0a54
2012-06-27 23:09:14 +02:00
Chris Beams 0d18deb6a4 Polish
Issue: SPR-9448
Backport-Issue: SPR-6870
Backport-Commit: db1cb13448
2012-06-27 23:09:14 +02:00
Sam Brannen 42204e5098 Fix regression in ClassPathResource descriptions
ClassPathResource.getDescription() now returns consistent, meaningful
results for all variants of ClassPathResource's constructors.

Issue: SPR-9415
Backport-Issue: SPR-9413
Backport-Commit: b50f6e19a6
2012-06-27 23:09:14 +02:00
Dridi Boukelmoune eed090e5f5 Fix scoped-proxy memory leak w/ @Resource injection
Prior to this change, request-scoped components having
@Resource-injected dependencies caused a memory leak in
DefaultListableBeanFactory#dependenciesForBeanMap.

Consider the following example:

    @Component
    @Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
    public class MyComponent {

        @Resource
        private HttpServletRequest request;

        // ...
    }

The bean name for "MyComponent" will end up being
'scopedTarget.myComponent', which will become a key in
the #dependenciesForBeanMap structure.

On the first request, the injected HttpServletRequest bean will be a
proxy and will internally have a bean name of the form
"$Proxy10@1a3a2a52". This name will be added to the Set value associated
with the 'scopedTarget.myComponent' entry in #dependenciesForBeanMap.

On the second request, the process will repeat, but the injected
HttpServletRequest will be a different proxy instance, thus having a
different identity hex string, e.g. "$Proxy10@5eba06ff". This name will
also be added to the Set value associated with the
'scopedTarget.myComponent' entry in #dependenciesForBeanMap, and this
is the source of the leak: a new entry is added to the set on each
request but should be added only once.

This commit fixes the leak by introducing caching to
CommonAnnotationBeanPostProcessor#ResourceElement similar to that already
present in AutowiredAnnotationBeanPostProcessor#AutowiredFieldElement
and #AutowiredMethodElement. Essentially, each ResourceElement instance
now tracks whether it has been created, caches the ultimate value to be
injected and returns it eagerly if necessary. Besides solving the memory
leak, this has the side effect of avoiding unnecessary proxy creation.

This fix also explains clearly why injection into request-scoped
components using @Autowired never suffered this memory leak: because the
correct caching was already in place. Because @Resource is considerably
less-frequently used than @Autowired, and given that this particular
injection arrangement is relatively infrequent, it becomes
understandable how this bug has been present without being reported
since the introduction of @Resource support in Spring 2.5: developers
were unlikely to encounter it in the first place; and if they did, the
leak was minor enough (adding strings to a Set), that it could
potentially go unnoticed indefinitely depending on request volumes and
available memory.

Issue: SPR-9363
Backport-Issue: SPR-9176
Backport-Commit: f779c199ea
2012-06-27 23:09:13 +02:00
Chris Beams 0320cc582b Introduce BeanFactoryAnnotationUtils
Commit 3f387eb9cf refactored and
deprecated TransactionAspectUtils, moving its #qualifiedBeanOfType
and related methods into BeanFactoryUtils. This created a package cycle
between beans.factory and beans.factory.annotation due to use of the
beans.factory.annotation.Qualifier annotation in these methods.

This commit breaks the package cycle by introducing
beans.factory.annotation.BeanFactoryAnnotationUtils and moving these
@Qualifier-related methods to it. It is intentionally similar in name
and style to the familiar BeanFactoryUtils class for purposes of
discoverability.

There are no backward-compatibilty concerns associated with this change
as the cycle was introduced, caught and now fixed before a release.

Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: a4b00c732b
2012-06-27 23:09:06 +02:00
Chris Beams a76c7ca299 Test meta-@Async executor qualification
Prove that Async#value is respected even when using @Async as a meta
annotation.

Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: 37e024c6eb
2012-06-27 23:06:54 +02:00
Chris Beams 8bab873107 Support executor qualification with @Async#value
Prior to this change, Spring's @Async annotation support was tied to a
single AsyncTaskExecutor bean, meaning that all methods marked with
@Async were forced to use the same executor. This is an undesirable
limitation, given that certain methods may have different priorities,
etc. This leads to the need to (optionally) qualify which executor
should handle each method.

This is similar to the way that Spring's @Transactional annotation was
originally tied to a single PlatformTransactionManager, but in Spring
3.0 was enhanced to allow for a qualifier via the #value attribute, e.g.

  @Transactional(ptm1)
  public void m() { ... }

where ptm1 is either the name of a PlatformTransactionManager bean or
a qualifier value associated with a PlatformTransactionManager bean,
e.g. via the <qualifier> element in XML or the @Qualifier annotation.

This commit introduces the same approach to @Async and its relationship
to underlying executor beans. As always, the following syntax remains
supported

  @Async
  public void m() { ... }

indicating that calls to #m will be delegated to the default executor,
i.e. the executor provided to

  <task:annotation-driven executor=.../>

or the executor specified when authoring a @Configuration class that
implements AsyncConfigurer and its #getAsyncExecutor method.

However, it now also possible to qualify which executor should be used
on a method-by-method basis, e.g.

  @Async(e1)
  public void m() { ... }

indicating that calls to #m will be delegated to the executor bean
named or otherwise qualified as e1. Unlike the default executor
which is specified up front at configuration time as described above,
the e1 executor bean is looked up within the container on the first
execution of #m and then cached in association with that method for the
lifetime of the container.

Class-level use of Async#value behaves as expected, indicating that all
methods within the annotated class should be executed with the named
executor. In the case of both method- and class-level annotations, any
method-level #value overrides any class level #value.

This commit introduces the following major changes:

 - Add @Async#value attribute for executor qualification

 - Introduce AsyncExecutionAspectSupport as a common base class for
   both MethodInterceptor- and AspectJ-based async aspects. This base
   class provides common structure for specifying the default executor
   (#setExecutor) as well as logic for determining (and caching) which
   executor should execute a given method (#determineAsyncExecutor) and
   an abstract method to allow subclasses to provide specific strategies
   for executor qualification (#getExecutorQualifier).

 - Introduce AnnotationAsyncExecutionInterceptor as a specialization of
   the existing AsyncExecutionInterceptor to allow for introspection of
   the @Async annotation and its #value attribute for a given method.
   Note that this new subclass was necessary for packaging reasons -
   the original AsyncExecutionInterceptor lives in
   org.springframework.aop and therefore does not have visibility to
   the @Async annotation in org.springframework.scheduling.annotation.
   This new subclass replaces usage of AsyncExecutionInterceptor
   throughout the framework, though the latter remains usable and
   undeprecated for compatibility with any existing third-party
   extensions.

 - Add documentation to spring-task-3.2.xsd and reference manual
   explaining @Async executor qualification

 - Add tests covering all new functionality

Note that the public API of all affected components remains backward-
compatible.

Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: ed0576c181
2012-06-27 23:06:54 +02:00
Chris Beams e8006bdf78 Polish async method execution infrastructure
In anticipation of substantive changes required to implement @Async
executor qualification, the following updates have been made to the
components and infrastructure supporting @Async functionality:

 - Fix trailing whitespace and indentation errors
 - Fix generics warnings
 - Add Javadoc where missing, update to use {@code} tags, etc.
 - Avoid NPE in AopUtils#canApply
 - Organize imports to follow conventions
 - Remove System.out.println statements from tests
 - Correct various punctuation and grammar problems

Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: 3fb11870d9
2012-06-27 23:06:05 +02:00
Chris Beams 3f387eb9cf Refactor and deprecate TransactionAspectUtils
TransactionAspectUtils contains a number of methods useful in
retrieving a bean by type+qualifier. These methods are functionally
general-purpose save for the hard coding of PlatformTransactionManager
class literals throughout.

This commit generifies these methods and moves them into
BeanFactoryUtils primarily in anticipation of their use by async method
execution interceptors and aspects when performing lookups for qualified
executor beans e.g. via @Async(qualifier).

The public API of TransactionAspectUtils remains backward compatible;
all methods within have been deprecated, and all calls to those methods
throughout the framework refactored to use the new BeanFactoryUtils
variants instead.

Issue: SPR-9443
Backport-Issue: SPR-6847
Backport-Commit: 096693c46f
2012-06-27 23:06:05 +02:00
Oliver Gierke 0769d53a6a Use transactional connection during db population
Previously, DatabasePopulatorUtils#execute looked up a Connection from
the given DataSource directly which resulted in the executed statements
not being executed against a transactional connection (if any) which in
turn resulted in the statements executed by the populator potentially
not being rolled back.

Now DataSourceUtils#getConnection is used to transparently take part in
any active transaction and #releaseConnection is used to ensure the
connection is closed if appropriate.

Issue: SPR-9465
Backport-Issue: SPR-9457
Backport-Commit: 49c9a2a915
2012-06-27 23:06:04 +02:00
Chris Beams 6263c9abf9 Fix package cycle in @EnableSpringConfigured
@EnableSpringConfigured and its @Import'ed
SpringConfiguredConfiguration @Configuration class inadvertently
established a package cycle between beans.factory.aspectj and
context.annotation due to SpringConfiguredConfiguration's
dependency on annotations such as @Configuration, @Bean and @Role.

This commit fixes this architecture bug by moving
@EnableSpringConfigured and SpringConfiguredConfiguration from the
beans.factory.aspectj package to the context.annotation package where
they belong.

This change is assumed to be very low impact as @EnableSpringConfigured
was introduced in 3.1.0 and relocation is happening as quickly as
possible in 3.1.2. @EnableSpringConfigured is assumed to be infrequently
used at this point, and for those that are the migration path
is straightforward. When upgrading from Spring 3.1.0 or 3.1.1, update
import statements in any affected @Configuration classes to reflect the
new packaging.

Backporter's note: this change causes Bundlor warnings in
org.springframework.aspect as its manifest now "imports and exports the
package org.springframework.context.annotation". To 'solve' this
problem, `fail.on.warnings=false` has been added to build.properties.
This means that future Bundlor-based warnings may go unnoticed.

Issue: SPR-9442
Backport-Issue: SPR-9441
Backport-Commit: 5327a7a37d
2012-06-27 23:06:04 +02:00
Chris Beams 1eb50297ad Introduce ConfigurableWebEnvironment
Changes introduced in Spring 3.1 for Environment support inadvertently
established a cyclic dependency between the
org.springframework.web.context and
org.springframework.web.context.support packages, specifically through
web.context.ContextLoader's invocation of
web.context.support.WebApplicationContextUtils#initServletPropertySources.

This commit introduces ConfigurableWebEnvironment to break this cyclic
dependency. All web.context.ConfigurableWebApplicationContext types now
return web.context.ConfigurableWebEnvironment from their #getEnvironment
methods; web.context.support.StandardServletEnvironment now implements
ConfigurableWebEnvironment and makes the call to
web.context.support.WebApplicationContextUtils#initServletPropertySources
within its implementation of #initPropertySources. This means that
web.context.ContextLoader now invokes
web.context.ConfigurableWebEnvironment#initPropertySources instead of
web.context.support.WebApplicationContextUtils#initServletPropertySources
and thus the cycle is broken.

Issue: SPR-9440
Backport-Issue: SPR-9439
Backport-Commit: 2a2b6eef91
2012-06-27 23:06:04 +02:00
Chris Beams 20f87ab98d Introduce ConfigurableEnvironment#merge
Prior to this change, AbstractApplicationContext#setParent replaced the
child context's Environment with the parent's Environment if available.
This has the negative effect of potentially changing the type of the
child context's Environment, and in any case causes property sources
added directly against the child environment to be ignored. This
situation could easily occur if a WebApplicationContext child had a
non-web ApplicationContext set as its parent. In this case the parent
Environment type would (likely) be StandardEnvironment, while the child
Environment type would (likely) be StandardServletEnvironment. By
directly inheriting the parent environment, critical property sources
such as ServletContextPropertySource are lost entirely.

This commit introduces the concept of merging an environment through
the new ConfigurableEnvironment#merge method. Instead of replacing the
child's environment with the parent's,
AbstractApplicationContext#setParent now merges property sources as
well as active and default profile names from the parent into the
child. In this way, distinct environment objects are maintained with
specific types and property sources preserved. See #merge Javadoc for
additional details.

Issue: SPR-9446
Backport-Issue: SPR-9444, SPR-9439
Backport-Commit: 9fcfd7e827
2012-06-27 23:06:04 +02:00
Chris Beams c25a1bcb60 Reduce log level for message re: missing annotation
Previously (since Spring 3.1.1) RecursiveAnnotationAttributesVisitor
logs at level WARN when ASM parsing encounters an annotation or an (enum
used within an annotation) that cannot be classloaded. This is not
necessarily indicative of an error, e.g. JSR-305 annotations such as
@Nonnull may be used only for static analysis purposes, but because
these annotations have runtime retention, they remain present in the
bytecode. Per section 9.6.1.2 of the JLS, "An annotation that is present
in the binary may or may not be available at run-time via the reflective
libraries of the Java platform."

This commit lowers the log level of these messages from warn to debug,
but leaves at warn level other messages dealing with the ability
reflectively read enum values from within annotations.

Issue: SPR-9447
Backport-Issue: SPR-9233
Backport-Commit: f55a4a1ac5
2012-06-27 23:06:04 +02:00
Rossen Stoyanchev e8deba2915 Fix issue with encoded params in UriComponentsBuilder
The fromUri method of UriComponentsBuilder used uri.getXxx() methods,
which decode the URI parts causing URI parsing issues. The same method
now uses uri.getRawXxx().

Issue: SPR-9317
Backport-Issue: SPR-9549
Backport-Commit: a33fe6fa0a
2012-06-27 10:51:45 -04:00
Rossen Stoyanchev fa33c4b857 Update changelog 2012-06-26 18:03:32 -04:00
Rossen Stoyanchev 24c30eac49 Raise RestClientException for unknown status codes
HttpStatus cannot be created with an unknown status code. If a server
returns a status code that's not in the HttpStatus enum values, an
IllegalArgumentException is raised. Rather than allowing it to
propagate as such, this change ensures the actual exception raised is
a RestClientException.

Issue: SPR-9406
Backport-Issue: SPR-9502
2012-06-26 17:56:31 -04:00
Rossen Stoyanchev 1af7575bde Merge rather than add URI vars to data binding values
As of Spring 3.1 URI variables can be used for data binding purposes in
addition to request parameters (including query string and form params)

In some cases URI variables and request params can overlap (e.g. form
contains a child entity with an entityId as hidden form input while the
URI contains the entityId of the parent entity) and that can lead to
surprises if the application already exists.

This change ensures that request parameters are used first and URI
vars are added only if they don't overlap. Ideally however an
application should not use the same uri variable name as the name of
a request parameter where they don't refer to the same value.

Issue: SPR-9349
Backport-Issue: SPR-9432
Backport-Commit: 4027b38903
2012-06-26 17:40:45 -04:00
Rossen Stoyanchev 8143d66e4c Pattern suffix issue in AnnotationMethodHandlerAdapter
Issue: SPR-9333
Backport-Issue: SPR-9419
Backport-Commit: cf5d55173b
2012-06-26 17:38:29 -04:00
Rossen Stoyanchev 9e370208d0 Fix content negotiation issue with sort by q-value
Before this fix the q-value of media types in the Accept header were
ignored when using the new RequestMappingHandlerAdapter in combination
with @ResponseBody and HttpMessageConverters.

Issue: SPR-9160
Backport-Issue: SPR-9168
Backport-Commit: 982cb2f258
2012-06-26 17:28:52 -04:00
Rossen Stoyanchev e66bc07c37 Translate EOF to HttpMessageNotReadableException
The MappingJacksonHttpMessageConverter now catches all IOException
types raised while reading JSON and translates them into
HttpMessageNotReadableException.

Issue: SPR-9238
Backport-Issue: SPR-9397
Backport-Commit: 816c1f47a4
2012-06-26 17:04:44 -04:00
Rossen Stoyanchev c9a2dbdbfd Add Jackson 2 HttpMessageConverter and View
Jackson 2 uses completely new package names and new maven artifact ids.
This change adds Jackson 2 as an optional dependency and also provides
MappingJackson2HttpMessageConverter and MappingJackson2JsonView for use
with the new version.

The MVC namespace and the MVC Java config detect and use
MappingJackson2HttpMessageConverter if Jackson 2 is present.
Otherwise if Jackson 1.x is present,
then MappingJacksonHttpMessageConverter is used.

Issue: SPR-9302
Backport-Issue: SPR-9507
Backport-Commit: e63ca04fdb
2012-06-26 16:52:51 -04:00
Rossen Stoyanchev 2fa0e63e5a Discover controllers based on type @RequestMapping
This was supported in DefaultAnnotationHandlerMapping but not in the
RequestMappingHandlerMapping. The specific scenario where this matters
is a controller decorated with a JDK proxy. In this scenario the
HandlerMapping looks at interfaces only to decide if the bean is a
controller. The @Controller annotation is better left (and required)
on the class.

Issue: SPR-9374
Backport-Issue: SPR-9384
Backport-Commit: f61f4a960e
2012-06-26 15:51:08 -04:00
Rossen Stoyanchev 83ac44d1e4 Fix issue with parsing media types
Invalid Content-Type or Accept header values previously resulted in the
IllegalArgumentException getting propagated. After this change such
errors are detected and generally treated as a "no match", which
may for example result in a 406 in the case of the Accept header.

Issue: SPR-9142
Backport-Issue: SPR-9148
Backport-Commit: ca8b98e947
2012-06-26 13:55:05 -04:00
Rossen Stoyanchev 0cf93711b9 Fix race condition in AnntationMethodHER
Issue: SPR-9138
Backport-Issue: SPR-9147
Backport-Commit: 0b02933938
2012-06-26 13:46:25 -04:00
Rossen Stoyanchev 8faa2e61ec Fix bug with custom RequestCondition
A custom RequestCondition which can be provided by overriding methods
in RequestMappingHandlerMapping worked only for conditions that match
and did not return null (as it should have) for conditions that don't
match.

Issue: SPR-9134
Backport-Issue: SPR-9146
Backport-Commit: 64ee5e579a
2012-06-26 13:40:00 -04:00
Chris Beams 71443efd90 Fix typo in MessageSource reference docs
Issue: SPR-5022
2012-06-19 11:58:41 +02:00
Juergen Hoeller bc243b5aa7 preparations for 3.1.2 release 2012-05-28 00:23:01 +02:00
Juergen Hoeller d36979bc80 fixed WindowState comparison 2012-05-28 00:12:55 +02:00
Juergen Hoeller 5875695d99 polishing 2012-05-28 00:11:55 +02:00
Juergen Hoeller dcb44264ad EhCacheFactoryBean applies listeners and enabled/disabled flags to existing cache regions as well (SPR-9392) 2012-05-28 00:11:19 +02:00
Juergen Hoeller 9fcb578187 fixed StandardServletMultipartResolver compatibility with Resin (SPR-9299) 2012-05-28 00:10:47 +02:00
Juergen Hoeller 8cdfbfe864 ServletContextResource's getFile implementation falls back to getRealPath for non-existent files (SPR-8461) 2012-05-28 00:10:23 +02:00
Oliver Gierke 9ca407d55e Add missing section ids in reference documentation
Add missing id attributes to <section> elements in the reference
documentation to ensure stable anchor links in HTML output.

Issue: SPR-9410
Backport-Issue: SPR-9346
Backport-Commit: 2a75c57d3c
2012-05-15 22:11:23 +03:00
Chris Beams 1380d053c4 Clarify @EnableScheduling javadoc
It is now advised that destroyMethod="shutdown" should be used
on @Bean methods returning an ExecutorService.

Backport-Issue: SPR-9280
Backport-Commit: 6da03a61b22696283c2c5c79f8f88b5c36480560
2012-05-15 22:10:54 +03:00
Chris Beams 6b76afd1ce Fix typo in reference documentation
Issue: SPR-9321
2012-04-13 20:40:21 +03:00
Chris Beams 2fe74a4ef0 Eliminate INDEX.LIST from Spring jar META-INF dirs
The contents of this file could be problematic as they were generated
by spring-build with "org.springframework.core.jar" EBR-style naming,
but this naming is incorrect when dealing with Maven-central style
artifacts, e.g. spring-core.jar.

While a well-formed INDEX.LIST may speed up classloading, the simplest
solution to the issues listed below is simply to eliminate the file.
This also means consistent treatment across 3.1.x and 3.2.x artifacts,
as the new Gradle build in 3.2.x does not create these index files.

Issue: SPR-6383, SPR-9208
2012-04-13 16:58:26 +03:00
Juergen Hoeller ee9b9d6a57 JDBC parameter binding uses JDBC 3.0 ParameterMetaData (if available) for type determination 2012-03-14 16:54:22 +01:00
Juergen Hoeller bf8fa6e268 moved getInputStream() not-null requirement to InputStreamSource itself 2012-03-14 16:40:47 +01:00
Juergen Hoeller c976fa329f initial fixes for 3.1.2 2012-03-14 16:18:06 +01:00
Juergen Hoeller d22c8aca49 moved getInputStream() not-null requirement to InputStreamSource itself 2012-03-14 16:12:57 +01:00
Juergen Hoeller 79d9f7a5f7 JDBC parameter binding uses JDBC 3.0 ParameterMetaData (if available) for type determination 2012-03-14 16:07:39 +01:00
Juergen Hoeller 9d3cfcd8e6 fixed OSGi metadata for optional "javax.inject" package import (SPR-9173) 2012-03-14 16:03:49 +01:00
Chris Beams 7d72ab59ae Return null correctly from MutablePropertySources#get
Prior to this commit, MutablePropertySources#get(String) would throw
IndexArrayOutOfBoundsException if the named property source does not
actually exist. This is a violation of the PropertySource#get contract
as described in its Javadoc.

The implementation now correctly checks for the existence of the named
property source, returning null if non-existent and otherwise returning
the associated PropertySource.

Other changes

 - Rename PropertySourcesTests => MutablePropertySourcesTests
 - Polish MutablePropertySourcesTests for style, formatting
 - Refactor MutablePropertySources for consistency

Issue: SPR-9185
Backport-Issue: SPR-9179
Backport-Commit: 15d1d824b5
2012-02-29 14:47:47 +01:00
Chris Beams 40a6769309 Avoid infinite loop in AbstractResource#contentLength
Due to changes made in commit 2fa87a71 for SPR-9118,
AbstractResource#contentLength would fall into an infinite loop unless
the method were overridden by a subclass (which it is in the majority of
use cases).

This commit:

 - fixes the infinite recursion by refactoring to a while loop

 - asserts that the value returned from #getInputStream is not null in
   order to avoid NullPointerException

 - tests both of the above

 - adds Javadoc to the Resource interface to clearly document that the
   contract for any implementation is that #getInputStream must not
   return null

Issue: SPR-9163
Backport-Issue: SPR-9161
Backport-Commit: 7ca5fba05f
2012-02-24 14:47:02 +01:00
Chris Beams e30d6104f3 Fix regression in @PropertySource placeholder resolution
Changes in commit 41ade68b50 introduced
a regression causing all but the first location in the
@PropertySource#value array to be ignored during ${...} placeholder
resolution. This change ensures that all locations are processed and
replaced as expected.

Issue: SPR-9133
Backport-Issue: SPR-9127
Backport-Commit: 4df2a14b13
2012-02-20 15:27:09 +01:00
Chris Beams 129b4b3136 Update reference doc copyright year to 2012 2012-02-17 01:24:14 +01:00
Spring Buildmaster b32a365f14 Increment version to 3.1.2.BUILD-SNAPSHOT 2012-02-16 15:38:16 -08:00
Spring Buildmaster 79c9ca1a26 Release version 3.1.1.RELEASE 2012-02-16 15:33:27 -08:00
Chris Beams 7535e24deb Warn re Environment construction and instance vars
- Add warning regarding access to default instance variable values
   during AbstractEnvironment#customizePropertySources callback

 - Polish AbstractEnvironment Javadoc and formatting

Issue: SPR-9013
2012-02-16 21:31:10 +01:00
Chris Beams 80dd32e95c Disallow empty @PropertySource(value = {})
Previously, a user could specify an empty array of resource locations
to the @PropertySource annotation, which amounts to a meaningless no-op.

ConfigurationClassParser now throws IllegalArgumentException upon
encountering any such misconfiguration.
2012-02-16 18:25:53 +01:00
Chris Beams 41ade68b50 Fix @PropertySource bug with multiple values
Prior to this commit, specifying a named @PropertySource with multiple
values would not work as expected. e.g.:

  @PropertySource(
      name = "ps",
      value = { "classpath:a.properties", "classpath:b.properties" })

In this scenario, the implementation would register a.properties with
the name "ps", and subsequently register b.properties with the name
"ps", overwriting the entry for a.properties.

To fix this behavior, a CompositePropertySource type has been introduced
which accepts a single name and a set of PropertySource objects to
iterate over. ConfigurationClassParser's @PropertySource parsing routine
has been updated to use this composite approach when necessary, i.e.
when both an explicit name and more than one location have been
specified.

Note that if no explicit name is specified, the generated property
source names are enough to distinguish the instances and avoid
overwriting each other; this is why the composite wrapper is not used
in these cases.

Issue: SPR-9127
2012-02-16 18:25:03 +01:00
Juergen Hoeller ff862addbe final preparations for 3.1.1 release 2012-02-16 17:34:53 +01:00
Juergen Hoeller 94e3f08a44 added "receive-timeout" attribute to "jms:listener-container" element in JMS namespace (SPR-9114) 2012-02-16 12:03:09 +01:00
Chris Beams 1c2b1d2c85 Demonstrate use of @Configuration as meta-annotation
Issue: SPR-9090
2012-02-15 22:01:35 +01:00
Chris Beams 58e270f7da Prune dead code from JmsTransactionManager#doBegin 2012-02-15 21:11:29 +01:00
Chris Beams fc416bcb0b Apply @Configuration BeanNameGenerator consistently
Since the introduction of the AnnotationConfig(Web)ApplicationContext
types in Spring 3.0, it has been possible to specify a custom
bean name generation strategy via the #setBeanNameGenerator methods
available on each of these classes.

If specified, that BeanNameGenerator was delegated to the underlying
AnnotatedBeanDefinitionReader and ClassPathBeanDefinitionScanner. This
meant that any @Configuration classes registered or scanned directly
from the application context, e.g. via #register or #scan methods would
respect the custom name generation strategy as intended.

However, for @Configuration classes picked up via @Import or implicitly
registered due to being nested classes would not be aware of this
strategy, and would rather fall back to a hard-coded default
AnnotationBeanNameGenerator.

This change ensures consistent application of custom BeanNameGenerator
strategies in the following ways:

 - Introduction of AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
   singleton

   If a custom BeanNameGenerator is specified via #setBeanNameGenerator
   the AnnotationConfig* application contexts will, in addition to
   delegating this object to the underlying reader and scanner, register
   it as a singleton bean within the enclosing bean factory having the
   constant name mentioned above.

   ConfigurationClassPostProcessor now checks for the presence of this
   singleton, falling back to a default AnnotationBeanNameGenerator if
   not present. This singleton-based approach is necessary because it is
   otherwise impossible to parameterize CCPP, given that it is
   registered as a BeanDefinitionRegistryPostProcessor bean definition
   in AnnotationConfigUtils#registerAnnotationConfigProcessors

 - Introduction of ConfigurationClassPostProcessor#setBeanNameGenerator

   As detailed in the Javadoc for this new method, this allows for
   customizing the BeanNameGenerator via XML by dropping down to direct
   registration of CCPP as a <bean> instead of using
   <context:annotation-config> to enable  @Configuration class
   processing.

 - Smarter defaulting for @ComponentScan#beanNameGenerator

   Previously, @ComponentScan's #beanNameGenerator attribute had a
   default value of AnnotationBeanNameGenerator. The value is now the
   BeanNameGenerator interface itself, indicating that the scanner
   dedicated to processing each @ComponentScan should fall back to an
   inherited generator, i.e. the one originally specified against the
   application context, or the original default provided by
   ConfigurationClassPostProcessor. This means that name generation
   strategies will be consistent with a single point of configuration,
   but that individual @ComponentScan declarations may still customize
   the strategy for the beans that are picked up by that particular
   scanning.

Issue: SPR-9124
2012-02-15 15:33:35 +01:00
Chris Beams e81df2ef3e Improve @Configuration bean name discovery
Prior to this commit, and based on earlier changes supporting SPR-9023,
ConfigurationClassBeanDefinitionReader employed a simplistic strategy
for extracting the 'value' attribute (if any) from @Configuration in
order to determine the bean name for imported and nested configuration
classes. An example case follows:

  @Configuration("myConfig")
  public class AppConfig { ... }

This approach is too simplistic however, given that it is possible in
'configuration lite' mode to specify a @Component-annotated class with
@Bean methods, e.g.

  @Component("myConfig")
  public class AppConfig {
      @Bean
      public Foo foo() { ... }
  }

In this case, it's the 'value' attribute of @Component, not
@Configuration, that should be consulted for the bean name. Or indeed if
it were any other stereotype annotation meta-annotated with @Component,
the value attribute should respected.

This kind of sophisticated discovery is exactly what
AnnotationBeanNameGenerator was designed to do, and
ConfigurationClassBeanDefinitionReader now uses it in favor of the
custom approach described above.

To enable this refactoring, nested and imported configuration classes
are no longer registered as GenericBeanDefinition, but rather as
AnnotatedGenericBeanDefinition given that AnnotationBeanNameGenerator
falls back to a generic strategy unless the bean definition in question
is assignable to AnnotatedBeanDefinition.

A new constructor accepting AnnotationMetadata
has been added to AnnotatedGenericBeanDefinition in order to support
the ASM-based approach in use by configuration class processing. Javadoc
has been updated for both AnnotatedGenericBeanDefinition and its now
very similar cousin ScannedGenericBeanDefinition to make clear the
semantics and intention of these two variants.

Issue: SPR-9023
2012-02-15 15:33:35 +01:00
Chris Beams 08e2669b84 Fix infinite recursion bug in nested @Configuration
Prior to this commit, an infinite recursion would occur if a
@Configuration class were nested within its superclass, e.g.

  abstract class Parent {
      @Configuration
      static class Child extends Parent { ... }
  }

This is because the processing of the nested class automatically
checks the superclass hierarchy for certain reasons, and each
superclass is in turn checked for nested @Configuration classes.

The ConfigurationClassParser implementation now prevents this by
keeping track of known superclasses, i.e. once a superclass has been
processed, it is never again checked for nested classes, etc.

Issue: SPR-8955
2012-02-15 15:33:35 +01:00
Chris Beams f3651c9998 Polish static imports 2012-02-15 15:33:35 +01:00
Rossen Stoyanchev a3484aebb3 Minor fix in ServletResponseMethodArgumentResolver
Issues: SPR-8983
2012-02-15 09:20:02 -05:00
Juergen Hoeller 6fd476e2c5 extracted ResourceUtils.useCachesIfNecessary(URLConnection) method (SPR-9117) 2012-02-14 21:55:29 +01:00
Juergen Hoeller ab98f288e9 prepared for 3.1.1 release 2012-02-14 21:30:12 +01:00
Juergen Hoeller acaf820941 CustomSQLExceptionTranslatorRegistry/Registrar etc 2012-02-14 21:29:52 +01:00
Juergen Hoeller ddf0d071ad revised CustomSQLExceptionTranslatorRegistry/Registrar method naming 2012-02-14 21:29:22 +01:00
Juergen Hoeller 2fa87a71fa use custom InputStream traversal instead of a full byte array (SPR-9118) 2012-02-14 21:16:10 +01:00
Juergen Hoeller fe57f74c1a PathMatchingResourcePatternResolver preserves caching for JNLP jar connections (SPR-9117) 2012-02-14 18:26:56 +01:00
Juergen Hoeller 81861ca7a8 Resource "contentLength()" implementations work with OSGi bundle resources and JBoss VFS resources (SPR-9118) 2012-02-14 14:46:45 +01:00
Juergen Hoeller 4831ca27d2 fixed MethodInvokingJobDetailFactoryBean for compatibility with Quartz 2.0/2.1 (SPR-8889) 2012-02-14 14:43:37 +01:00
Juergen Hoeller 1bfa7013a0 fixed MethodInvokingJobDetailFactoryBean for compatibility with Quartz 2.0/2.1 () 2012-02-14 14:09:41 +01:00
Chris Beams 1d9d3e6ff7 Fix false negative test failure in ResourceTests
Prior to changes in commit 57851de88e,
AbstractResource#getFilename threw IllegalStateException unless
overridden by a subclass. Following that change, this method now throws
null instead, but ResourceTests#testAbstractResourceExceptions had not
been updated to reflect, resulting in a false negative failure. This has
now been fixed.

Issue: SPR-9043
2012-02-13 15:52:37 +01:00
Chris Beams 8e0b1c3a5f Compensate for Eclipse vs Sun compiler discrepancy
Eclipse allows autoboxing on type inference; Sun javac does not. This
means that variables assigned from calls to
AnnotationAttributes#getNumber should consistently use object wrappers
as opposed to number primitives. There was only one such instance
anyway, and has now been updated accordingly.
2012-02-13 15:37:19 +01:00
Chris Beams 0a5392e37d Compensate for changes in JDK 7 Introspector
Prior to JDK 7, java.beans.Introspector registered indexed write methods
irrespective of return type, for example either of the following methods
were legal

    void setFoo(int i, Foo foo)
    Object setFoo(int i, Foo foo)

This was considered a bug and disallowed starting with JDK 7, such that
only the former signature is a candidate.

Supporting non-void returning setter methods is exactly what
ExtendedBeanInfo was designed to do, and prior to this commit, the
implementation of ExtendedBeanInfo assumed this (somewhat surprising)
behavior from the underlying Introspector, and because it worked out of
the box, took no extra steps to recognize and register these methods.
For this reason, non-void returning indexed write methods were not
registered under JDK 7+, causing test failures in ExtendedBeanInfoTests.

Now the implementation is careful to detect these methods without any
assumption about Introspector behavior, such that they are registered in
exactly the same fashion across JDK versions.

Issue: SPR-9014
2012-02-13 15:01:06 +01:00
Chris Beams b787a68f20 Avoid 'type mismatch' errors in ExtendedBeanInfo
Prior to this commit, ExtendedBeanInfo would add non-indexed write
methods without consideration for the presence of indexed read/write
methods, which is invalid per the JavaBeans spec and per the behavior
of java.beans.Introspector.  That is, a method with the signature

    void setFoo(Foo foo)

Should never be registered as a write method if the following method
signature is also present in the class

    void setFoo(int i, Foo foo)

In most cases, this oversight caused no problems, but in certain
situations where a bean actually contains such a mismatch of methods,
"type mismatch" errors were thrown when ExtendedBeanInfo attempted the
illegal addition against the underlying property descriptor.

The implementation is now more careful about checking the parameter type
of write methods -- if the property descriptor in question is an
IndexedPropertyDescriptor, i.e. has an indexed write method, then any
non-indexed write method candidate must have a single *array* parameter,
which conforms to the spec and to Introspector behavior.

Issue: SPR-8937
2012-02-13 15:01:06 +01:00
Chris Beams ef143d363e Polish ExtendedBeanInfo and tests
ExtendedBeanInfo

 - Reduce log messages from warn to debug

 - Remove now-incorrect comment indicating underlying property
   descriptors are never modified (they actually are as of SPR-8806)

ExtendedBeanInfoTests

 - Consolidate SPR-8949 tests

 - Eliminate compiler warnings

Issue: SPR-8949, SPR-8806
2012-02-13 15:01:05 +01:00
Chris Beams e25f1cbca9 Infer AnnotationAttributes method return types
- Drop 'expectedType' parameter from #getClass and #getEnum methods and
   rely on compiler inference based on type of assigned variable, e.g.

     public @interface Example {
         Color color();
         Class<? extends UserType> userType();
         int order() default 0;
     }

     AnnotationAttributes example =
        AnnotationUtils.getAnnotationAttributes(Example.class, true, true);

     Color color = example.getEnum("color");
     Class<? extends UserType> userType = example.getClass("userType");

   or in cases where there is no variable assignment (and thus no
   inference possible), use explicit generic type, e.g.

     bean.setColor(example.<Color>getEnum("color"));

 - Rename #get{Int=>Number} and update return type from int to
   <N extends Number>, allowing invocations such as:

     int order = example.getNumber("order");

These changes reduce the overall number of methods exposed by
AnnotationAttributes, while at the same time providing comprehensive
access to all possible annotation attribute types -- that is, instead of
requiring explicit #getInt, #getFloat, #getDouble methods, the
single #getNumber method is capabable of handling them all, and without
any casting required. And the obvious additional benefit is more concise
invocation as no redundant 'expectedType' parameters are required.
2012-02-13 15:01:05 +01:00
Rossen Stoyanchev 997c6c56f7 Minor fix in MVC reference doc chapter
Issues: SPR-9111
2012-02-12 19:54:17 -05:00
jhoeller caa50a1d41 Merge pull request #33 from trisberg/SQLException-translation-enhancements
SQL exception translation enhancements
2012-02-12 07:19:21 -08:00
jhoeller 6e00456e67 Merge pull request #25 from trisberg/fixes-for-SimpleJdbcInsert
Fixes for SimpleJdbcInsert [SPR-9006]
2012-02-12 07:17:15 -08:00
Juergen Hoeller a46facc2f9 Hibernate 4.1 etc 2012-02-11 19:15:42 +01:00
Juergen Hoeller 9e21d2f741 TypeDescriptor equals implementation accepts annotations in any order (SPR-9084) 2012-02-11 19:15:41 +01:00
Juergen Hoeller 9470323724 "setBasenames" uses varargs now (for programmatic setup; SPR-9106) 2012-02-11 19:15:40 +01:00
Juergen Hoeller b17d545bb7 @ActiveProfiles mechanism works with @ImportResource as well (SPR-8992) 2012-02-11 19:15:39 +01:00
Juergen Hoeller 1bd260adaf polishing 2012-02-11 19:15:38 +01:00
Juergen Hoeller 57851de88e clarified Resource's "getFilename" method to consistently return null if resource type does not have a filename (SPR-9043) 2012-02-11 19:15:37 +01:00
Juergen Hoeller 1e1f8c912b substituteNamedParameters detects and unwraps SqlParameterValue objects (SPR-9052) 2012-02-11 19:15:35 +01:00
Rossen Stoyanchev 66bc214a79 Replace spaces with tabs 2012-02-10 18:24:58 -05:00
Chris Beams 45ad183331 Consider security in ClassUtils#getMostSpecificMethod
Recent changes in ExtendedBeanInfo involve invoking
ClassUtils#getMostSpecificMethod when determining JavaBeans get/set
pairs; if Java security settings control disallow reflective access,
this results in an AccessControlException.

This change defends against this (comparatively rare) scenario by
catching the exception and falling back to returning the method
originally supplied by the user.

This change was a result of noticing CallbacksSecurityTests failing
following the ExtendedBeanInfo modifications mentioned above

Issue: SPR-8949
2012-02-10 00:13:24 +01:00
Thomas Risberg 66012b951e Adding null check for username being null.
The username is usually not null, but it  could be for some embedded databases.

Always setting generatedKeysColumnNameArraySupported to false when getGeneratedKeysSupported is false, since it can't be supported without having generated keys supported. This change only affects logging messages.

Issue: SPR-9006
2012-02-09 17:55:04 -05:00
Thomas Risberg f6c7d99ba4 Improvements for registering custom SQL exception translators in app contexts.
Adding a static CustomSQLExceptionTranslatorRegistry and a CustomSQLExceptionTranslatorRegistrar that can be used to register custom SQLExceptionTranslator implementations for specific databases from any application context.

This can be used in application contexts like this:

  <bean class="org.springframework.jdbc.support.CustomSQLExceptionTranslatorRegistrar">
    <property name="sqlExceptionTranslators">
      <map>
        <entry key="H2">
          <bean class="com.yourcompany.data.CustomSqlExceptionTranslator"/>
        </entry>
      </map>
    </property>
  </bean>

Issue: SPR-7675
2012-02-09 17:43:05 -05:00
Thomas Risberg e202d89c29 SPR-7680 Adding QueryTimeoutException to the DataAccessException hierarchy 2012-02-09 17:18:38 -05:00
Rossen Stoyanchev 21aed042ea Minor polish in WebMvcConfigurationSupport 2012-02-09 16:54:55 -05:00
Chris Beams f1ecd1ca2a Detect overridden boolean getters in ExtendedBeanInfo
Prior to this commit, and due to idiosyncracies of
java.beans.Introspector, overridden boolean getter methods were not
detected by Spring's ExtendedBeanInfo, which relied on too-strict
Method equality checks when selecting read and write methods.

Now ExtendedBeanInfo uses Spring's ClassUtils#getMostSpecificMethod
against the methods returned from java.beans.Introspector in order
to ensure that subsequent equality checks are reasonable to make.

Issue: SPR-8949
2012-02-09 22:23:57 +01:00
Chris Beams c1df51a3b4 Polish ExtendedBeanInfoTests
Clean up ignored test, consolidate and document tests cornering
covariant return type edge cases.

Issue: SPR-8079, SPR-8806
2012-02-09 22:23:57 +01:00
Arjen Poutsma edc80ffa95 Use request contentType/encoding in ServletServetHttpRequest/Response
ServletServerHttpRequest now falls back on the contentType and the
the characterEncoding of the ServletRequest, if the headers of the
incoming request don't specify one. Similary ServletServerHttpResponse
sets the contentType and the characterEncoding of the ServletResponse
if not already set.

This allows using the CharacterEncodingFilter to set a character
encoding where the request doesn't specify one and have it be used
in HttpMessageConverter's.

SPR-9096
2012-02-09 12:34:27 -05:00
Chris Beams ff44c9132c Upgrade Hibernate from 4.0.0.CR7=>4.1.0.Final
spring-orm now successfully builds against Hibernate 4.1.0.Final

Issue: SPR-9082
2012-02-09 12:35:58 +01:00
Juergen Hoeller 0db257cbe3 restored preference for covariant return type if applicable 2012-02-09 12:24:13 +01:00
Juergen Hoeller 35c2869875 INSTANCE constant should be marked as final (SPR-9101) 2012-02-09 11:56:06 +01:00
Juergen Hoeller c931eaa436 documentation fixes (SPR-9025, SPR-9027) 2012-02-08 18:35:57 +01:00
Juergen Hoeller 357a5193b7 added reference documentation to IntelliJ project 2012-02-08 18:34:44 +01:00
Juergen Hoeller e4f2cfe39e Provider injection etc 2012-02-08 17:53:15 +01:00
Juergen Hoeller 4aa8b96687 write method parameter type preferred over read method parameter type for property conversion (fixing regression; SPR-8964) 2012-02-08 17:51:06 +01:00
Juergen Hoeller 17bbc623c1 optimized converter lookup to avoid contention in JDK proxy check (SPR-9084) 2012-02-08 17:08:57 +01:00
Juergen Hoeller c55362c35e Provider injection works with generically typed collections of beans as well (SPR-9030) 2012-02-08 16:29:00 +01:00
Juergen Hoeller 9a61f36d3d removed optional javax.validation.spi dependency (SPR-8973) 2012-02-08 12:52:51 +01:00
Juergen Hoeller 95e3f486b5 fixed SpringValidatorAdapter regression to return correct error codes for class-level constraints (SPR-8958) 2012-02-08 12:46:05 +01:00
Juergen Hoeller 2a0714b41c converted EmptyResultDataAccessException preserves JPA NoResultException as root cause (SPR-9041) 2012-02-08 12:23:15 +01:00
Juergen Hoeller efd2783dd1 restored JBossLoadTimeWeaver compability with JBoss AS 5.1 (SPR-9065) 2012-02-08 12:14:58 +01:00
jhoeller 5b18fc44ce Merge pull request #16 from cbeams/SPR-8954
Check original beanClass in #isFactoryBean calls
2012-02-08 02:58:19 -08:00
Rossen Stoyanchev 4f4a2e7fc7 Update documentation with regards to differences between @MVC 3.0/3.1
Although the reference documentation listed the new @MVC support
classes and their benefits, it did not explicitly mention a few
use cases that are no longer supported. There is now a specific
section on the new support classes listing exactly what is not
supported.

Similary the @RequestMapping annotation never refered explicitly
to the existence of old and new support and never made it clear
exactly what the differences are.

Both have not been corrected.

SPR-9063, SPR-9042
2012-02-07 19:49:44 -05:00
Chris Beams bf541db5b0 Refactor to consistent use of AnnotationAttributes
Uses of AnnotationMetadata#getAnnotationAttributes throughout the
framework have been updated to use the new AnnotationAttributes API in
order to take advantage of the more concise, expressive and type-safe
methods there.

All changes are binary compatible to the 3.1.0 public API, save
the exception below.

A minor binary compatibility issue has been introduced in
AbstractCachingConfiguration, AbstractAsyncConfiguration and
AbstractTransactionManagementConfiguration when updating their
protected Map<String, Object> fields representing annotation attributes
to use the new AnnotationAttributes API. This is a negligible breakage,
however, as the likelilhood of users subclassing these types is very
low, the classes have only been in existence for a short time (further
reducing the likelihood), and it is a source-compatible change given
that AnnotationAttributes is assignable to Map<String, Object>.
2012-02-07 21:57:49 +01:00
Chris Beams d9f7fdd120 Support reading nested annotations via ASM
Background

  Spring 3.1 introduced the @ComponentScan annotation, which can accept
  an optional array of include and/or exclude @Filter annotations, e.g.

     @ComponentScan(
         basePackages = "com.acme.app",
         includeFilters = { @Filter(MyStereotype.class), ... }
     )
     @Configuration
     public class AppConfig { ... }

  @ComponentScan and other annotations related to @Configuration class
  processing such as @Import, @ImportResource and the @Enable*
  annotations are parsed using reflection in certain code paths, e.g.
  when registered directly against AnnotationConfigApplicationContext,
  and via ASM in other code paths, e.g. when a @Configuration class is
  discovered via an XML bean definition or when included via the
  @Import annotation.

  The ASM-based approach is designed to avoid premature classloading of
  user types and is instrumental in providing tooling support (STS, etc).

  Prior to this commit, the ASM-based routines for reading annotation
  attributes were unable to recurse into nested annotations, such as in
  the @Filter example above. Prior to Spring 3.1 this was not a problem,
  because prior to @ComponentScan, there were no cases of nested
  annotations in the framework.

  This limitation manifested itself in cases where users encounter
  the ASM-based annotation parsing code paths AND declare
  @ComponentScan annotations with explicit nested @Filter annotations.
  In these cases, the 'includeFilters' and 'excludeFilters' attributes
  are simply empty where they should be populated, causing the framework
  to ignore the filter directives and provide incorrect results from
  component scanning.

  The purpose of this change then, is to introduce the capability on the
  ASM side to recurse into nested annotations and annotation arrays. The
  challenge in doing so is that the nested annotations themselves cannot
  be realized as annotation instances, so must be represented as a
  nested Map (or, as described below, the new AnnotationAttributes type).

  Furthermore, the reflection-based annotation parsing must also be
  updated to treat nested annotations in a similar fashion; even though
  the reflection-based approach has no problem accessing nested
  annotations (it just works out of the box), for substitutability
  against the AnnotationMetadata SPI, both ASM- and reflection-based
  implementations should return the same results in any case. Therefore,
  the reflection-based StandardAnnotationMetadata has also been updated
  with an optional 'nestedAnnotationsAsMap' constructor argument that is
  false by default to preserve compatibility in the rare case that
  StandardAnnotationMetadata is being used outside the core framework.
  Within the framework, all uses of StandardAnnotationMetadata have been
  updated to set this new flag to true, meaning that nested annotation
  results will be consistent regardless the parsing approach used.

  Spr9031Tests corners this bug and demonstrates that nested @Filter
  annotations can be parsed and read in both the ASM- and
  reflection-based paths.

Major changes

 - AnnotationAttributes has been introduced as a concrete
   LinkedHashMap<String, Object> to be used anywhere annotation
   attributes are accessed, providing error reporting on attribute
   lookup and convenient type-safe access to common annotation types
   such as String, String[], boolean, int, and nested annotation and
   annotation arrays, with the latter two also returned as
   AnnotationAttributes instances.

 - AnnotationUtils#getAnnotationAttributes methods now return
   AnnotationAttributes instances, even though for binary compatibility
   the signatures of these methods have been preserved as returning
   Map<String, Object>.

 - AnnotationAttributes#forMap provides a convenient mechanism for
   adapting any Map<String, Object> into an AnnotationAttributes
   instance. In the case that the Map is already actually of
   type AnnotationAttributes, it is simply casted and returned.
   Otherwise, the map is supplied to the AnnotationAttributes(Map)
   constructor and wrapped in common collections style.

 - The protected MetadataUtils#attributesFor(Metadata, Class) provides
   further convenience in the many locations throughout the
   .context.annotation packagage that depend on annotation attribute
   introspection.

 - ASM-based core.type.classreading package reworked

   Specifically, AnnotationAttributesReadingVisitor has been enhanced to
   support recursive reading of annotations and annotation arrays, for
   example in @ComponentScan's nested array of @Filter annotations,
   ensuring that nested AnnotationAttributes objects are populated as
   described above.

   AnnotationAttributesReadingVisitor has also been refactored for
   clarity, being broken up into several additional ASM
   AnnotationVisitor implementations. Given that all types are
   package-private here, these changes represent no risk to binary
   compatibility.

 - Reflection-based StandardAnnotationMetadata updated

   As described above, the 'nestedAnnotationsAsMap' constructor argument
   has been added, and all framework-internal uses of this class have
   been updated to set this flag to true.

Issue: SPR-7979, SPR-8719, SPR-9031
2012-02-07 21:57:49 +01:00
Juergen Hoeller 905d17d444 LocalContainerEntityManagerFactoryBean etc 2012-02-07 21:00:14 +01:00
Juergen Hoeller 62e5b9da04 LocalContainerEntityManagerFactoryBean's "persistenceUnitName" applies to "packagesToScan" as well; DefaultPersistenceUnitManager uses containing jar as persistence unit root URL for default unit (SPR-8832) 2012-02-07 20:59:48 +01:00
Juergen Hoeller f367619b0c added "durability" and "description" properties to JobDetailFactoryBean (SPR-9080) 2012-02-07 15:54:18 +01:00
Juergen Hoeller afa4bb3f1b fixed javadoc link (SPR-9089) 2012-02-07 15:54:17 +01:00
Juergen Hoeller f8238f5243 Servlet/PortletContextResource's "isReadable()" implementation returns false for directories (SPR-9067) 2012-02-07 15:54:16 +01:00
Arjen Poutsma 7a170e8005 Updated IntelliJ project for JUnit 4.9.0 2012-02-07 15:41:49 +01:00
Arjen Poutsma 3ec78e2c04 SPR-9093: UriTemplate not throwing IllegalArgumentException when URIVariables map missing values 2012-02-07 15:40:50 +01:00
Rossen Stoyanchev a3bb3769ba Tighten FlashMapManager for use with alternative storage options
Ensure that both FlashMapManager methods - the one invoked at the
start of a request and the one invoked before a redirect, update
the underlying storage fully since it's not guaranteed that both
will be invoked on any given request.

Also move the logic to remove expired FlashMap instances to the
metohd invoked at the start of a request to ensure the check is
made frequently enough.

SPR-8997
2012-02-06 18:04:27 -05:00
Chris Beams 598b125bb2 Merge pull request #27 from trisberg/parameter-parsing 2012-02-06 09:47:35 +01:00
Thomas Risberg 9fb6e2313c Fix single quote parsing in NamedParameterUtils
Prior to this change, single quotes were incorrectly parsed by
NamedParameterUtils#parseSqlStatement, resulting in incorrect parameter
counts:

    ParsedSql sql = NamedParameterUtils
            .parseSqlStatement("SELECT 'foo''bar', :xxx FROM DUAL");
    assert sql.getTotalParameterCount() == 0 // incorrect, misses :xxx

That is, presence of the single-quoted string caused the parser to
overlook the named parameter :xxx.

This commit fixes the parsing error such that:

    ParsedSql sql = NamedParameterUtils
            .parseSqlStatement("SELECT 'foo''bar', :xxx FROM DUAL");
    assert sql.getTotalParameterCount() == 1 // correct

Issue: SPR-8280
2012-02-06 09:47:17 +01:00
Chris Beams ff84419f4d Merge pull request #26 from trisberg/improved-RDP 2012-02-06 09:04:08 +01:00
Thomas Risberg 2ffa4725cd Allow SELECT statements in ResourceDatabasePopulator
ResourceDatabasePopulator is a component that underlies the database
initialization support within Spring's jdbc: namespace, e.g.:

    <jdbc:initialize-database data-source="dataSource">
        <jdbc:script execution="INIT" location="classpath:init.sql"/>
    </jdbc:initialize-database>

Prior to this commit, ResourceDatabasePopulator#executeSqlScript's use
of Statement#executeUpdate(sql) precluded the possibility of SELECT
statements because returning a result is not permitted by this method
and results in an exception being thrown.

Whether this behavior is a function of the JDBC specification or an
idiosyncracy of certain implementations does not matter as the issue
can be worked around entirely. This commit eliminates use
of #executeUpdate(sql) in favor of #execute(sql) followed by a call
to #getUpdateCount, effectively allowing any kind of SQL statement to
be executed during database initialization.

Issue: SPR-8932
2012-02-06 08:59:28 +01:00
Chris Beams 025b8abfaf Allow ACI classes access to servlet context params
Prior to this commit, StandardServletEnvironment's servlet context
PropertySource remained stubbed out until it the ServletContext became
available and could be replaced during the refresh() of its enclosing
WebApplicationContext. This behavior is acceptable in most cases.
However, if the user has declared an ApplicationContextInitializer that
attempts to access servlet context-params via the Environment API, this
result in a kind of 'false negative', i.e. the context-param key and
value are actually present in the ServletContext, but the PropertySource
representing servlet context params is still a stub at this point,
meaning that it returns an empty result in all cases.

With this change, WebApplicationContextUtils#initServletPropertySources
is invoked eagerly by the ContextLoader if any ACI classes have been
declared. This swaps out the servlet context property source stub for
the real thing just in time for ACIs to use it if necessary.

Extra guard logic has been added to #initServletPropertySources to
ensure idempotency -- once the stub has been replaced, the method
never attempts the replacement again, e.g. during the normal context
refresh() when this method will be called again.

Issue: SPR-8991
2012-02-04 23:13:52 +01:00
Chris Beams 856b77bc31 Optimize ApplicationContextInitializer handling
- Perform early check whether any ACI classes have been declared and
   exit immediately if not, avoiding any other processing

 - Polish method names in ContextLoaderTests

Issue: SPR-8991
2012-02-04 23:13:48 +01:00
Chris Beams a9451d11f6 Relax -aspects dependence on -test (compile=>test)
The spring-aspects Maven pom had an incorrect compile-scoped dependence
on spring-test. In fact, spring-aspects only uses spring-test in its
unit tests. The pom has been updated accordingly, meaning that use
of spring-aspects in Maven-based applications will no longer require
spring-test on the classpath at runtime.

ivy.xml metadata did not need updating, as it was already correct.

This change is only necessary on the 3.1.x line; in 3.2.x (master) Maven
poms are generated automatically from Gradle dependency metadata, which
is also already correct.

Issue: SPR-9048
2012-02-04 17:49:11 +01:00
Rossen Stoyanchev 871336a8c8 Better support for @SessionAttributes in clustered environments
A list of "known" session attributes (listed in @SessionAttributes)
was gradually built as attributes get added to the model. In a
failover scenario that knowledge is lost causing session attributes
to be potentially re-initialized via @ModelAttribute methods.

With this change @SessionAttributes listed by name are immediately
added to he list of "known" session attributes thus this knowledge
is not lost after a failover. Attributes listed by type however
still must be discovered as they get added to the model.
2012-02-03 12:23:24 -05:00
Chris Beams 81e25b91c2 Respect @Configuration(value) for @Imported classes
Prior to this commit, @Configuration classes included via @Import (or
via automatic registration of nested configuration classes) would
always be registered with a generated bean name, regardless of whether
the user had specified a 'value' indicating a customized bean name, e.g.

    @Configuration("myConfig")
    public class AppConfig { ... }

Now this bean name is propagated as intended in all cases, meaning that
in the example above, the resulting bean definition of type AppConfig
will be named "myConfig" regardless how it was registered with the
container -- directly against the application context, via component
scanning, via @Import, or via automatic registration of nested
configuration classes.

Issue: SPR-9023
2012-02-03 17:54:03 +01:00
Rossen Stoyanchev 6e5cc53fc9 SPR-9085 Correct typo. 2012-02-02 09:56:02 -05:00
Chris Beams 17cf465d23 Fix method equality bug in ExtendedBeanInfo
A number of users reported issues with comparing method identity vs
equivalence when discovering JavaBeans property methods in
ExtendedBeanInfo.

This commit updates the implementation to consistently use '.equals()'
instead of '=='.

Issue: SPR-8079, SPR-8347
2012-02-02 15:24:52 +01:00
Chris Beams f3f73f0e32 Check original beanClass in #isFactoryBean calls
This issue originates from a need in Spring Data JPA, wherein a custom
InstantiationAwareBeanPostProcessor may alter the predicted type of
FactoryBean objects, effectively preventing retrieval of those beans via
calls to #getBeansOfType(FactoryBean.class).

The reason for this "masking effect" is that prior to this change, the
implementation of AbstractBeanFactory#isFactoryBean considered only the
"predicted type" returned from #predictBeanType when evaluating
assignability to FactoryBean.class

The implementation of #isFactoryBean now ensures that not only the
predicted bean type is considered, but also the original bean
definition's beanClass (if one is available).

Issue: SPR-8954
2012-02-02 12:38:23 +01:00
Rossen Stoyanchev 010abd06e3 SPR-9077 Remove empty path segments from input to UriComponentsBuilder. 2012-02-01 19:51:00 -05:00
Rossen Stoyanchev 8530828eb4 SPR-9076 Add normalize() method to UriComponents. 2012-02-01 19:12:52 -05:00
Rossen Stoyanchev 95683f5137 SPR-9075 Add fromRequestUri() methods to ServletUriComponentsBuilder 2012-02-01 18:54:08 -05:00
Chris Beams f61410705c Merge pull request #21 from aclement/spr9038 2012-02-01 22:47:36 +01:00
Rossen Stoyanchev 64a69f7cf8 SPR-9079 Don't check for "POST" multipart request method arg resolvers 2012-02-01 13:22:12 -05:00
Andy Clement 90bed9718f Allow customization of SpEL method resolution
This change introduces a protected ReflectiveMethodResolver#getMethods,
allowing subclasses to specify additional static methods not
declared directly on the type being evaluated. These methods then become
candidates for filtering by any registered MethodFilters and ultimately
become available within for use within SpEL expressions.

Issue: SPR-9038
2012-02-01 17:36:57 +01:00
Chris Beams c7fd03be69 Polish ReflectiveMethodResolver and unit tests
- Update Javadoc
 - Fix whitespace errors (tabs v. spaces, trailing spaces)
 - Break at 90 chars where sensible
 - Remove dead test code
 - Fix generics warnings, remove @SuppressWarnings
2012-02-01 17:36:57 +01:00
Rossen Stoyanchev 3d1fa4f6b6 SPR-9060 Revise HTTP Session based FlashMapManager implementation.
The "default" FlashMapManager implementation added in 3.1 was invoked
after the redirect, which is too late in cases where the HTTP session
has not been yet been created since as the response is committed.

This change corrects the issue and makes other improvements to the
FlashMapManager implementation such as extracting a base
AbstractFlashMapManager class and making it easier for other
implementations to be added (for example cookie-based).
2012-01-31 22:10:55 -05:00
Chris Beams f3c3babfdf Update Quartz links in reference and Javadoc
Issue: SPR-8915
2012-01-31 15:18:05 +01:00
Chris Beams 87a021d5c9 Add <license> section to 3.1.x Maven poms
Issue: SPR-8927
2012-01-31 15:18:05 +01:00
Chris Beams 38a62f8389 Ignore Gradle-related files and directories
When switching back to 3.1.x from master, ignore renamed directories,
Gradle 'build' dirs, generated IDE metadata, etc.

You may wish to clean these files with

    $ git clean -dfx

Or do a dry-run beforehand with the '-n' flag:

    $ git clean -dfxn
2012-01-31 15:18:05 +01:00
Rossen Stoyanchev e9208981a6 SPR-9062 Fix bug with ambiguous path and HTTP method request mappings
A direct path match with incorrect HTTP request method was causing another
request mapping with a pattern and a correct HTTP method to be ignored.
The bug affects the new @MVC support classes
(i.e. RequestMappingHandlerMapping).
2012-01-30 19:52:20 -05:00
Rossen Stoyanchev 21966990c8 SPR-9016 Add flag to Redirectview to disable expanding URI vars 2012-01-30 18:39:20 -05:00
Rossen Stoyanchev 610fa618aa SPR-9056 Make DelegatingWebMvcConfiguration config callbacks not final
It should be possible to progress from extending
WebMvcConfigurerAdapter (w/ @EnableWebMvc) to extending
WebMvcConfigurationSupport directly, to extending
DelegatingWebMvcConfigurationSupport. This change
makes that possible.
2012-01-30 17:55:34 -05:00
Arjen Poutsma 8980ce712d SPR-8986 RestTemplate throws IllegalArgumentException when HTTP status is not in the HttpStatus enum
- Added getRawStatusCode
2012-01-23 14:26:11 +01:00
Arjen Poutsma ff9ad7adc6 SPR-8986 RestTemplate throws IllegalArgumentException when HTTP status is not in the HttpStatus enum
- Added status codes from Wikipedia
2012-01-23 14:03:14 +01:00
Arjen Poutsma 79f32c7f33 SPR-8986 Add the ability to Scan Packages for JAXB Marshalling
Jaxb2Marshaller now has the capability to scan for classes annotated with JAXB2 annotations.
2012-01-20 16:25:33 +01:00
Rossen Stoyanchev bcd8355e61 SPR-8974 Fix regression in UriUtils.java 2012-01-19 23:47:31 -05:00
Chris Beams 9c45acd43a Update links to reference and api documentation 2012-01-16 22:16:43 +01:00
Juergen Hoeller 958bd49850 Hibernate 4 LocalSessionFactoryBean, etc 2012-01-15 20:09:35 +01:00
Juergen Hoeller 697bc43c40 added missing @Override annotations 2012-01-15 20:07:51 +01:00
Juergen Hoeller 3fdbe1081d JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers () 2012-01-15 20:07:50 +01:00
Juergen Hoeller 4a63a5b3ba fixed "configTimeRegionFactoryHolder" reset 2012-01-15 20:07:49 +01:00
Juergen Hoeller 56d0e67581 added "getConfiguration" accessor to Hibernate 4 LocalSessionFactoryBean (SPR-8961) 2012-01-15 20:07:49 +01:00
Juergen Hoeller 96b8c46480 nicer error message indicating JAX-WS 2.1 requirement at runtime (SPR-8998) 2012-01-15 20:07:48 +01:00
Juergen Hoeller b91e989ad4 JMS CachingConnectionFactory never caches consumers for temporary queues and topics 2012-01-15 20:07:47 +01:00
Rossen Stoyanchev e8fc90ce3e SPR-8917 Fix issue with quoted parameter values in MediaType. 2012-01-13 15:25:53 -05:00
Rossen Stoyanchev b0c735feae SPR-8976 Make flash attrs available to view controllers.
Previously flash attributes were automatically merged into the
model of annotated controllers only. This change extends the same
benefit to ParameterizableView- and UrlFilenameViewController,
both of which merely select a view without user controller logic
and (the views) would otherwise  not have access to the flash
attributes.
2012-01-13 13:18:53 -05:00
Rossen Stoyanchev be4e698483 SPR-9021 Correct issue in comparing Accept header media types.
When checking for an exact match of Accept header media types
additional parameters such as quality need to be excluded.
For example "*/*" matches "*/*;q=0.9".
2012-01-12 17:13:11 -05:00
Rossen Stoyanchev 6da6acbe54 Make AbstractHandlerMethodExceptionResolver an abstract class. 2012-01-11 11:10:52 -05:00
Arjen Poutsma ab6a7e8e74 Polishing 2012-01-11 11:48:20 +01:00
Rossen Stoyanchev 5a2bd97c37 SPR-8997 Add getter for access to flash timeout. 2012-01-10 22:24:14 -05:00
Chris Beams d7d1b495f2 Polish "Support flash attrs..." and related classes
- Eliminate trailing whitespace

 - Update long method signatures to follow framework whitespace
   conventions

   Based on the following search,

       $ git grep -A3 '^.public .* .*([^\{;]*$' */src/main

   the strong convention throughout the framework when dealing with
   methods having long signatures (i.e. many parameters) is to break
   immediately after the opening paren, indent two tabs deeper and break
   lines around 90 characters as necessary. Such signatures should also
   be followed by a newline after the opening curly brace to break
   things up visually.

   The files edited in this commit had a particularly different style of
   intenting arguments to align with each other vertically, but the
   alignment only worked if one's tabstop is set at four spaces.
   When viewed at a different tabstop value, the effect is is jarring,
   both in that it is misaligned and significantly different from most
   of the framework. The convention described above reads well at any
   tabstop value.
2012-01-10 12:21:14 -05:00
Rossen Stoyanchev 92f8446eea SPR-8997 Add HttpServletResponse to FlashMapManager contract.
This change makes the HttpServletResponse available to the methods
of FlashMapManager in addition to the HttpServletRequest.
2012-01-10 10:47:47 -05:00
Rossen Stoyanchev 66df039b03 SPR-8698 Support flash attrs and a ModelAndView return value.
Before this change, flash attributes could only be added if via
RedirectAttributes.addFlashAttribute(..) if the method returned
a view name or a View instance. With this change, the above is
supported with a ModelAndView return value as well.
2012-01-09 20:18:44 -05:00
Rossen Stoyanchev fe0ffec8b9 SPR-7799 Minor fix in documentation. 2012-01-09 19:13:50 -05:00
Rossen Stoyanchev a4b33533d3 SPR-9001 Javadoc fix 2012-01-06 18:23:46 -05:00
Costin Leau 66d4e45b58 add getCacheManager() for access to native class 2012-01-06 18:23:07 -05:00
Juergen Hoeller e208a2de5f JBoss AS 7, etc 2012-01-05 17:38:02 +01:00
Juergen Hoeller adac38f91b fixed documented bean class names in jdbc namespace xsd (SPR-8972) 2012-01-05 17:38:01 +01:00
Juergen Hoeller affa733927 Hibernate exception translation covers NonUniqueObjectException to DuplicateKeyException case (SPR-8996) 2012-01-05 17:38:00 +01:00
Juergen Hoeller 211f8ea854 JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well (SPR-8957) 2012-01-05 17:37:59 +01:00
Chris Beams af38448181 Ignore spring-build 'docbook' directory 2011-12-23 09:30:04 +01:00
Juergen Hoeller d331c5d1c9 correctly handle ParseException from Formatter for String->String case (SPR-8944) 2011-12-22 16:30:22 +01:00
Juergen Hoeller 3d5e245374 CacheNamespaceHandler etc 2011-12-22 15:54:17 +01:00
Juergen Hoeller 89ee5e2d80 DataBinder etc 2011-12-22 15:54:17 +01:00
Juergen Hoeller 86bef9030f correctly handle ParseException from Formatter for String->String case (SPR-8944) 2011-12-22 15:54:17 +01:00
Costin Leau 0053319c62 Add test to corner potential bug with @CacheEvict
Cannot yet actually reproduce the issue, but this remains a useful
test case.

Issue: SPR-8934
2011-12-22 15:07:59 +01:00
Costin Leau c39a14a130 Parse cache:annotation-driven key-generator attribute
Prior to this change, the spring-cache XSD allowed a 'key-generator'
attribute, but it was not actually parsed by AnnotationDrivenCacheBDP.

This commit adds the parsing logic as originally intended and the test
to prove it.

Issue: SPR-8939
2011-12-22 14:50:45 +01:00
Costin Leau e9ab1a7abb Update cache ref docs re 'args' vs 'params' naming
Prior to this change, the caching reference docs referred to
'root.params', whereas the actual naming should be 'root.args'. This
naming was also reflected in the "#p" syntax for specifying method args.

This change updates the documentation to refer to 'root.args' properly
and also adds "#a" syntax for specifying method arguments more
intuitively. Note that "#p" syntax remains in place as an alias for
backward compatibility.

Issue: SPR-8938
2011-12-22 14:31:21 +01:00
Chris Beams 02cd8681d4 Normalize whitespace in cache reference doc 2011-12-22 14:16:41 +01:00
Chris Beams 41c405998e Convert CRLF=>LF on files missed earlier
Complete pass with `dos2unix` found additional files missed on earlier
related commit.

Issue: SPR-5608
2011-12-22 14:06:44 +01:00
Juergen Hoeller f1168ea453 DefaultPersistenceUnitManager etc 2011-12-22 13:31:09 +01:00
Juergen Hoeller 103c648a92 added protected "isPersistenceUnitOverrideAllowed()" method to DefaultPersistenceUnitManager (SPR-8925) 2011-12-22 13:31:08 +01:00
Juergen Hoeller e0252ad0b1 "file-encoding" attribute value is being applied correctly (SPR-8024) 2011-12-22 13:31:08 +01:00
Juergen Hoeller 4b138e0e50 Hibernate etc 2011-12-22 13:31:08 +01:00
Juergen Hoeller 07ddedd7bf Hibernate synchronization properly unbinds Session even in case of afterCompletion exception (SPR-8757) 2011-12-22 13:31:08 +01:00
Juergen Hoeller 09ac195f0c do not insist on a "dataSource" reference being set (SPR-8924) 2011-12-22 13:31:08 +01:00
Juergen Hoeller 2caca29498 deprecated TopLinkJpaDialect, etc 2011-12-22 13:31:07 +01:00
Juergen Hoeller 391434e089 officially deprecated TopLinkJpaDialect in favor of EclipseLink and Spring's EclipseLinkJpaDialect; updated supported version ranges for EclipseLink and OpenJPA 2011-12-22 13:31:07 +01:00
Juergen Hoeller 392247d674 Hibernate 4 LocalSessionFactoryBean implements PersistenceExceptionTranslator interface as well (SPR-8952); consistent extending of HibernateExceptionTranslator for Hibernate 3 as well as Hibernate 4 2011-12-22 13:26:45 +01:00
Juergen Hoeller 1c9fe623f9 further post-GA fixes 2011-12-22 13:26:09 +01:00
Juergen Hoeller eb31528979 added "entityInterceptor" property to Hibernate 4 LocalSessionFactoryBean (SPR-8940) 2011-12-22 13:23:56 +01:00
Juergen Hoeller 00ff8fa2cc corrected fix for QuartzJobBean to work with Quartz 2.0/2.1 (SPR-8889) 2011-12-22 13:19:18 +01:00
Juergen Hoeller cc2e558fe0 prepared for 3.1.1 2011-12-22 13:19:18 +01:00
Juergen Hoeller e0231438cd fixed "packagesToScan" to avoid additional provider scan (SPR-8936) 2011-12-22 13:19:18 +01:00
Chris Beams 02452a1af9 Minor copy edits to README 2011-12-22 13:19:18 +01:00
Chris Beams 36d941fc99 Add readme 2011-12-22 13:19:18 +01:00
Chris Beams 88913f2b23 Convert CRLF (dos) to LF (unix)
Prior to this change, roughly 5% (~300 out of 6000+) of files under the
source tree had CRLF line endings as opposed to the majority which have
LF endings.

This change normalizes these files to LF for consistency going forward.

Command used:

$ git ls-files | xargs file | grep CRLF | cut -d":" -f1 | xargs dos2unix

Issue: SPR-5608
2011-12-21 14:52:47 +01:00
Rossen Stoyanchev e1b645368a Add missing (empty) source folders 2011-12-20 11:17:14 -05:00
Chris Beams e158f61e93 Increment version to 3.1.1.BUILD-SNAPSHOT 2011-12-16 11:59:06 +01:00
Juergen Hoeller dfc5b482c9 IntelliJ IDEA 11 project setup 2011-12-16 11:56:51 +01:00
Chris Beams abb5fc094a Add spring-build 2.5.2
spring-build was previously included via an svn:external. Adding
directly to the source tree under Git to avoid the need for a git
submodule.

In order to build from any earlier commit, it is recommended to
export spring-build or symlink an existing copy into the root
of the spring-framework project and then build normally.

    $ svn export https://src.springsource.org/svn/spring-build/tags/project-build-2.5.2 spring-build
2011-12-16 11:56:51 +01:00
1020 changed files with 68052 additions and 49835 deletions
+9 -1
View File
@@ -14,5 +14,13 @@ org.springframework.jdbc/derby.log
org.springframework.spring-parent/.classpath
org.springframework.spring-parent/.project
org.springframework.test/test-output/
spring-build
target
spring-build/lib/docbook
# ignore files and directories related to gradle build
/.classpath
/.project
/.gradle
/build
/spring-*
!/spring-framework-reference
+59
View File
@@ -0,0 +1,59 @@
## Spring Framework
The Spring Framework provides a comprehensive programming and configuration model for modern
Java-based enterprise applications - on any kind of deployment platform. A key element of Spring is
infrastructural support at the application level: Spring focuses on the "plumbing" of enterprise
applications so that teams can focus on application-level business logic, without unnecessary ties
to specific deployment environments.
The framework also serves as the foundation for
[Spring Integration](https://github.com/SpringSource/spring-integration),
[Spring Batch](https://github.com/SpringSource/spring-batch) and the rest of the Spring
[family of projects](http://springsource.org/projects). Browse the repositories under the
[SpringSource organization](https://github.com/SpringSource) on GitHub for a full list.
[.NET](https://github.com/SpringSource/spring-net) and
[Python](https://github.com/SpringSource/spring-python) variants are available as well.
## Downloading artifacts
Instructions on
[downloading Spring artifacts](https://github.com/SpringSource/spring-framework/wiki/Downloading-Spring-artifacts)
via Maven and other build systems are available via the project wiki.
## Documentation
See the current [Javadoc](http://static.springsource.org/spring-framework/docs/current/api)
and [Reference docs](http://static.springsource.org/spring-framework/docs/current/reference).
## Getting support
Check out the [Spring forums](http://forum.springsource.org) and the
[Spring tag](http://stackoverflow.com/questions/tagged/spring) on StackOverflow.
[Commercial support](http://springsource.com/support/springsupport) is available too.
## Issue Tracking
Spring's JIRA issue tracker can be found [here](http://jira.springsource.org/browse/SPR). Think
you've found a bug? Please consider submitting a reproduction project via the
[spring-framework-issues](https://github.com/springsource/spring-framework-issues) repository. The
[readme](https://github.com/springsource/spring-framework-issues#readme) provides simple
step-by-step instructions.
## Building from source
Instructions on
[building Spring from source](https://github.com/SpringSource/spring-framework/wiki/Building-from-source)
are available via the project wiki.
## Contributing
[Pull requests](http://help.github.com/send-pull-requests) are welcome; you'll be asked to sign our
contributor license agreement ([CLA](https://support.springsource.com/spring_committer_signup)).
Trivial changes like typo fixes are especially appreciated (just
[fork and edit!](https://github.com/blog/844-forking-with-the-edit-button)). For larger changes,
please search through JIRA for similiar issues, creating a new one if necessary, and discuss your
ideas with the Spring team.
## Staying in touch
Follow [@springframework](http://twitter.com/springframework) and its
[team members](http://twitter.com/springframework/team/members) on Twitter. In-depth articles can be
found at the SpringSource [team blog](http://blog.springsource.org), and releases are announced via
our [news feed](http://www.springsource.org/news-events).
## License
The Spring Framework is released under version 2.0 of the
[Apache License](http://www.apache.org/licenses/LICENSE-2.0).
+12 -12
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+81 -81
View File
@@ -1,81 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="build-spring-framework" default="precommit">
<path id="unit.test.bundles">
<pathelement location="../org.springframework.instrument"/>
<pathelement location="../org.springframework.instrument.tomcat"/>
<pathelement location="../org.springframework.core"/>
<pathelement location="../org.springframework.expression"/>
<pathelement location="../org.springframework.beans"/>
<pathelement location="../org.springframework.aop"/>
<pathelement location="../org.springframework.context"/>
<pathelement location="../org.springframework.transaction"/>
<pathelement location="../org.springframework.oxm"/>
<pathelement location="../org.springframework.jms"/>
<pathelement location="../org.springframework.jdbc"/>
<pathelement location="../org.springframework.web"/>
<pathelement location="../org.springframework.orm"/>
<pathelement location="../org.springframework.context.support"/>
<pathelement location="../org.springframework.aspects"/>
<pathelement location="../org.springframework.web.servlet"/>
<pathelement location="../org.springframework.web.portlet"/>
<pathelement location="../org.springframework.test"/>
<pathelement location="../org.springframework.web.struts"/>
</path>
<path id="bundles">
<pathelement location="../org.springframework.spring-parent"/>
<pathelement location="../org.springframework.asm"/>
<path refid="unit.test.bundles" />
<pathelement location="../org.springframework.integration-tests"/>
<pathelement location="../org.springframework.spring-library"/>
</path>
<property file="${basedir}/../build.properties"/>
<import file="${basedir}/package-top-level.xml"/>
<import file="${basedir}/publish-top-level.xml"/>
<import file="${basedir}/publish-documentation.xml"/>
<import file="${basedir}/../spring-build/multi-bundle/default.xml"/>
<target name="precommit" depends="clean, clean-integration, test"/>
<presetdef name="javadoc.links">
<javadoc>
<link href="http://download.oracle.com/javase/6/docs/api"/>
<link href="http://download.oracle.com/javaee/6/api"/>
<link href="http://aopalliance.sourceforge.net/doc"/>
<!-- Caucho Burlap/Hessian -->
<link href="http://cglib.sourceforge.net/apidocs"/>
<!-- EasyMock -->
<link href="http://ehcache.sourceforge.net/apidocs"/>
<link href="http://freemarker.sourceforge.net/docs/api/"/>
<link href="http://docs.jboss.org/hibernate/core/3.6/javadocs/"/>
<!-- iBATIS -->
<!-- iText -->
<!-- Commons Attributes -->
<link href="http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/"/>
<link href="http://jakarta.apache.org/commons/dbcp/apidocs/"/>
<link href="http://jakarta.apache.org/commons/fileupload/apidocs/"/>
<link href="http://jakarta.apache.org/commons/httpclient/apidocs/"/>
<link href="http://jakarta.apache.org/commons/logging/apidocs/"/>
<link href="http://jakarta.apache.org/commons/pool/apidocs/"/>
<!-- JasperReports -->
<!-- JDO -->
<!-- JMX -->
<!-- JOTM -->
<!-- JPA -->
<!-- JSF -->
<link href="http://junit.sourceforge.net/javadoc_40/"/>
<link href="http://logging.apache.org/log4j/docs/api/"/>
<link href="http://jakarta.apache.org/regexp/apidocs/"/>
<link href="http://jakarta.apache.org/poi/apidocs/"/>
<link href="http://portals.apache.org/pluto/portlet-1.0-apidocs/"/>
<link href="http://www.quartz-scheduler.org/api/2.1.0/"/>
<link href="http://struts.apache.org/struts-doc-1.2.9/api/"/>
<link href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/"/>
<link href="http://tiles.apache.org/framework/apidocs/"/>
<link href="http://velocity.apache.org/engine/devel/apidocs/"/>
</javadoc>
</presetdef>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project name="build-spring-framework" default="precommit">
<path id="unit.test.bundles">
<pathelement location="../org.springframework.instrument"/>
<pathelement location="../org.springframework.instrument.tomcat"/>
<pathelement location="../org.springframework.core"/>
<pathelement location="../org.springframework.expression"/>
<pathelement location="../org.springframework.beans"/>
<pathelement location="../org.springframework.aop"/>
<pathelement location="../org.springframework.context"/>
<pathelement location="../org.springframework.transaction"/>
<pathelement location="../org.springframework.oxm"/>
<pathelement location="../org.springframework.jms"/>
<pathelement location="../org.springframework.jdbc"/>
<pathelement location="../org.springframework.web"/>
<pathelement location="../org.springframework.orm"/>
<pathelement location="../org.springframework.context.support"/>
<pathelement location="../org.springframework.aspects"/>
<pathelement location="../org.springframework.web.servlet"/>
<pathelement location="../org.springframework.web.portlet"/>
<pathelement location="../org.springframework.test"/>
<pathelement location="../org.springframework.web.struts"/>
</path>
<path id="bundles">
<pathelement location="../org.springframework.spring-parent"/>
<pathelement location="../org.springframework.asm"/>
<path refid="unit.test.bundles" />
<pathelement location="../org.springframework.integration-tests"/>
<pathelement location="../org.springframework.spring-library"/>
</path>
<property file="${basedir}/../build.properties"/>
<import file="${basedir}/package-top-level.xml"/>
<import file="${basedir}/publish-top-level.xml"/>
<import file="${basedir}/publish-documentation.xml"/>
<import file="${basedir}/../spring-build/multi-bundle/default.xml"/>
<target name="precommit" depends="clean, clean-integration, test"/>
<presetdef name="javadoc.links">
<javadoc>
<link href="http://download.oracle.com/javase/6/docs/api"/>
<link href="http://download.oracle.com/javaee/6/api"/>
<link href="http://aopalliance.sourceforge.net/doc"/>
<!-- Caucho Burlap/Hessian -->
<link href="http://cglib.sourceforge.net/apidocs"/>
<!-- EasyMock -->
<link href="http://ehcache.sourceforge.net/apidocs"/>
<link href="http://freemarker.sourceforge.net/docs/api/"/>
<link href="http://docs.jboss.org/hibernate/core/3.6/javadocs/"/>
<!-- iBATIS -->
<!-- iText -->
<!-- Commons Attributes -->
<link href="http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/"/>
<link href="http://jakarta.apache.org/commons/dbcp/apidocs/"/>
<link href="http://jakarta.apache.org/commons/fileupload/apidocs/"/>
<link href="http://jakarta.apache.org/commons/httpclient/apidocs/"/>
<link href="http://jakarta.apache.org/commons/logging/apidocs/"/>
<link href="http://jakarta.apache.org/commons/pool/apidocs/"/>
<!-- JasperReports -->
<!-- JDO -->
<!-- JMX -->
<!-- JOTM -->
<!-- JPA -->
<!-- JSF -->
<link href="http://junit.sourceforge.net/javadoc_40/"/>
<link href="http://logging.apache.org/log4j/docs/api/"/>
<link href="http://jakarta.apache.org/regexp/apidocs/"/>
<link href="http://jakarta.apache.org/poi/apidocs/"/>
<link href="http://portals.apache.org/pluto/portlet-1.0-apidocs/"/>
<link href="http://www.quartz-scheduler.org/api/2.1.0/"/>
<link href="http://struts.apache.org/struts-doc-1.2.9/api/"/>
<link href="http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/"/>
<link href="http://tiles.apache.org/framework/apidocs/"/>
<link href="http://velocity.apache.org/engine/devel/apidocs/"/>
</javadoc>
</presetdef>
</project>
@@ -3,6 +3,168 @@ 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)
-------------------------------------
* fixed cache handling for JNLP connections
* LinkedCaseInsensitiveMap checks for uniqueness of case-insensitive keys now
* ResourceBundleMessageSource supports "defaultEncoding", "fallbackToSystemLocale", "cacheSeconds"
* BeanWrapper does not fall back to String constructor if ConversionService attempt failed before
* @Import'ed configuration classes get properly registered in case of same class name
* @Autowired-driven ObjectFactory/Provider resolution works in non-singleton beans as well
* @Resource processing properly works with scoped beans and prototypes again
* allow replaced-method 'arg-type' matches against element body as well as 'match' attribute
* fixed potential race condition in concurrent calling of autowired methods on a prototype bean
* cancel on a Future returned by a TaskScheduler works reliably
* LoadTimeWeaverAware beans are consistently being created early for JPA weaving to work reliably
* Spring-backed DataSources consistently implement JDBC 4.0's Wrapper interface
* optimized ResourceDatabasePopulator to work around JDK 1.7 substring performance regression
* deprecated SimpleJdbcTestUtils in favor of JdbcTestUtils
* introduced "countRowsInTableWhere()" and "dropTables()" in JdbcTestUtils
* same-named unit from persistence.xml overrides in case of conflict with default unit
* JPA persistence.xml files may use jar-file entries relative to the unit root (as per the JPA spec)
* added "jtaDataSource" property to JPA LocalContainerEntityManagerFactoryBean (for default units)
* Hibernate 4 LocalSessionFactoryBuilder sets thread context ClassLoader (for JBoss 7 compatibility)
* Jaxb2Marshaller performs proper "supports" check for scanned packages
* media types in HTTP Accept headers can be parsed with single quotes (-> Android 2.x)
* MediaType's include method now recognizes wildcards in media types with a suffix
* added support for recognizing wildcards in media types with a suffix
* UriComponentsBuilder is capable of handling opaque URIs as well
* CookieGenerator supports "cookieHttpOnly" flag for Servlet 3.0
* HttpComponentsHttpInvokerRequestExecutor explicitly releases connection on HttpComponents 4.2
* improved no-match handling for @RequestMapping methods
* dynamic return value types for @MVC methods
* fixed issue with resolution of WebDataBinder argument
* fixed issue with resolving Errors controller argument
* now decoding target parameters prior to saving a FlashMap
* prevent response updates if @ResponseStatus has a reason
* improved regex for parsing query params
* optimized use of AntPathStringMatcher
* optimized use of HandlerMethod and subclasses
* fixed issue in message conversion where producible and acceptable headers are equally specific
* fixed NullPointerException in AbstractMessageConverterMethodProcessor
* fixed side effect from caching in AnnotationMethodHandlerExceptionResolver
* DispatcherPortlet uses a forward for rendering a view as resource response
* fixed Portlet request mapping priorities in cross-controller case
Changes in version 3.1.2 (2012-07-09)
-------------------------------------
* removed INDEX.LIST entries from Spring jar META-INF dirs
* fixed OSGi metadata for optional "javax.inject" package import
* fixed AbstractResource's InputStream-based "contentLength()" implementation
* fixed MutablePropertySources "get" implementation to correctly return null if not found
* fixed @PropertySource placeholder resolution to apply to all specified values
* JDBC parameter binding uses JDBC 3.0 ParameterMetaData (if available) for type determination
* added "jtaTransactionManager" property to Hibernate 4 LocalSessionFactoryBean/Builder
* EhCacheFactoryBean applies listeners and enabled/disabled flags to existing cache regions as well
* added "repeatCount" bean property to Quartz SimpleTriggerFactoryBean
* support executor qualification with @Async#value
* ServletContextResource's getFile implementation falls back to getRealPath for non-existent files
* fixed StandardServletMultipartResolver compatibility with Resin (only deleting actual file parts)
* fixed RequestConditionHolder to return null when no match is found
* fixed concurrency issue in AnnotationMethodHandlerExceptionResolver
* fixed issue with parsing invalid Content-Type or Accept headers
* added "defaultCharset" property to StringHttpMessageConverter
* added Jackson 2 HttpMessageConverter and View types
* translate IOException on EOF from Jackson to HttpMessageNotReadableException
* fix content negotiation issue when sorting selected media types by quality value
* raise RestClientException instead of IllegalArgumentException for unknown status codes
* discover controllers based on type-level @RequestMapping in new @MVC support classes
* fixed issue with suffix pattern in AnnotationMethodHandlerAdapter
* merge rather than add URI vars in ExtendedServletRequestDataBinder
* raise RestClientException for unknown HTTP status codes
* fixed issue with encoded params in UriComponentsBuilder
* XStreamMarshaller converts StreamException to Spring exception in case of unmarshalling an empty stream
* corrected DispatcherPortlet behavior to not forward event exceptions to the render phase by default
Changes in version 3.1.1 (2012-02-16)
-------------------------------------
* official support for Hibernate 4.0.0/4.0.1 as well as Hibernate 4.1
* JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well
* restored JBossLoadTimeWeaver compatibility with JBoss AS 5.1
* Provider injection works with generically typed collections of beans as well
* @ActiveProfiles mechanism in test context framework works with @ImportResource as well
* context:property-placeholder's "file-encoding" attribute value is being applied correctly
* clarified Resource's "getFilename" method to return null if resource type does not have a filename
* Resource "contentLength()" implementations work with OSGi bundle resources and JBoss VFS resources
* PathMatchingResourcePatternResolver preserves caching for JNLP (Java Web Start) jar connections
* optimized converter lookup in GenericConversionService to avoid contention in JDK proxy check
* DataBinder correctly handles ParseException from Formatter for String->String case
* CacheNamespaceHandler actually parses cache:annotation-driven's "key-generator" attribute
* introduced CustomSQLExceptionTranslatorRegistry/Registrar for JDBC error code translation
* officially deprecated TopLinkJpaDialect in favor of EclipseLink and Spring's EclipseLinkJpaDialect
* fixed LocalContainerEntityManagerFactoryBean's "packagesToScan" to avoid additional provider scan
* LocalContainerEntityManagerFactoryBean's "persistenceUnitName" applies to "packagesToScan" as well
* DefaultPersistenceUnitManager uses containing jar as persistence unit root URL for default unit
* added protected "isPersistenceUnitOverrideAllowed()" method to DefaultPersistenceUnitManager
* Hibernate synchronization properly unbinds Session even in case of afterCompletion exception
* Hibernate exception translation covers NonUniqueObjectException to DuplicateKeyException case
* Hibernate 4 LocalSessionFactoryBean implements PersistenceExceptionTranslator interface as well
* Hibernate 4 LocalSessionFactoryBean does not insist on a "dataSource" reference being set
* added "entityInterceptor" property to Hibernate 4 LocalSessionFactoryBean
* added "getConfiguration" accessor to Hibernate 4 LocalSessionFactoryBean
* added "durability" and "description" properties to JobDetailFactoryBean
* fixed QuartzJobBean and MethodInvokingJobDetailFactoryBean for compatibility with Quartz 2.0/2.1
* JMS CachingConnectionFactory never caches consumers for temporary queues and topics
* JMS SimpleMessageListenerContainer silently falls back to lazy registration of consumers
* added "receive-timeout" attribute to jms:listener-container element in JMS namespace
* ServletServerHttpRequest/Response fall back on the Content-Type and encoding of the request
* preserve quotes in MediaType parameters
* added "normalize()" method to UriComponents
* remove empty path segments from input to UriComponentsBuilder
* added "fromRequestUri(request)" and "fromCurrentRequestUri()" methods to ServletUriComponentsBuilder
* Servlet/PortletContextResource's "isReadable()" implementation returns false for directories
* allow adding flash attributes in methods with a ModelAndView return value
* make flash attributes available in the model of Parameterizable/UrlFilenameViewController
* revised the FlashMapManager contract and implementation to address a flaw in its design
* removed check for HTTP POST when resolving multipart request controller method arguments
* fixed request mapping bug involving direct vs pattern path matches with HTTP methods
* updated @RequestMapping and reference docs wrt differences between @MVC 3.1 and @MVC 2.5-3.0
* improved @SessionAttributes handling to provide better support for clustered sessions
* added property to RedirectView to disable expanding URI variables in redirect URL
Changes in version 3.1 GA (2011-12-12)
--------------------------------------
+2 -2
View File
@@ -1,5 +1,5 @@
SPRING FRAMEWORK 3.1 GA (December 2011)
---------------------------------------
SPRING FRAMEWORK 3.1.4 (January 2013)
-------------------------------------
http://www.springsource.org
1. INTRODUCTION
+8 -5
View File
@@ -1,4 +1,4 @@
version=3.1.0
version=3.1.5
natural.name=spring-framework
project.name=Spring Framework
@@ -17,13 +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
+4 -4
View File
@@ -1,4 +1,4 @@
# common dependency versions
aspectj.version=1.6.8.RELEASE
junit.version=4.9.0
testng.version=5.12.1
# common dependency versions
aspectj.version=1.6.8.RELEASE
junit.version=4.9.0
testng.version=5.12.1
+20 -20
View File
@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry kind="var" path="IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-2.4.0.jar" sourcepath="/IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-sources-2.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<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.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.beans"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.core"/>
<classpathentry kind="var" path="IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-2.4.0.jar" sourcepath="/IVY_CACHE/com.jamonapi/com.springsource.com.jamonapi/2.4.0/com.springsource.com.jamonapi-sources-2.4.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.2.0/com.springsource.net.sf.cglib-2.2.0.jar" sourcepath="/IVY_CACHE/net.sourceforge.cglib/com.springsource.net.sf.cglib/2.1.3/com.springsource.net.sf.cglib-sources-2.1.3.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-1.0.0.jar" sourcepath="/IVY_CACHE/org.aopalliance/com.springsource.org.aopalliance/1.0.0/com.springsource.org.aopalliance-sources-1.0.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<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.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-1.2.15.jar" sourcepath="/IVY_CACHE/org.apache.log4j/com.springsource.org.apache.log4j/1.2.15/com.springsource.org.apache.log4j-sources-1.2.15.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-2.5.1.jar" sourcepath="/IVY_CACHE/org.easymock/com.springsource.org.easymock/2.5.1/com.springsource.org.easymock-sources-2.5.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-4.9.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-sources-4.9.0.jar"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-4.9.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-sources-4.9.0.jar"/>
<classpathentry kind="lib" path="/org.springframework.asm/target/artifacts/org.springframework.asm.jar" sourcepath="/org.springframework.asm/target/artifacts/org.springframework.asm-sources.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
+32 -32
View File
@@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntry type="module" module-name="beans" />
<orderEntry type="module" module-name="core" />
<orderEntry type="library" name="AOP Alliance" level="project" />
<orderEntry type="library" name="AspectJ" level="project" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="library" name="Commons Logging" level="project" />
<orderEntry type="library" name="Commons Pool" level="project" />
<orderEntry type="library" name="EasyMock" level="project" />
<orderEntry type="library" name="Jamon" level="project" />
<orderEntry type="library" name="JUnit" level="project" />
<orderEntry type="library" name="Log4j" level="project" />
</component>
<component name="copyright">
<Base>
<setting name="state" value="2" />
</Base>
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntry type="module" module-name="beans" />
<orderEntry type="module" module-name="core" />
<orderEntry type="library" name="AOP Alliance" level="project" />
<orderEntry type="library" name="AspectJ" level="project" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="library" name="Commons Logging" level="project" />
<orderEntry type="library" name="Commons Pool" level="project" />
<orderEntry type="library" name="EasyMock" level="project" />
<orderEntry type="library" name="Jamon" level="project" />
<orderEntry type="library" name="JUnit" level="project" />
<orderEntry type="library" name="Log4j" level="project" />
</component>
<component name="copyright">
<Base>
<setting name="state" value="2" />
</Base>
</component>
</module>
+12 -4
View File
@@ -1,17 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<packaging>jar</packaging>
<version>3.1.0.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.0.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>com.jamonapi</groupId>
@@ -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() + "]");
@@ -0,0 +1,125 @@
/*
* 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.aop.interceptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Base class for asynchronous method execution aspects, such as
* {@link org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor}
* or {@link org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect}.
*
* <p>Provides support for <i>executor qualification</i> on a method-by-method basis.
* {@code AsyncExecutionAspectSupport} objects must be constructed with a default {@code
* Executor}, but each individual method may further qualify a specific {@code Executor}
* bean to be used when executing it, e.g. through an annotation attribute.
*
* @author Chris Beams
* @since 3.1.2
*/
public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
private final Map<Method, AsyncTaskExecutor> executors = new HashMap<Method, AsyncTaskExecutor>();
private Executor defaultExecutor;
private BeanFactory beanFactory;
/**
* Create a new {@link AsyncExecutionAspectSupport}, using the provided default
* executor unless individual async methods indicate via qualifier that a more
* specific executor should be used.
* @param defaultExecutor the executor to use when executing asynchronous methods
*/
public AsyncExecutionAspectSupport(Executor defaultExecutor) {
this.setExecutor(defaultExecutor);
}
/**
* Supply the executor to be used when executing async methods.
* @param defaultExecutor the {@code Executor} (typically a Spring {@code
* AsyncTaskExecutor} or {@link java.util.concurrent.ExecutorService}) to delegate to
* unless a more specific executor has been requested via a qualifier on the async
* method, in which case the executor will be looked up at invocation time against the
* enclosing bean factory.
* @see #getExecutorQualifier
* @see #setBeanFactory(BeanFactory)
*/
public void setExecutor(Executor defaultExecutor) {
this.defaultExecutor = defaultExecutor;
}
/**
* Set the {@link BeanFactory} to be used when looking up executors by qualifier.
*/
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Determine the specific executor to use when executing the given method.
* @returns the executor to use (never {@code null})
*/
protected AsyncTaskExecutor determineAsyncExecutor(Method method) {
if (!this.executors.containsKey(method)) {
Executor executor = this.defaultExecutor;
String qualifier = getExecutorQualifier(method);
if (StringUtils.hasLength(qualifier)) {
Assert.notNull(this.beanFactory,
"BeanFactory must be set on " + this.getClass().getSimpleName() +
" to access qualified executor [" + qualifier + "]");
executor = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
this.beanFactory, Executor.class, qualifier);
}
if (executor instanceof AsyncTaskExecutor) {
this.executors.put(method, (AsyncTaskExecutor) executor);
}
else if (executor != null) {
this.executors.put(method, new TaskExecutorAdapter(executor));
}
}
return this.executors.get(method);
}
/**
* Return the qualifier or bean name of the executor to be used when executing the
* given async method, typically specified in the form of an annotation attribute.
* Returning an empty string or {@code null} indicates that no specific executor has
* been specified and that the {@linkplain #setExecutor(Executor) default executor}
* should be used.
* @param method the method to inspect for executor qualifier metadata
* @return the qualifier if specified, otherwise empty string or {@code null}
* @see #determineAsyncExecutor(Method)
*/
protected abstract String getExecutorQualifier(Method method);
}
@@ -1,103 +1,120 @@
/*
* Copyright 2002-2009 the original author 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.aop.interceptor;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* AOP Alliance <code>MethodInterceptor</code> that processes method invocations
* asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}.
* Typically used with the {@link org.springframework.context.task.Async} annotation.
*
* <p>In terms of target method signatures, any parameter types are supported.
* However, the return type is constrained to either <code>void</code> or
* <code>java.util.concurrent.Future</code>. In the latter case, the Future handle
* returned from the proxy will be an actual asynchronous Future that can be used
* to track the result of the asynchronous method execution. However, since the
* target method needs to implement the same signature, it will have to return
* a temporary Future handle that just passes the return value through
* (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
* or EJB 3.1's <code>javax.ejb.AsyncResult</code>).
*
* @author Juergen Hoeller
* @since 3.0
* @see org.springframework.scheduling.annotation.Async
* @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
*/
public class AsyncExecutionInterceptor implements MethodInterceptor, Ordered {
private final AsyncTaskExecutor asyncExecutor;
/**
* Create a new AsyncExecutionInterceptor.
* @param asyncExecutor the Spring AsyncTaskExecutor to delegate to
*/
public AsyncExecutionInterceptor(AsyncTaskExecutor asyncExecutor) {
Assert.notNull(asyncExecutor, "TaskExecutor must not be null");
this.asyncExecutor = asyncExecutor;
}
/**
* Create a new AsyncExecutionInterceptor.
* @param asyncExecutor the <code>java.util.concurrent</code> Executor
* to delegate to (typically a {@link java.util.concurrent.ExecutorService}
*/
public AsyncExecutionInterceptor(Executor asyncExecutor) {
this.asyncExecutor = new TaskExecutorAdapter(asyncExecutor);
}
public Object invoke(final MethodInvocation invocation) throws Throwable {
Future result = this.asyncExecutor.submit(new Callable<Object>() {
public Object call() throws Exception {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future) result).get();
}
}
catch (Throwable ex) {
ReflectionUtils.rethrowException(ex);
}
return null;
}
});
if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
return result;
}
else {
return null;
}
}
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
/*
* 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.aop.interceptor;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.core.Ordered;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.util.ReflectionUtils;
/**
* AOP Alliance <code>MethodInterceptor</code> that processes method invocations
* asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}.
* Typically used with the {@link org.springframework.scheduling.annotation.Async} annotation.
*
* <p>In terms of target method signatures, any parameter types are supported.
* However, the return type is constrained to either <code>void</code> or
* <code>java.util.concurrent.Future</code>. In the latter case, the Future handle
* returned from the proxy will be an actual asynchronous Future that can be used
* to track the result of the asynchronous method execution. However, since the
* target method needs to implement the same signature, it will have to return
* a temporary Future handle that just passes the return value through
* (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult}
* or EJB 3.1's <code>javax.ejb.AsyncResult</code>).
*
* <p>As of Spring 3.1.2 the {@code AnnotationAsyncExecutionInterceptor} subclass is
* preferred for use due to its support for executor qualification in conjunction with
* Spring's {@code @Async} annotation.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 3.0
* @see org.springframework.scheduling.annotation.Async
* @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor
* @see org.springframework.scheduling.annotation.AnnotationAsyncExecutionInterceptor
*/
public class AsyncExecutionInterceptor extends AsyncExecutionAspectSupport
implements MethodInterceptor, Ordered {
/**
* Create a new {@code AsyncExecutionInterceptor}.
* @param executor the {@link Executor} (typically a Spring {@link AsyncTaskExecutor}
* or {@link java.util.concurrent.ExecutorService}) to delegate to.
*/
public AsyncExecutionInterceptor(Executor executor) {
super(executor);
}
/**
* Intercept the given method invocation, submit the actual calling of the method to
* the correct task executor and return immediately to the caller.
* @param invocation the method to intercept and make asynchronous
* @return {@link Future} if the original method returns {@code Future}; {@code null}
* otherwise.
*/
public Object invoke(final MethodInvocation invocation) throws Throwable {
Future<?> result = this.determineAsyncExecutor(invocation.getMethod()).submit(
new Callable<Object>() {
public Object call() throws Exception {
try {
Object result = invocation.proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
}
catch (Throwable ex) {
ReflectionUtils.rethrowException(ex);
}
return null;
}
});
if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
return result;
}
else {
return null;
}
}
/**
* {@inheritDoc}
* <p>This implementation is a no-op for compatibility in Spring 3.1.2. Subclasses may
* override to provide support for extracting qualifier information, e.g. via an
* annotation on the given method.
* @return always {@code null}
* @see #determineAsyncExecutor(Method)
* @since 3.1.2
*/
@Override
protected String getExecutorQualifier(Method method) {
return null;
}
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
@@ -206,6 +206,7 @@ public abstract class AopUtils {
* @return whether the pointcut can apply on any method
*/
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
@@ -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();
}
}
@@ -1,7 +1,7 @@
<html>
<body>
<p>
Spring's proxy-based AOP framework.
</p>
</body>
<html>
<body>
<p>
Spring's proxy-based AOP framework.
</p>
</body>
</html>
@@ -1,174 +1,174 @@
package org.springframework.aop.aspectj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.core.OverridingClassLoader;
/**
* @author Dave Syer
*/
public class TrickyAspectJPointcutExpressionTests {
@Test
public void testManualProxyJavaWithUnconditionalPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithStaticPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithDynamicPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true);
}
@Test
public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception {
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
// Test with default class loader first...
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl");
// Then try again with a different class loader on the target...
SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader());
// Make sure the interface is loaded from the parent class loader
loader.excludeClass(TestService.class.getName());
loader.excludeClass(TestException.class.getName());
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance();
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl");
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message)
throws Exception {
testAdvice(advisor, logAdvice, target, message, false);
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message,
boolean proxyTargetClass) throws Exception {
logAdvice.reset();
ProxyFactory factory = new ProxyFactory(target);
factory.setProxyTargetClass(proxyTargetClass);
factory.addAdvisor(advisor);
TestService bean = (TestService) factory.getProxy();
assertEquals(0, logAdvice.getCountThrows());
try {
bean.sayHello();
fail("Expected exception");
} catch (TestException e) {
assertEquals(message, e.getMessage());
}
assertEquals(1, logAdvice.getCountThrows());
}
public static class SimpleThrowawayClassLoader extends OverridingClassLoader {
/**
* Create a new SimpleThrowawayClassLoader for the given class loader.
* @param parent the ClassLoader to build a throwaway ClassLoader for
*/
public SimpleThrowawayClassLoader(ClassLoader parent) {
super(parent);
}
}
public static class TestException extends RuntimeException {
public TestException(String string) {
super(string);
}
}
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public static @interface Log {
}
public static interface TestService {
public String sayHello();
}
@Log
public static class TestServiceImpl implements TestService{
public String sayHello() {
throw new TestException("TestServiceImpl");
}
}
public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice {
private int countBefore = 0;
private int countThrows = 0;
public void before(Method method, Object[] objects, Object o) throws Throwable {
countBefore++;
}
public void afterThrowing(Exception e) throws Throwable {
countThrows++;
throw e;
}
public int getCountBefore() {
return countBefore;
}
public int getCountThrows() {
return countThrows;
}
public void reset() {
countThrows = 0;
countBefore = 0;
}
}
}
package org.springframework.aop.aspectj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.core.OverridingClassLoader;
/**
* @author Dave Syer
*/
public class TrickyAspectJPointcutExpressionTests {
@Test
public void testManualProxyJavaWithUnconditionalPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithStaticPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithDynamicPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true);
}
@Test
public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception {
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
// Test with default class loader first...
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl");
// Then try again with a different class loader on the target...
SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader());
// Make sure the interface is loaded from the parent class loader
loader.excludeClass(TestService.class.getName());
loader.excludeClass(TestException.class.getName());
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance();
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl");
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message)
throws Exception {
testAdvice(advisor, logAdvice, target, message, false);
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message,
boolean proxyTargetClass) throws Exception {
logAdvice.reset();
ProxyFactory factory = new ProxyFactory(target);
factory.setProxyTargetClass(proxyTargetClass);
factory.addAdvisor(advisor);
TestService bean = (TestService) factory.getProxy();
assertEquals(0, logAdvice.getCountThrows());
try {
bean.sayHello();
fail("Expected exception");
} catch (TestException e) {
assertEquals(message, e.getMessage());
}
assertEquals(1, logAdvice.getCountThrows());
}
public static class SimpleThrowawayClassLoader extends OverridingClassLoader {
/**
* Create a new SimpleThrowawayClassLoader for the given class loader.
* @param parent the ClassLoader to build a throwaway ClassLoader for
*/
public SimpleThrowawayClassLoader(ClassLoader parent) {
super(parent);
}
}
public static class TestException extends RuntimeException {
public TestException(String string) {
super(string);
}
}
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public static @interface Log {
}
public static interface TestService {
public String sayHello();
}
@Log
public static class TestServiceImpl implements TestService{
public String sayHello() {
throw new TestException("TestServiceImpl");
}
}
public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice {
private int countBefore = 0;
private int countThrows = 0;
public void before(Method method, Object[] objects, Object o) throws Throwable {
countBefore++;
}
public void afterThrowing(Exception e) throws Throwable {
countThrows++;
throw e;
}
public int getCountBefore() {
return countBefore;
}
public int getCountThrows() {
return countThrows;
}
public void reset() {
countThrows = 0;
countBefore = 0;
}
}
}
@@ -1,41 +1,41 @@
/*
* Copyright 2002-2009 the original author 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.aop.support;
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactory;
import test.beans.TestBean;
import org.springframework.util.ClassUtils;
/**
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Rob Harrop
* @author Rick Evans
*/
public class ClassUtilsTests extends TestCase {
public void testGetShortNameForCglibClass() {
TestBean tb = new TestBean();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(tb);
pf.setProxyTargetClass(true);
TestBean proxy = (TestBean) pf.getProxy();
String className = ClassUtils.getShortName(proxy.getClass());
assertEquals("Class name did not match", "TestBean", className);
}
}
/*
* Copyright 2002-2009 the original author 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.aop.support;
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactory;
import test.beans.TestBean;
import org.springframework.util.ClassUtils;
/**
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Rob Harrop
* @author Rick Evans
*/
public class ClassUtilsTests extends TestCase {
public void testGetShortNameForCglibClass() {
TestBean tb = new TestBean();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(tb);
pf.setProxyTargetClass(true);
TestBean proxy = (TestBean) pf.getProxy();
String className = ClassUtils.getShortName(proxy.getClass());
assertEquals("Class name did not match", "TestBean", className);
}
}
+43 -36
View File
@@ -1,55 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>spring-asm</artifactId>
<packaging>jar</packaging>
<version>3.1.0.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.0.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>jarjar</id>
<phase>process-classes</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="maven.plugin.classpath" />
<jarjar jarfile="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar">
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.jar"/>
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.commons.jar"/>
<rule pattern="org.objectweb.asm.**" result="org.springframework.asm.@1"/>
</jarjar>
<unjar src="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar"
dest="${project.build.outputDirectory}">
<patternset>
<include name="**/*.class"/>
<executions>
<execution>
<id>jarjar</id>
<phase>process-classes</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpathref="maven.plugin.classpath" />
<jarjar jarfile="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar">
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.jar"/>
<zipfileset src="${project.build.directory}/jarjar-staging/com.springsource.org.objectweb.asm.commons.jar"/>
<rule pattern="org.objectweb.asm.**" result="org.springframework.asm.@1"/>
</jarjar>
<unjar src="${project.build.directory}${file.separator}${project.build.finalName}-jarjar.jar"
dest="${project.build.outputDirectory}">
<patternset>
<include name="**/*.class"/>
<exclude name="*"/>
</patternset>
</unjar>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.google.code</groupId>
<artifactId>jarjar</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</unjar>
</tasks>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.google.code</groupId>
<artifactId>jarjar</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
+2
View File
@@ -15,7 +15,9 @@
<classpathentry kind="var" path="IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar" sourcepath="/IVY_CACHE/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-sources-1.1.1.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar" sourcepath="/IVY_CACHE/org.aspectj/com.springsource.org.aspectj.weaver/1.6.8.RELEASE/com.springsource.org.aspectj.weaver-sources-1.6.8.RELEASE.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-4.9.0.jar" sourcepath="/IVY_CACHE/org.junit/com.springsource.org.junit/4.9.0/com.springsource.org.junit-sources-4.9.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/org.hamcrest/com.springsource.org.hamcrest/1.1.0/com.springsource.org.hamcrest-1.1.0.jar" sourcepath="IVY_CACHE/org.hamcrest/com.springsource.org.hamcrest/1.1.0/com.springsource.org.hamcrest-sources-1.1.0.jar"/>
<classpathentry kind="var" path="IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-1.0.0.jar" sourcepath="/IVY_CACHE/javax.persistence/com.springsource.javax.persistence/1.0.0/com.springsource.javax.persistence-sources-1.0.0.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.orm"/>
<classpathentry combineaccessrules="false" kind="src" path="/org.springframework.aop"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
+45 -44
View File
@@ -1,44 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
<ivy-module
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
version="1.3">
<info organisation="org.springframework" module="${ant.project.name}">
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
</info>
<configurations>
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
<conf name="commons-logging" extends="runtime" description="JARs needed to run with Commons Logging"/>
<conf name="aspectj" extends="runtime" description="JARs needed to run with AspectJ"/>
<conf name="context" extends="runtime" description="JARs needed to register @Configuration classes and @Bean methods"/>
<conf name="tx" extends="runtime" description="JARs needed to run transactional aspects"/>
<conf name="orm" extends="runtime" description="JARs needed to compile JPA aspects"/>
<conf name="cache" extends="runtime" description="JARs needed to compile caching aspects"/>
</configurations>
<publications>
<artifact name="${ant.project.name}"/>
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
<artifact name="license" type="license" ext="txt"/>
<artifact name="notice" type="notice" ext="txt"/>
</publications>
<dependencies>
<dependency org="net.sourceforge.cglib" name="com.springsource.net.sf.cglib" rev="2.2.0" conf="test->runtime"/>
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile, commons-logging->compile"/>
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="${aspectj.version}" conf="optional, aspectj->compile"/>
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="test->compile"/>
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="optional, tx->compile"/>
<dependency org="org.springframework" name="org.springframework.orm" rev="latest.integration" conf="optional, orm->compile"/>
<dependency org="org.springframework" name="org.springframework.test" rev="latest.integration" conf="test->runtime"/>
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="context->compile"/>
<dependency org="org.springframework" name="org.springframework.context.support" rev="latest.integration" conf="optional, cache->compile"/>
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, orm->compile"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="optional, test->compile"/>
</dependencies>
</ivy-module>
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
<ivy-module
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
version="1.3">
<info organisation="org.springframework" module="${ant.project.name}">
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
</info>
<configurations>
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
<conf name="commons-logging" extends="runtime" description="JARs needed to run with Commons Logging"/>
<conf name="aspectj" extends="runtime" description="JARs needed to run with AspectJ"/>
<conf name="context" extends="runtime" description="JARs needed to register @Configuration classes and @Bean methods"/>
<conf name="tx" extends="runtime" description="JARs needed to run transactional aspects"/>
<conf name="orm" extends="runtime" description="JARs needed to compile JPA aspects"/>
<conf name="cache" extends="runtime" description="JARs needed to compile caching aspects"/>
</configurations>
<publications>
<artifact name="${ant.project.name}"/>
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
<artifact name="license" type="license" ext="txt"/>
<artifact name="notice" type="notice" ext="txt"/>
</publications>
<dependencies>
<dependency org="net.sourceforge.cglib" name="com.springsource.net.sf.cglib" rev="2.2.0" conf="test->runtime"/>
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile, commons-logging->compile"/>
<dependency org="org.aspectj" name="com.springsource.org.aspectj.weaver" rev="${aspectj.version}" conf="optional, aspectj->compile"/>
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="test->compile"/>
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="optional, tx->compile"/>
<dependency org="org.springframework" name="org.springframework.orm" rev="latest.integration" conf="optional, orm->compile"/>
<dependency org="org.springframework" name="org.springframework.test" rev="latest.integration" conf="test->runtime"/>
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="context->compile"/>
<dependency org="org.springframework" name="org.springframework.context.support" rev="latest.integration" conf="optional, cache->compile"/>
<dependency org="javax.persistence" name="com.springsource.javax.persistence" rev="1.0.0" conf="optional, orm->compile"/>
<dependency org="org.junit" name="com.springsource.org.junit" rev="${junit.version}" conf="test->compile"/>
<dependency org="org.hamcrest" name="com.springsource.org.hamcrest" rev="1.1.0" conf="test->compile"/>
<dependency org="javax.mail" name="com.springsource.javax.mail" rev="1.4.0" conf="optional, test->compile"/>
</dependencies>
</ivy-module>
+13 -5
View File
@@ -1,17 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<packaging>jar</packaging>
<version>3.1.0.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.0.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencies>
<!-- common logging dependency is in spring-core -->
<dependency>
@@ -53,7 +61,7 @@
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
@@ -1,54 +1,54 @@
/*
* Copyright 2002-2008 the original author 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.aspectj;
/**
* Generic-based dependency injection aspect.
* <p>
* This aspect allows users to implement efficient, type-safe dependency injection without
* the use of the &#64;Configurable annotation.
*
* The subaspect of this aspect doesn't need to include any AOP constructs.
* For example, here is a subaspect that configures the <code>PricingStrategyClient</code> objects.
* <pre>
* aspect PricingStrategyDependencyInjectionAspect
* extends GenericInterfaceDrivenDependencyInjectionAspect<PricingStrategyClient> {
* private PricingStrategy pricingStrategy;
*
* public void configure(PricingStrategyClient bean) {
* bean.setPricingStrategy(pricingStrategy);
* }
*
* public void setPricingStrategy(PricingStrategy pricingStrategy) {
* this.pricingStrategy = pricingStrategy;
* }
* }
* </pre>
* @author Ramnivas Laddad
* @since 3.0.0
*/
public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect<I> extends AbstractInterfaceDrivenDependencyInjectionAspect {
declare parents: I implements ConfigurableObject;
public pointcut inConfigurableBean() : within(I+);
public final void configureBean(Object bean) {
configure((I)bean);
}
// Unfortunately, erasure used with generics won't allow to use the same named method
protected abstract void configure(I bean);
}
/*
* Copyright 2002-2008 the original author 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.aspectj;
/**
* Generic-based dependency injection aspect.
* <p>
* This aspect allows users to implement efficient, type-safe dependency injection without
* the use of the &#64;Configurable annotation.
*
* The subaspect of this aspect doesn't need to include any AOP constructs.
* For example, here is a subaspect that configures the <code>PricingStrategyClient</code> objects.
* <pre>
* aspect PricingStrategyDependencyInjectionAspect
* extends GenericInterfaceDrivenDependencyInjectionAspect<PricingStrategyClient> {
* private PricingStrategy pricingStrategy;
*
* public void configure(PricingStrategyClient bean) {
* bean.setPricingStrategy(pricingStrategy);
* }
*
* public void setPricingStrategy(PricingStrategy pricingStrategy) {
* this.pricingStrategy = pricingStrategy;
* }
* }
* </pre>
* @author Ramnivas Laddad
* @since 3.0.0
*/
public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect<I> extends AbstractInterfaceDrivenDependencyInjectionAspect {
declare parents: I implements ConfigurableObject;
public pointcut inConfigurableBean() : within(I+);
public final void configureBean(Object bean) {
configure((I)bean);
}
// Unfortunately, erasure used with generics won't allow to use the same named method
protected abstract void configure(I bean);
}
@@ -1,73 +1,73 @@
/*
* 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.cache.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cache.interceptor.CacheAspectSupport;
import org.springframework.cache.interceptor.CacheOperationSource;
/**
* Abstract superaspect for AspectJ cache aspects. Concrete subaspects will implement the
* {@link #cacheMethodExecution} pointcut using a strategy such as Java 5 annotations.
*
* <p>Suitable for use inside or outside the Spring IoC container. Set the
* {@link #setCacheManager cacheManager} property appropriately, allowing use of any cache
* implementation supported by Spring.
*
* <p><b>NB:</b> If a method implements an interface that is itself cache annotated, the
* relevant Spring cache definition will <i>not</i> be resolved.
*
* @author Costin Leau
* @since 3.1
*/
public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
protected AbstractCacheAspect() {
}
/**
* Construct object using the given caching metadata retrieval strategy.
* @param cos {@link CacheOperationSource} implementation, retrieving Spring cache
* metadata for each joinpoint.
*/
protected AbstractCacheAspect(CacheOperationSource... cos) {
setCacheOperationSources(cos);
}
@SuppressAjWarnings("adviceDidNotMatch")
Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method method = methodSignature.getMethod();
Invoker aspectJInvoker = new Invoker() {
public Object invoke() {
return proceed(cachedObject);
}
};
return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
}
/**
* Concrete subaspects must implement this pointcut, to identify cached methods.
*/
protected abstract pointcut cacheMethodExecution(Object cachedObject);
}
/*
* 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.cache.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cache.interceptor.CacheAspectSupport;
import org.springframework.cache.interceptor.CacheOperationSource;
/**
* Abstract superaspect for AspectJ cache aspects. Concrete subaspects will implement the
* {@link #cacheMethodExecution} pointcut using a strategy such as Java 5 annotations.
*
* <p>Suitable for use inside or outside the Spring IoC container. Set the
* {@link #setCacheManager cacheManager} property appropriately, allowing use of any cache
* implementation supported by Spring.
*
* <p><b>NB:</b> If a method implements an interface that is itself cache annotated, the
* relevant Spring cache definition will <i>not</i> be resolved.
*
* @author Costin Leau
* @since 3.1
*/
public abstract aspect AbstractCacheAspect extends CacheAspectSupport {
protected AbstractCacheAspect() {
}
/**
* Construct object using the given caching metadata retrieval strategy.
* @param cos {@link CacheOperationSource} implementation, retrieving Spring cache
* metadata for each joinpoint.
*/
protected AbstractCacheAspect(CacheOperationSource... cos) {
setCacheOperationSources(cos);
}
@SuppressAjWarnings("adviceDidNotMatch")
Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method method = methodSignature.getMethod();
Invoker aspectJInvoker = new Invoker() {
public Object invoke() {
return proceed(cachedObject);
}
};
return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
}
/**
* Concrete subaspects must implement this pointcut, to identify cached methods.
*/
protected abstract pointcut cacheMethodExecution(Object cachedObject);
}
@@ -1,116 +1,116 @@
/*
* 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.cache.aspectj;
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* Concrete AspectJ cache aspect using Spring's @{@link Cacheable} annotation.
*
* <p>When using this aspect, you <i>must</i> annotate the implementation class (and/or
* methods within that class), <i>not</i> the interface (if any) that the class
* implements. AspectJ follows Java's rule that annotations on interfaces are <i>not</i>
* inherited.
*
* <p>A {@code @Cacheable} annotation on a class specifies the default caching semantics
* for the execution of any <b>public</b> operation in the class.
*
* <p>A {@code @Cacheable} annotation on a method within the class overrides the default
* caching semantics given by the class annotation (if present). Any method may be
* annotated (regardless of visibility). Annotating non-public methods directly is the
* only way to get caching demarcation for the execution of such operations.
*
* @author Costin Leau
* @since 3.1
*/
public aspect AnnotationCacheAspect extends AbstractCacheAspect {
public AnnotationCacheAspect() {
super(new AnnotationCacheOperationSource(false));
}
/**
* Matches the execution of any public method in a type with the @{@link Cacheable}
* annotation, or any subtype of a type with the {@code @Cacheable} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCacheableType() :
execution(public * ((@Cacheable *)+).*(..)) && within(@Cacheable *);
/**
* Matches the execution of any public method in a type with the @{@link CacheEvict}
* annotation, or any subtype of a type with the {@code CacheEvict} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCacheEvictType() :
execution(public * ((@CacheEvict *)+).*(..)) && within(@CacheEvict *);
/**
* Matches the execution of any public method in a type with the @{@link CachePut}
* annotation, or any subtype of a type with the {@code CachePut} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCachePutType() :
execution(public * ((@CachePut *)+).*(..)) && within(@CachePut *);
/**
* Matches the execution of any public method in a type with the @{@link Caching}
* annotation, or any subtype of a type with the {@code Caching} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCachingType() :
execution(public * ((@Caching *)+).*(..)) && within(@Caching *);
/**
* Matches the execution of any method with the @{@link Cacheable} annotation.
*/
private pointcut executionOfCacheableMethod() :
execution(@Cacheable * *(..));
/**
* Matches the execution of any method with the @{@link CacheEvict} annotation.
*/
private pointcut executionOfCacheEvictMethod() :
execution(@CacheEvict * *(..));
/**
* Matches the execution of any method with the @{@link CachePut} annotation.
*/
private pointcut executionOfCachePutMethod() :
execution(@CachePut * *(..));
/**
* Matches the execution of any method with the @{@link Caching} annotation.
*/
private pointcut executionOfCachingMethod() :
execution(@Caching * *(..));
/**
* Definition of pointcut from super aspect - matched join points will have Spring
* cache management applied.
*/
protected pointcut cacheMethodExecution(Object cachedObject) :
(executionOfAnyPublicMethodInAtCacheableType()
|| executionOfAnyPublicMethodInAtCacheEvictType()
|| executionOfAnyPublicMethodInAtCachePutType()
|| executionOfAnyPublicMethodInAtCachingType()
|| executionOfCacheableMethod()
|| executionOfCacheEvictMethod()
|| executionOfCachePutMethod()
|| executionOfCachingMethod())
&& this(cachedObject);
/*
* 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.cache.aspectj;
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* Concrete AspectJ cache aspect using Spring's @{@link Cacheable} annotation.
*
* <p>When using this aspect, you <i>must</i> annotate the implementation class (and/or
* methods within that class), <i>not</i> the interface (if any) that the class
* implements. AspectJ follows Java's rule that annotations on interfaces are <i>not</i>
* inherited.
*
* <p>A {@code @Cacheable} annotation on a class specifies the default caching semantics
* for the execution of any <b>public</b> operation in the class.
*
* <p>A {@code @Cacheable} annotation on a method within the class overrides the default
* caching semantics given by the class annotation (if present). Any method may be
* annotated (regardless of visibility). Annotating non-public methods directly is the
* only way to get caching demarcation for the execution of such operations.
*
* @author Costin Leau
* @since 3.1
*/
public aspect AnnotationCacheAspect extends AbstractCacheAspect {
public AnnotationCacheAspect() {
super(new AnnotationCacheOperationSource(false));
}
/**
* Matches the execution of any public method in a type with the @{@link Cacheable}
* annotation, or any subtype of a type with the {@code @Cacheable} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCacheableType() :
execution(public * ((@Cacheable *)+).*(..)) && within(@Cacheable *);
/**
* Matches the execution of any public method in a type with the @{@link CacheEvict}
* annotation, or any subtype of a type with the {@code CacheEvict} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCacheEvictType() :
execution(public * ((@CacheEvict *)+).*(..)) && within(@CacheEvict *);
/**
* Matches the execution of any public method in a type with the @{@link CachePut}
* annotation, or any subtype of a type with the {@code CachePut} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCachePutType() :
execution(public * ((@CachePut *)+).*(..)) && within(@CachePut *);
/**
* Matches the execution of any public method in a type with the @{@link Caching}
* annotation, or any subtype of a type with the {@code Caching} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCachingType() :
execution(public * ((@Caching *)+).*(..)) && within(@Caching *);
/**
* Matches the execution of any method with the @{@link Cacheable} annotation.
*/
private pointcut executionOfCacheableMethod() :
execution(@Cacheable * *(..));
/**
* Matches the execution of any method with the @{@link CacheEvict} annotation.
*/
private pointcut executionOfCacheEvictMethod() :
execution(@CacheEvict * *(..));
/**
* Matches the execution of any method with the @{@link CachePut} annotation.
*/
private pointcut executionOfCachePutMethod() :
execution(@CachePut * *(..));
/**
* Matches the execution of any method with the @{@link Caching} annotation.
*/
private pointcut executionOfCachingMethod() :
execution(@Caching * *(..));
/**
* Definition of pointcut from super aspect - matched join points will have Spring
* cache management applied.
*/
protected pointcut cacheMethodExecution(Object cachedObject) :
(executionOfAnyPublicMethodInAtCacheableType()
|| executionOfAnyPublicMethodInAtCacheEvictType()
|| executionOfAnyPublicMethodInAtCachePutType()
|| executionOfAnyPublicMethodInAtCachingType()
|| executionOfCacheableMethod()
|| executionOfCacheEvictMethod()
|| executionOfCachePutMethod()
|| executionOfCachingMethod())
&& this(cachedObject);
}
@@ -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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.beans.factory.aspectj;
package org.springframework.context.annotation.aspectj;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -25,14 +25,16 @@ import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Signals the current application context to apply dependency injection to non-managed
* classes that are instantiated outside of the Spring bean factory (typically classes
* annotated with the @{@link org.springframework.beans.factory.annotation.Configurable
* Signals the current application context to apply dependency injection to
* non-managed classes that are instantiated outside of the Spring bean factory
* (typically classes annotated with the @
* {@link org.springframework.beans.factory.annotation.Configurable
* Configurable} annotation).
*
* <p>Similar to functionality found in Spring's {@code <context:spring-configured>} XML
* element. Often used in conjunction with {@link
* org.springframework.context.annotation.EnableLoadTimeWeaving @EnableLoadTimeWeaving}.
* <p>Similar to functionality found in Spring's
* {@code <context:spring-configured>} XML element. Often used in conjunction
* with {@link org.springframework.context.annotation.EnableLoadTimeWeaving
* @EnableLoadTimeWeaving}.
*
* @author Chris Beams
* @since 3.1
@@ -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.
@@ -14,8 +14,9 @@
* limitations under the License.
*/
package org.springframework.beans.factory.aspectj;
package org.springframework.context.annotation.aspectj;
import org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -1,197 +1,197 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Abstract aspect to enable mocking of methods picked out by a pointcut.
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
* indicate call stacks when mocking should be triggered, and the
* methodToMock() pointcut to pick out a method invocations to mock.
*
* @author Rod Johnson
* @author Ramnivas Laddad
*/
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
protected abstract pointcut mockStaticsTestMethod();
protected abstract pointcut methodToMock();
private boolean recording = true;
static enum CallResponse { nothing, return_, throw_ };
// Represents a list of expected calls to static entity methods
// Public to allow inserted code to access: is this normal??
public class Expectations {
// Represents an expected call to a static entity method
private class Call {
private final String signature;
private final Object[] args;
private Object responseObject; // return value or throwable
private CallResponse responseType = CallResponse.nothing;
public Call(String name, Object[] args) {
this.signature = name;
this.args = args;
}
public boolean hasResponseSpecified() {
return responseType != CallResponse.nothing;
}
public void setReturnVal(Object retVal) {
this.responseObject = retVal;
responseType = CallResponse.return_;
}
public void setThrow(Throwable throwable) {
this.responseObject = throwable;
responseType = CallResponse.throw_;
}
public Object returnValue(String lastSig, Object[] args) {
checkSignature(lastSig, args);
return responseObject;
}
public Object throwException(String lastSig, Object[] args) {
checkSignature(lastSig, args);
throw (RuntimeException)responseObject;
}
private void checkSignature(String lastSig, Object[] args) {
if (!signature.equals(lastSig)) {
throw new IllegalArgumentException("Signature doesn't match");
}
if (!Arrays.equals(this.args, args)) {
throw new IllegalArgumentException("Arguments don't match");
}
}
}
private List<Call> calls = new LinkedList<Call>();
// Calls already verified
private int verified;
public void verify() {
if (verified != calls.size()) {
throw new IllegalStateException("Expected " + calls.size()
+ " calls, received " + verified);
}
}
/**
* Validate the call and provide the expected return value
* @param lastSig
* @param args
* @return
*/
public Object respond(String lastSig, Object[] args) {
Call call = nextCall();
CallResponse responseType = call.responseType;
if (responseType == CallResponse.return_) {
return call.returnValue(lastSig, args);
} else if(responseType == CallResponse.throw_) {
return (RuntimeException)call.throwException(lastSig, args);
} else if(responseType == CallResponse.nothing) {
// do nothing
}
throw new IllegalStateException("Behavior of " + call + " not specified");
}
private Call nextCall() {
if (verified > calls.size() - 1) {
throw new IllegalStateException("Expected " + calls.size()
+ " calls, received " + verified);
}
return calls.get(verified++);
}
public void expectCall(String lastSig, Object lastArgs[]) {
Call call = new Call(lastSig, lastArgs);
calls.add(call);
}
public boolean hasCalls() {
return !calls.isEmpty();
}
public void expectReturn(Object retVal) {
Call call = calls.get(calls.size() - 1);
if (call.hasResponseSpecified()) {
throw new IllegalStateException("No static method invoked before setting return value");
}
call.setReturnVal(retVal);
}
public void expectThrow(Throwable throwable) {
Call call = calls.get(calls.size() - 1);
if (call.hasResponseSpecified()) {
throw new IllegalStateException("No static method invoked before setting throwable");
}
call.setThrow(throwable);
}
}
private Expectations expectations = new Expectations();
after() returning : mockStaticsTestMethod() {
if (recording && (expectations.hasCalls())) {
throw new IllegalStateException(
"Calls recorded, yet playback state never reached: Create expectations then call "
+ this.getClass().getSimpleName() + ".playback()");
}
expectations.verify();
}
Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
if (recording) {
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
// Return value doesn't matter
return null;
} else {
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
}
}
public void expectReturnInternal(Object retVal) {
if (!recording) {
throw new IllegalStateException("Not recording: Cannot set return value");
}
expectations.expectReturn(retVal);
}
public void expectThrowInternal(Throwable throwable) {
if (!recording) {
throw new IllegalStateException("Not recording: Cannot set throwable value");
}
expectations.expectThrow(throwable);
}
public void playbackInternal() {
recording = false;
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* Abstract aspect to enable mocking of methods picked out by a pointcut.
* Sub-aspects must define the mockStaticsTestMethod() pointcut to
* indicate call stacks when mocking should be triggered, and the
* methodToMock() pointcut to pick out a method invocations to mock.
*
* @author Rod Johnson
* @author Ramnivas Laddad
*/
public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) {
protected abstract pointcut mockStaticsTestMethod();
protected abstract pointcut methodToMock();
private boolean recording = true;
static enum CallResponse { nothing, return_, throw_ };
// Represents a list of expected calls to static entity methods
// Public to allow inserted code to access: is this normal??
public class Expectations {
// Represents an expected call to a static entity method
private class Call {
private final String signature;
private final Object[] args;
private Object responseObject; // return value or throwable
private CallResponse responseType = CallResponse.nothing;
public Call(String name, Object[] args) {
this.signature = name;
this.args = args;
}
public boolean hasResponseSpecified() {
return responseType != CallResponse.nothing;
}
public void setReturnVal(Object retVal) {
this.responseObject = retVal;
responseType = CallResponse.return_;
}
public void setThrow(Throwable throwable) {
this.responseObject = throwable;
responseType = CallResponse.throw_;
}
public Object returnValue(String lastSig, Object[] args) {
checkSignature(lastSig, args);
return responseObject;
}
public Object throwException(String lastSig, Object[] args) {
checkSignature(lastSig, args);
throw (RuntimeException)responseObject;
}
private void checkSignature(String lastSig, Object[] args) {
if (!signature.equals(lastSig)) {
throw new IllegalArgumentException("Signature doesn't match");
}
if (!Arrays.equals(this.args, args)) {
throw new IllegalArgumentException("Arguments don't match");
}
}
}
private List<Call> calls = new LinkedList<Call>();
// Calls already verified
private int verified;
public void verify() {
if (verified != calls.size()) {
throw new IllegalStateException("Expected " + calls.size()
+ " calls, received " + verified);
}
}
/**
* Validate the call and provide the expected return value
* @param lastSig
* @param args
* @return
*/
public Object respond(String lastSig, Object[] args) {
Call call = nextCall();
CallResponse responseType = call.responseType;
if (responseType == CallResponse.return_) {
return call.returnValue(lastSig, args);
} else if(responseType == CallResponse.throw_) {
return (RuntimeException)call.throwException(lastSig, args);
} else if(responseType == CallResponse.nothing) {
// do nothing
}
throw new IllegalStateException("Behavior of " + call + " not specified");
}
private Call nextCall() {
if (verified > calls.size() - 1) {
throw new IllegalStateException("Expected " + calls.size()
+ " calls, received " + verified);
}
return calls.get(verified++);
}
public void expectCall(String lastSig, Object lastArgs[]) {
Call call = new Call(lastSig, lastArgs);
calls.add(call);
}
public boolean hasCalls() {
return !calls.isEmpty();
}
public void expectReturn(Object retVal) {
Call call = calls.get(calls.size() - 1);
if (call.hasResponseSpecified()) {
throw new IllegalStateException("No static method invoked before setting return value");
}
call.setReturnVal(retVal);
}
public void expectThrow(Throwable throwable) {
Call call = calls.get(calls.size() - 1);
if (call.hasResponseSpecified()) {
throw new IllegalStateException("No static method invoked before setting throwable");
}
call.setThrow(throwable);
}
}
private Expectations expectations = new Expectations();
after() returning : mockStaticsTestMethod() {
if (recording && (expectations.hasCalls())) {
throw new IllegalStateException(
"Calls recorded, yet playback state never reached: Create expectations then call "
+ this.getClass().getSimpleName() + ".playback()");
}
expectations.verify();
}
Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) {
if (recording) {
expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
// Return value doesn't matter
return null;
} else {
return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs());
}
}
public void expectReturnInternal(Object retVal) {
if (!recording) {
throw new IllegalStateException("Not recording: Cannot set return value");
}
expectations.expectReturn(retVal);
}
public void expectThrowInternal(Throwable throwable) {
if (!recording) {
throw new IllegalStateException("Not recording: Cannot set throwable value");
}
expectations.expectThrow(throwable);
}
public void playbackInternal() {
recording = false;
}
}
@@ -1,68 +1,68 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
/**
* Annotation-based aspect to use in test build to enable mocking static methods
* on JPA-annotated <code>@Entity</code> classes, as used by Roo for finders.
*
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
* that is annotated with the @MockStaticEntityMethods annotation.
*
* <p>Also provides static methods to simplify the programming model for
* entering playback mode and setting expected return values.
*
* <p>Usage:
* <ol>
* <li>Annotate a test class with @MockStaticEntityMethods.
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
* Invoke static methods on Entity classes, with each recording-mode invocation
* being followed by an invocation to the static expectReturn() or expectThrow()
* method on AnnotationDrivenStaticEntityMockingControl.
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
* <li>Call the code you wish to test that uses the static methods. Verification will
* occur automatically.
* </ol>
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @see MockStaticEntityMethods
*/
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
/**
* Stop recording mock calls and enter playback state
*/
public static void playback() {
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
}
public static void expectReturn(Object retVal) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
}
public static void expectThrow(Throwable throwable) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
}
// Only matches directly annotated @Test methods, to allow methods in
// @MockStatics classes to invoke each other without resetting the mocking environment
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
/**
* Annotation-based aspect to use in test build to enable mocking static methods
* on JPA-annotated <code>@Entity</code> classes, as used by Roo for finders.
*
* <p>Mocking will occur in the call stack of any method in a class (typically a test class)
* that is annotated with the @MockStaticEntityMethods annotation.
*
* <p>Also provides static methods to simplify the programming model for
* entering playback mode and setting expected return values.
*
* <p>Usage:
* <ol>
* <li>Annotate a test class with @MockStaticEntityMethods.
* <li>In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode.
* Invoke static methods on Entity classes, with each recording-mode invocation
* being followed by an invocation to the static expectReturn() or expectThrow()
* method on AnnotationDrivenStaticEntityMockingControl.
* <li>Invoke the static AnnotationDrivenStaticEntityMockingControl() method.
* <li>Call the code you wish to test that uses the static methods. Verification will
* occur automatically.
* </ol>
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @see MockStaticEntityMethods
*/
public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl {
/**
* Stop recording mock calls and enter playback state
*/
public static void playback() {
AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal();
}
public static void expectReturn(Object retVal) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal);
}
public static void expectThrow(Throwable throwable) {
AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable);
}
// Only matches directly annotated @Test methods, to allow methods in
// @MockStatics classes to invoke each other without resetting the mocking environment
protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..));
protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..));
}
@@ -1,34 +1,34 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to indicate a test class for whose @Test methods
* static methods on Entity classes should be mocked.
*
* @author Rod Johnson
* @see AbstractMethodMockingControl
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MockStaticEntityMethods {
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to indicate a test class for whose @Test methods
* static methods on Entity classes should be mocked.
*
* @author Rod Johnson
* @see AbstractMethodMockingControl
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MockStaticEntityMethods {
}
@@ -1,75 +1,86 @@
/*
* Copyright 2002-2010 the original author 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.scheduling.aspectj;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
/**
* Abstract aspect that routes selected methods asynchronously.
*
* <p>This aspect needs to be injected with an implementation of
* {@link Executor} to activate it for a specific thread pool.
* Otherwise it will simply delegate all calls synchronously.
*
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @since 3.0.5
*/
public abstract aspect AbstractAsyncExecutionAspect {
private AsyncTaskExecutor asyncExecutor;
public void setExecutor(Executor executor) {
if (executor instanceof AsyncTaskExecutor) {
this.asyncExecutor = (AsyncTaskExecutor) executor;
}
else {
this.asyncExecutor = new TaskExecutorAdapter(executor);
}
}
Object around() : asyncMethod() {
if (this.asyncExecutor == null) {
return proceed();
}
Callable<Object> callable = new Callable<Object>() {
public Object call() throws Exception {
Object result = proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
return null;
}};
Future<?> result = this.asyncExecutor.submit(callable);
if (Future.class.isAssignableFrom(((MethodSignature) thisJoinPointStaticPart.getSignature()).getReturnType())) {
return result;
}
else {
return null;
}
}
public abstract pointcut asyncMethod();
}
/*
* 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.scheduling.aspectj;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.aop.interceptor.AsyncExecutionAspectSupport;
import org.springframework.core.task.AsyncTaskExecutor;
/**
* Abstract aspect that routes selected methods asynchronously.
*
* <p>This aspect needs to be injected with an implementation of
* {@link Executor} to activate it for a specific thread pool.
* Otherwise it will simply delegate all calls synchronously.
*
* @author Ramnivas Laddad
* @author Juergen Hoeller
* @author Chris Beams
* @since 3.0.5
*/
public abstract aspect AbstractAsyncExecutionAspect extends AsyncExecutionAspectSupport {
/**
* Create an {@code AnnotationAsyncExecutionAspect} with a {@code null} default
* executor, which should instead be set via {@code #aspectOf} and
* {@link #setExecutor(Executor)}.
*/
public AbstractAsyncExecutionAspect() {
super(null);
}
/**
* Apply around advice to methods matching the {@link #asyncMethod()} pointcut,
* submit the actual calling of the method to the correct task executor and return
* immediately to the caller.
* @return {@link Future} if the original method returns {@code Future}; {@code null}
* otherwise.
*/
Object around() : asyncMethod() {
MethodSignature methodSignature = (MethodSignature) thisJoinPointStaticPart.getSignature();
AsyncTaskExecutor executor = determineAsyncExecutor(methodSignature.getMethod());
if (executor == null) {
return proceed();
}
Callable<Object> callable = new Callable<Object>() {
public Object call() throws Exception {
Object result = proceed();
if (result instanceof Future) {
return ((Future<?>) result).get();
}
return null;
}};
Future<?> result = executor.submit(callable);
if (Future.class.isAssignableFrom(methodSignature.getReturnType())) {
return result;
}
else {
return null;
}
}
/**
* Return the set of joinpoints at which async advice should be applied.
*/
public abstract pointcut asyncMethod();
}
@@ -1,54 +1,82 @@
/*
* Copyright 2002-2010 the original author 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.scheduling.aspectj;
import java.util.concurrent.Future;
import org.springframework.scheduling.annotation.Async;
/**
* Aspect to route methods based on the {@link Async} annotation.
*
* <p>This aspect routes methods marked with the {@link Async} annotation
* as well as methods in classes marked with the same. Any method expected
* to be routed asynchronously must return either void, {@link Future},
* or a subtype of {@link Future}. This aspect, therefore, will produce
* a compile-time error for methods that violate this constraint on the return type.
* If, however, a class marked with <code>&#64;Async</code> contains a method that
* violates this constraint, it produces only a warning.
*
* @author Ramnivas Laddad
* @since 3.0.5
*/
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
private pointcut asyncMarkedMethod()
: execution(@Async (void || Future+) *(..));
private pointcut asyncTypeMarkedMethod()
: execution((void || Future+) (@Async *).*(..));
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
declare error:
execution(@Async !(void||Future) *(..)):
"Only methods that return void or Future may have an @Async annotation";
declare warning:
execution(!(void||Future) (@Async *).*(..)):
"Methods in a class marked with @Async that do not return void or Future will be routed synchronously";
}
/*
* 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.scheduling.aspectj;
import java.lang.reflect.Method;
import java.util.concurrent.Future;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.annotation.Async;
/**
* Aspect to route methods based on the {@link Async} annotation.
*
* <p>This aspect routes methods marked with the {@link Async} annotation
* as well as methods in classes marked with the same. Any method expected
* to be routed asynchronously must return either {@code void}, {@link Future},
* or a subtype of {@link Future}. This aspect, therefore, will produce
* a compile-time error for methods that violate this constraint on the return type.
* If, however, a class marked with {@code @Async} contains a method that violates this
* constraint, it produces only a warning.
*
* @author Ramnivas Laddad
* @author Chris Beams
* @since 3.0.5
*/
public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect {
private pointcut asyncMarkedMethod()
: execution(@Async (void || Future+) *(..));
private pointcut asyncTypeMarkedMethod()
: execution((void || Future+) (@Async *).*(..));
public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod();
/**
* {@inheritDoc}
* <p>This implementation inspects the given method and its declaring class for the
* {@code @Async} annotation, returning the qualifier value expressed by
* {@link Async#value()}. If {@code @Async} is specified at both the method and class level, the
* method's {@code #value} takes precedence (even if empty string, indicating that
* the default executor should be used preferentially).
* @return the qualifier if specified, otherwise empty string indicating that the
* {@linkplain #setExecutor(Executor) default executor} should be used
* @see #determineAsyncExecutor(Method)
*/
@Override
protected String getExecutorQualifier(Method method) {
// maintainer's note: changes made here should also be made in
// AnnotationAsyncExecutionInterceptor#getExecutorQualifier
Async async = AnnotationUtils.findAnnotation(method, Async.class);
if (async == null) {
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
}
return async == null ? null : async.value();
}
declare error:
execution(@Async !(void||Future) *(..)):
"Only methods that return void or Future may have an @Async annotation";
declare warning:
execution(!(void||Future) (@Async *).*(..)):
"Methods in a class marked with @Async that do not return void or Future will " +
"be routed synchronously";
}
@@ -1,93 +1,93 @@
/*
* Copyright 2002-2010 the original author 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.transaction.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
/**
* Abstract superaspect for AspectJ transaction aspects. Concrete
* subaspects will implement the <code>transactionalMethodExecution()</code>
* pointcut using a strategy such as Java 5 annotations.
*
* <p>Suitable for use inside or outside the Spring IoC container.
* Set the "transactionManager" property appropriately, allowing
* use of any transaction implementation supported by Spring.
*
* <p><b>NB:</b> If a method implements an interface that is itself
* transactionally annotated, the relevant Spring transaction attribute
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
* if proxying an interface (but not when proxying a class). We recommend that
* transaction annotations should be added to classes, rather than business
* interfaces, as they are an implementation detail rather than a contract
* specification validation.
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @since 2.0
*/
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
/**
* Construct object using the given transaction metadata retrieval strategy.
* @param tas TransactionAttributeSource implementation, retrieving Spring
* transaction metadata for each joinpoint. Write the subclass to pass in null
* if it's intended to be configured by Setter Injection.
*/
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
setTransactionAttributeSource(tas);
}
@SuppressAjWarnings("adviceDidNotMatch")
before(Object txObject) : transactionalMethodExecution(txObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method method = methodSignature.getMethod();
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
}
@SuppressAjWarnings("adviceDidNotMatch")
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
try {
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
}
catch (Throwable t2) {
logger.error("Failed to close transaction after throwing in a transactional method", t2);
}
}
@SuppressAjWarnings("adviceDidNotMatch")
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
}
@SuppressAjWarnings("adviceDidNotMatch")
after(Object txObject) : transactionalMethodExecution(txObject) {
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
}
/**
* Concrete subaspects must implement this pointcut, to identify
* transactional methods. For each selected joinpoint, TransactionMetadata
* will be retrieved using Spring's TransactionAttributeSource interface.
*/
protected abstract pointcut transactionalMethodExecution(Object txObject);
}
/*
* Copyright 2002-2010 the original author 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.transaction.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.annotation.SuppressAjWarnings;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
/**
* Abstract superaspect for AspectJ transaction aspects. Concrete
* subaspects will implement the <code>transactionalMethodExecution()</code>
* pointcut using a strategy such as Java 5 annotations.
*
* <p>Suitable for use inside or outside the Spring IoC container.
* Set the "transactionManager" property appropriately, allowing
* use of any transaction implementation supported by Spring.
*
* <p><b>NB:</b> If a method implements an interface that is itself
* transactionally annotated, the relevant Spring transaction attribute
* will <i>not</i> be resolved. This behavior will vary from that of Spring AOP
* if proxying an interface (but not when proxying a class). We recommend that
* transaction annotations should be added to classes, rather than business
* interfaces, as they are an implementation detail rather than a contract
* specification validation.
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @since 2.0
*/
public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport {
/**
* Construct object using the given transaction metadata retrieval strategy.
* @param tas TransactionAttributeSource implementation, retrieving Spring
* transaction metadata for each joinpoint. Write the subclass to pass in null
* if it's intended to be configured by Setter Injection.
*/
protected AbstractTransactionAspect(TransactionAttributeSource tas) {
setTransactionAttributeSource(tas);
}
@SuppressAjWarnings("adviceDidNotMatch")
before(Object txObject) : transactionalMethodExecution(txObject) {
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method method = methodSignature.getMethod();
TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass());
}
@SuppressAjWarnings("adviceDidNotMatch")
after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) {
try {
completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t);
}
catch (Throwable t2) {
logger.error("Failed to close transaction after throwing in a transactional method", t2);
}
}
@SuppressAjWarnings("adviceDidNotMatch")
after(Object txObject) returning() : transactionalMethodExecution(txObject) {
commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo());
}
@SuppressAjWarnings("adviceDidNotMatch")
after(Object txObject) : transactionalMethodExecution(txObject) {
cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo());
}
/**
* Concrete subaspects must implement this pointcut, to identify
* transactional methods. For each selected joinpoint, TransactionMetadata
* will be retrieved using Spring's TransactionAttributeSource interface.
*/
protected abstract pointcut transactionalMethodExecution(Object txObject);
}
@@ -1,75 +1,75 @@
/*
* Copyright 2002-2010 the original author 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.transaction.aspectj;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.annotation.Transactional;
/**
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
*
* <p>When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited.
*
* <p>An @Transactional annotation on a class specifies the default transaction
* semantics for the execution of any <b>public</b> operation in the class.
*
* <p>An @Transactional annotation on a method within the class overrides the
* default transaction semantics given by the class annotation (if present).
* Any method may be annotated (regardless of visibility).
* Annotating non-public methods directly is the only way
* to get transaction demarcation for the execution of such operations.
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @author Adrian Colyer
* @since 2.0
* @see org.springframework.transaction.annotation.Transactional
*/
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
public AnnotationTransactionAspect() {
super(new AnnotationTransactionAttributeSource(false));
}
/**
* Matches the execution of any public method in a type with the
* Transactional annotation, or any subtype of a type with the
* Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
/**
* Matches the execution of any method with the
* Transactional annotation.
*/
private pointcut executionOfTransactionalMethod() :
execution(@Transactional * *(..));
/**
* Definition of pointcut from super aspect - matched join points
* will have Spring transaction management applied.
*/
protected pointcut transactionalMethodExecution(Object txObject) :
(executionOfAnyPublicMethodInAtTransactionalType()
|| executionOfTransactionalMethod() )
&& this(txObject);
}
/*
* Copyright 2002-2010 the original author 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.transaction.aspectj;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.annotation.Transactional;
/**
* Concrete AspectJ transaction aspect using Spring's @Transactional annotation.
*
* <p>When using this aspect, you <i>must</i> annotate the implementation class
* (and/or methods within that class), <i>not</i> the interface (if any) that
* the class implements. AspectJ follows Java's rule that annotations on
* interfaces are <i>not</i> inherited.
*
* <p>An @Transactional annotation on a class specifies the default transaction
* semantics for the execution of any <b>public</b> operation in the class.
*
* <p>An @Transactional annotation on a method within the class overrides the
* default transaction semantics given by the class annotation (if present).
* Any method may be annotated (regardless of visibility).
* Annotating non-public methods directly is the only way
* to get transaction demarcation for the execution of such operations.
*
* @author Rod Johnson
* @author Ramnivas Laddad
* @author Adrian Colyer
* @since 2.0
* @see org.springframework.transaction.annotation.Transactional
*/
public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {
public AnnotationTransactionAspect() {
super(new AnnotationTransactionAttributeSource(false));
}
/**
* Matches the execution of any public method in a type with the
* Transactional annotation, or any subtype of a type with the
* Transactional annotation.
*/
private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);
/**
* Matches the execution of any method with the
* Transactional annotation.
*/
private pointcut executionOfTransactionalMethod() :
execution(@Transactional * *(..));
/**
* Definition of pointcut from super aspect - matched join points
* will have Spring transaction management applied.
*/
protected pointcut transactionalMethodExecution(Object txObject) :
(executionOfAnyPublicMethodInAtTransactionalType()
|| executionOfTransactionalMethod() )
&& this(txObject);
}
@@ -1,7 +1,7 @@
<html>
<body>
<p>
The Spring Data Binding framework, an internal library used by Spring Web Flow.
</p>
</body>
<html>
<body>
<p>
The Spring Data Binding framework, an internal library used by Spring Web Flow.
</p>
</body>
</html>
@@ -1,19 +1,19 @@
<?xml version="1.0"?>
<!--
AspectJ load-time weaving config file to install common Spring aspects.
-->
<aspectj>
<!--
<weaver options="-showWeaveInfo"/>
-->
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
<aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/>
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
<aspect name="org.springframework.cache.aspectj.AnnotationCacheAspect"/>
</aspects>
</aspectj>
<?xml version="1.0"?>
<!--
AspectJ load-time weaving config file to install common Spring aspects.
-->
<aspectj>
<!--
<weaver options="-showWeaveInfo"/>
-->
<aspects>
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"/>
<aspect name="org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"/>
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
<aspect name="org.springframework.cache.aspectj.AnnotationCacheAspect"/>
</aspects>
</aspectj>
@@ -1,32 +1,32 @@
/*
* Copyright 2002-2007 the original author 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.aop.aspectj.autoproxy;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import junit.framework.TestCase;
/**
* @author Adrian Colyer
*/
public class AutoProxyWithCodeStyleAspectsTests extends TestCase {
public void testNoAutoproxyingOfAjcCompiledAspects() {
new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml");
}
}
/*
* Copyright 2002-2007 the original author 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.aop.aspectj.autoproxy;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import junit.framework.TestCase;
/**
* @author Adrian Colyer
*/
public class AutoProxyWithCodeStyleAspectsTests extends TestCase {
public void testNoAutoproxyingOfAjcCompiledAspects() {
new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml");
}
}
@@ -1,36 +1,36 @@
/*
* Copyright 2002-2010 the original author 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.aop.aspectj.autoproxy;
/**
* @author Adrian Colyer
*/
public aspect CodeStyleAspect {
private String foo;
pointcut somePC() : call(* someMethod());
before() : somePC() {
System.out.println("match");
}
public void setFoo(String foo) {
this.foo = foo;
}
}
/*
* Copyright 2002-2010 the original author 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.aop.aspectj.autoproxy;
/**
* @author Adrian Colyer
*/
public aspect CodeStyleAspect {
private String foo;
pointcut somePC() : call(* someMethod());
before() : somePC() {
System.out.println("match");
}
public void setFoo(String foo) {
this.foo = foo;
}
}
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="myAspect" class="org.springframework.aop.aspectj.autoproxy.CodeStyleAspect"
factory-method="aspectOf">
<property name="foo" value="bar"/>
</bean>
<bean id="otherBean" class="java.lang.Object"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="myAspect" class="org.springframework.aop.aspectj.autoproxy.CodeStyleAspect"
factory-method="aspectOf">
<property name="foo" value="bar"/>
</bean>
<bean id="otherBean" class="java.lang.Object"/>
</beans>
@@ -1,33 +1,33 @@
/*
* Copyright 2002-2006 the original author 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.aspectj;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import junit.framework.TestCase;
public class SpringConfiguredWithAutoProxyingTests extends TestCase {
@Override
protected void setUp() throws Exception {
new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml");
}
public void testSpringConfiguredAndAutoProxyUsedTogether() {
; // set up is sufficient to trigger failure if this is going to fail...
}
/*
* Copyright 2002-2006 the original author 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.aspectj;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import junit.framework.TestCase;
public class SpringConfiguredWithAutoProxyingTests extends TestCase {
@Override
protected void setUp() throws Exception {
new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml");
}
public void testSpringConfiguredAndAutoProxyUsedTogether() {
; // set up is sufficient to trigger failure if this is going to fail...
}
}
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:spring-configured/>
<context:annotation-config/>
<import resource="beanConfigurerTests-beans.xml"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:spring-configured/>
<context:annotation-config/>
<import resource="beanConfigurerTests-beans.xml"/>
</beans>
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:spring-configured/>
<aop:aspectj-autoproxy/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:spring-configured/>
<aop:aspectj-autoproxy/>
</beans>
@@ -1,33 +1,41 @@
/*
* Copyright 2010 the original author 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.cache.aspectj;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* @author Costin Leau
*/
public class AspectJAnnotationTest extends AbstractAnnotationTest {
@Override
protected ApplicationContext getApplicationContext() {
return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml");
}
}
/*
* Copyright 2010 the original author 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.cache.aspectj;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* @author Costin Leau
*/
public class AspectJAnnotationTest extends AbstractAnnotationTest {
@Override
protected ApplicationContext getApplicationContext() {
return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml");
}
@Test
public void testKeyStrategy() throws Exception {
AnnotationCacheAspect aspect = ctx.getBean("org.springframework.cache.config.internalCacheAspect", AnnotationCacheAspect.class);
Assert.assertSame(ctx.getBean("keyGenerator"), aspect.getKeyGenerator());
}
}
@@ -1,138 +1,138 @@
/*
* Copyright 2010-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.cache.config;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* @author Costin Leau
*/
@Cacheable("default")
public class AnnotatedClassCacheableService implements CacheableService<Object> {
private final AtomicLong counter = new AtomicLong();
public static final AtomicLong nullInvocations = new AtomicLong();
public Object cache(Object arg1) {
return counter.getAndIncrement();
}
public Object conditional(int field) {
return null;
}
@CacheEvict("default")
public void invalidate(Object arg1) {
}
@CacheEvict("default")
public void evictWithException(Object arg1) {
throw new RuntimeException("exception thrown - evict should NOT occur");
}
@CacheEvict(value = "default", allEntries = true)
public void evictAll(Object arg1) {
}
@CacheEvict(value = "default", beforeInvocation = true)
public void evictEarly(Object arg1) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@CacheEvict(value = "default", key = "#p0")
public void evict(Object arg1, Object arg2) {
}
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
public void invalidateEarly(Object arg1, Object arg2) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@Cacheable(value = "default", key = "#p0")
public Object key(Object arg1, Object arg2) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name")
public Object name(Object arg1) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
public Object rootVars(Object arg1) {
return counter.getAndIncrement();
}
@CachePut("default")
public Object update(Object arg1) {
return counter.getAndIncrement();
}
@CachePut(value = "default", condition = "#arg.equals(3)")
public Object conditionalUpdate(Object arg) {
return arg;
}
public Object nullValue(Object arg1) {
nullInvocations.incrementAndGet();
return null;
}
public Number nullInvocations() {
return nullInvocations.get();
}
public Long throwChecked(Object arg1) throws Exception {
throw new UnsupportedOperationException(arg1.toString());
}
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException();
}
// multi annotations
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
public Object multiCache(Object arg1) {
return counter.getAndIncrement();
}
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
public Object multiEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
public Object multiCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
public Object multiConditionalCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
public Object multiUpdate(Object arg1) {
return arg1;
}
/*
* Copyright 2010-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.cache.config;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* @author Costin Leau
*/
@Cacheable("default")
public class AnnotatedClassCacheableService implements CacheableService<Object> {
private final AtomicLong counter = new AtomicLong();
public static final AtomicLong nullInvocations = new AtomicLong();
public Object cache(Object arg1) {
return counter.getAndIncrement();
}
public Object conditional(int field) {
return null;
}
@CacheEvict("default")
public void invalidate(Object arg1) {
}
@CacheEvict("default")
public void evictWithException(Object arg1) {
throw new RuntimeException("exception thrown - evict should NOT occur");
}
@CacheEvict(value = "default", allEntries = true)
public void evictAll(Object arg1) {
}
@CacheEvict(value = "default", beforeInvocation = true)
public void evictEarly(Object arg1) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@CacheEvict(value = "default", key = "#p0")
public void evict(Object arg1, Object arg2) {
}
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
public void invalidateEarly(Object arg1, Object arg2) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@Cacheable(value = "default", key = "#p0")
public Object key(Object arg1, Object arg2) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name")
public Object name(Object arg1) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
public Object rootVars(Object arg1) {
return counter.getAndIncrement();
}
@CachePut("default")
public Object update(Object arg1) {
return counter.getAndIncrement();
}
@CachePut(value = "default", condition = "#arg.equals(3)")
public Object conditionalUpdate(Object arg) {
return arg;
}
public Object nullValue(Object arg1) {
nullInvocations.incrementAndGet();
return null;
}
public Number nullInvocations() {
return nullInvocations.get();
}
public Long throwChecked(Object arg1) throws Exception {
throw new UnsupportedOperationException(arg1.toString());
}
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException();
}
// multi annotations
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
public Object multiCache(Object arg1) {
return counter.getAndIncrement();
}
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
public Object multiEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
public Object multiCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
public Object multiConditionalCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
public Object multiUpdate(Object arg1) {
return arg1;
}
}
@@ -1,70 +1,70 @@
/*
* Copyright 2010-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.cache.config;
/**
* Basic service interface.
*
* @author Costin Leau
*/
public interface CacheableService<T> {
T cache(Object arg1);
void invalidate(Object arg1);
void evictEarly(Object arg1);
void evictAll(Object arg1);
void evictWithException(Object arg1);
void evict(Object arg1, Object arg2);
void invalidateEarly(Object arg1, Object arg2);
T conditional(int field);
T key(Object arg1, Object arg2);
T name(Object arg1);
T nullValue(Object arg1);
T update(Object arg1);
T conditionalUpdate(Object arg2);
Number nullInvocations();
T rootVars(Object arg1);
T throwChecked(Object arg1) throws Exception;
T throwUnchecked(Object arg1);
// multi annotations
T multiCache(Object arg1);
T multiEvict(Object arg1);
T multiCacheAndEvict(Object arg1);
T multiConditionalCacheAndEvict(Object arg1);
T multiUpdate(Object arg1);
/*
* Copyright 2010-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.cache.config;
/**
* Basic service interface.
*
* @author Costin Leau
*/
public interface CacheableService<T> {
T cache(Object arg1);
void invalidate(Object arg1);
void evictEarly(Object arg1);
void evictAll(Object arg1);
void evictWithException(Object arg1);
void evict(Object arg1, Object arg2);
void invalidateEarly(Object arg1, Object arg2);
T conditional(int field);
T key(Object arg1, Object arg2);
T name(Object arg1);
T nullValue(Object arg1);
T update(Object arg1);
T conditionalUpdate(Object arg2);
Number nullInvocations();
T rootVars(Object arg1);
T throwChecked(Object arg1) throws Exception;
T throwUnchecked(Object arg1);
// multi annotations
T multiCache(Object arg1);
T multiEvict(Object arg1);
T multiCacheAndEvict(Object arg1);
T multiConditionalCacheAndEvict(Object arg1);
T multiUpdate(Object arg1);
}
@@ -1,144 +1,144 @@
/*
* Copyright 2010-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.cache.config;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* Simple cacheable service
*
* @author Costin Leau
*/
public class DefaultCacheableService implements CacheableService<Long> {
private final AtomicLong counter = new AtomicLong();
private final AtomicLong nullInvocations = new AtomicLong();
@Cacheable("default")
public Long cache(Object arg1) {
return counter.getAndIncrement();
}
@CacheEvict("default")
public void invalidate(Object arg1) {
}
@CacheEvict("default")
public void evictWithException(Object arg1) {
throw new RuntimeException("exception thrown - evict should NOT occur");
}
@CacheEvict(value = "default", allEntries = true)
public void evictAll(Object arg1) {
}
@CacheEvict(value = "default", beforeInvocation = true)
public void evictEarly(Object arg1) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@CacheEvict(value = "default", key = "#p0")
public void evict(Object arg1, Object arg2) {
}
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
public void invalidateEarly(Object arg1, Object arg2) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@Cacheable(value = "default", condition = "#classField == 3")
public Long conditional(int classField) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#p0")
public Long key(Object arg1, Object arg2) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName")
public Long name(Object arg1) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
public Long rootVars(Object arg1) {
return counter.getAndIncrement();
}
@CachePut("default")
public Long update(Object arg1) {
return counter.getAndIncrement();
}
@CachePut(value = "default", condition = "#arg.equals(3)")
public Long conditionalUpdate(Object arg) {
return Long.valueOf(arg.toString());
}
@Cacheable("default")
public Long nullValue(Object arg1) {
nullInvocations.incrementAndGet();
return null;
}
public Number nullInvocations() {
return nullInvocations.get();
}
@Cacheable("default")
public Long throwChecked(Object arg1) throws Exception {
throw new Exception(arg1.toString());
}
@Cacheable("default")
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException(arg1.toString());
}
// multi annotations
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
public Long multiCache(Object arg1) {
return counter.getAndIncrement();
}
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
public Long multiEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
public Long multiCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
public Long multiConditionalCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
public Long multiUpdate(Object arg1) {
return Long.valueOf(arg1.toString());
}
/*
* Copyright 2010-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.cache.config;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* Simple cacheable service
*
* @author Costin Leau
*/
public class DefaultCacheableService implements CacheableService<Long> {
private final AtomicLong counter = new AtomicLong();
private final AtomicLong nullInvocations = new AtomicLong();
@Cacheable("default")
public Long cache(Object arg1) {
return counter.getAndIncrement();
}
@CacheEvict("default")
public void invalidate(Object arg1) {
}
@CacheEvict("default")
public void evictWithException(Object arg1) {
throw new RuntimeException("exception thrown - evict should NOT occur");
}
@CacheEvict(value = "default", allEntries = true)
public void evictAll(Object arg1) {
}
@CacheEvict(value = "default", beforeInvocation = true)
public void evictEarly(Object arg1) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@CacheEvict(value = "default", key = "#p0")
public void evict(Object arg1, Object arg2) {
}
@CacheEvict(value = "default", key = "#p0", beforeInvocation = true)
public void invalidateEarly(Object arg1, Object arg2) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@Cacheable(value = "default", condition = "#classField == 3")
public Long conditional(int classField) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#p0")
public Long key(Object arg1, Object arg2) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName")
public Long name(Object arg1) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
public Long rootVars(Object arg1) {
return counter.getAndIncrement();
}
@CachePut("default")
public Long update(Object arg1) {
return counter.getAndIncrement();
}
@CachePut(value = "default", condition = "#arg.equals(3)")
public Long conditionalUpdate(Object arg) {
return Long.valueOf(arg.toString());
}
@Cacheable("default")
public Long nullValue(Object arg1) {
nullInvocations.incrementAndGet();
return null;
}
public Number nullInvocations() {
return nullInvocations.get();
}
@Cacheable("default")
public Long throwChecked(Object arg1) throws Exception {
throw new Exception(arg1.toString());
}
@Cacheable("default")
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException(arg1.toString());
}
// multi annotations
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
public Long multiCache(Object arg1) {
return counter.getAndIncrement();
}
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
public Long multiEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
public Long multiCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
public Long multiConditionalCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
public Long multiUpdate(Object arg1) {
return Long.valueOf(arg1.toString());
}
}
@@ -0,0 +1,23 @@
/*
* 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.cache.config;
import org.springframework.cache.interceptor.DefaultKeyGenerator;
public class SomeKeyGenerator extends DefaultKeyGenerator {
}
@@ -1,43 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--
<aop:config>
<aop:advisor advice-ref="debugInterceptor" pointcut="execution(* *..CacheableService.*(..))" order="1"/>
</aop:config>
<bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheOperationSources" ref="annotationSource"/>
</bean>
<bean id="annotationSource" class="org.springframework.cache.annotation.AnnotationCacheOperationSource"/>
-->
<cache:annotation-driven mode="aspectj"/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="primary"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="secondary"/>
</set>
</property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="service" class="org.springframework.cache.config.DefaultCacheableService"/>
<bean id="classService" class="org.springframework.cache.config.AnnotatedClassCacheableService"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--
<aop:config>
<aop:advisor advice-ref="debugInterceptor" pointcut="execution(* *..CacheableService.*(..))" order="1"/>
</aop:config>
<bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheOperationSources" ref="annotationSource"/>
</bean>
<bean id="annotationSource" class="org.springframework.cache.annotation.AnnotationCacheOperationSource"/>
-->
<cache:annotation-driven mode="aspectj" key-generator="keyGenerator"/>
<bean id="keyGenerator" class="org.springframework.cache.config.SomeKeyGenerator" />
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="primary"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="secondary"/>
</set>
</property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="service" class="org.springframework.cache.config.DefaultCacheableService"/>
<bean id="classService" class="org.springframework.cache.config.AnnotatedClassCacheableService"/>
</beans>
@@ -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.
@@ -14,16 +14,19 @@
* limitations under the License.
*/
package org.springframework.beans.factory.aspectj;
package org.springframework.context.annotation.aspectj;
import org.springframework.beans.factory.aspectj.AbstractBeanConfigurerTests;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
/**
* Tests that @EnableSpringConfigured properly registers an
* {@link AnnotationBeanConfigurerAspect}, just as does {@code <context:spring-configured>}
* {@link org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect}, just
* as does {@code <context:spring-configured>}
*
* @author Chris Beams
* @since 3.1
@@ -1,146 +1,146 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import javax.persistence.PersistenceException;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
/**
* Test for static entity mocking framework.
* @author Rod Johnson
* @author Ramnivas Laddad
*
*/
@MockStaticEntityMethods
@RunWith(JUnit4.class)
public class AnnotationDrivenStaticEntityMockingControlTest {
@Test
public void testNoArgIntReturn() {
int expectedCount = 13;
Person.countPeople();
expectReturn(expectedCount);
playback();
Assert.assertEquals(expectedCount, Person.countPeople());
}
@Test(expected=PersistenceException.class)
public void testNoArgThrows() {
Person.countPeople();
expectThrow(new PersistenceException());
playback();
Person.countPeople();
}
@Test
public void testArgMethodMatches() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
Assert.assertEquals(found, Person.findPerson(id));
}
@Test
public void testLongSeriesOfCalls() {
long id1 = 13;
long id2 = 24;
Person found1 = new Person();
Person.findPerson(id1);
expectReturn(found1);
Person found2 = new Person();
Person.findPerson(id2);
expectReturn(found2);
Person.findPerson(id1);
expectReturn(found1);
Person.countPeople();
expectReturn(0);
playback();
Assert.assertEquals(found1, Person.findPerson(id1));
Assert.assertEquals(found2, Person.findPerson(id2));
Assert.assertEquals(found1, Person.findPerson(id1));
Assert.assertEquals(0, Person.countPeople());
}
// Note delegation is used when tests are invalid and should fail, as otherwise
// the failure will occur on the verify() method in the aspect after
// this method returns, failing the test case
@Test
public void testArgMethodNoMatchExpectReturn() {
try {
new Delegate().testArgMethodNoMatchExpectReturn();
Assert.fail();
} catch (IllegalArgumentException expected) {
}
}
@Test(expected=IllegalArgumentException.class)
public void testArgMethodNoMatchExpectThrow() {
new Delegate().testArgMethodNoMatchExpectThrow();
}
private void called(Person found, long id) {
Assert.assertEquals(found, Person.findPerson(id));
}
@Test
public void testReentrant() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
called(found, id);
}
@Test(expected=IllegalStateException.class)
public void testRejectUnexpectedCall() {
new Delegate().rejectUnexpectedCall();
}
@Test(expected=IllegalStateException.class)
public void testFailTooFewCalls() {
new Delegate().failTooFewCalls();
}
@Test
public void testEmpty() {
// Test that verification check doesn't blow up if no replay() call happened
}
@Test(expected=IllegalStateException.class)
public void testDoesntEverReplay() {
new Delegate().doesntEverReplay();
}
@Test(expected=IllegalStateException.class)
public void testDoesntEverSetReturn() {
new Delegate().doesntEverSetReturn();
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import javax.persistence.PersistenceException;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*;
/**
* Test for static entity mocking framework.
* @author Rod Johnson
* @author Ramnivas Laddad
*
*/
@MockStaticEntityMethods
@RunWith(JUnit4.class)
public class AnnotationDrivenStaticEntityMockingControlTest {
@Test
public void testNoArgIntReturn() {
int expectedCount = 13;
Person.countPeople();
expectReturn(expectedCount);
playback();
Assert.assertEquals(expectedCount, Person.countPeople());
}
@Test(expected=PersistenceException.class)
public void testNoArgThrows() {
Person.countPeople();
expectThrow(new PersistenceException());
playback();
Person.countPeople();
}
@Test
public void testArgMethodMatches() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
Assert.assertEquals(found, Person.findPerson(id));
}
@Test
public void testLongSeriesOfCalls() {
long id1 = 13;
long id2 = 24;
Person found1 = new Person();
Person.findPerson(id1);
expectReturn(found1);
Person found2 = new Person();
Person.findPerson(id2);
expectReturn(found2);
Person.findPerson(id1);
expectReturn(found1);
Person.countPeople();
expectReturn(0);
playback();
Assert.assertEquals(found1, Person.findPerson(id1));
Assert.assertEquals(found2, Person.findPerson(id2));
Assert.assertEquals(found1, Person.findPerson(id1));
Assert.assertEquals(0, Person.countPeople());
}
// Note delegation is used when tests are invalid and should fail, as otherwise
// the failure will occur on the verify() method in the aspect after
// this method returns, failing the test case
@Test
public void testArgMethodNoMatchExpectReturn() {
try {
new Delegate().testArgMethodNoMatchExpectReturn();
Assert.fail();
} catch (IllegalArgumentException expected) {
}
}
@Test(expected=IllegalArgumentException.class)
public void testArgMethodNoMatchExpectThrow() {
new Delegate().testArgMethodNoMatchExpectThrow();
}
private void called(Person found, long id) {
Assert.assertEquals(found, Person.findPerson(id));
}
@Test
public void testReentrant() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
expectReturn(found);
playback();
called(found, id);
}
@Test(expected=IllegalStateException.class)
public void testRejectUnexpectedCall() {
new Delegate().rejectUnexpectedCall();
}
@Test(expected=IllegalStateException.class)
public void testFailTooFewCalls() {
new Delegate().failTooFewCalls();
}
@Test
public void testEmpty() {
// Test that verification check doesn't blow up if no replay() call happened
}
@Test(expected=IllegalStateException.class)
public void testDoesntEverReplay() {
new Delegate().doesntEverReplay();
}
@Test(expected=IllegalStateException.class)
public void testDoesntEverSetReturn() {
new Delegate().doesntEverSetReturn();
}
}
@@ -1,92 +1,92 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import java.rmi.RemoteException;
import javax.persistence.PersistenceException;
import junit.framework.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
import org.springframework.mock.staticmock.MockStaticEntityMethods;
//Used because verification failures occur after method returns,
//so we can't test for them in the test case itself
@MockStaticEntityMethods
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
public class Delegate {
@Test
public void testArgMethodNoMatchExpectReturn() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
AnnotationDrivenStaticEntityMockingControl.playback();
Assert.assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void testArgMethodNoMatchExpectThrow() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
AnnotationDrivenStaticEntityMockingControl.playback();
Assert.assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void failTooFewCalls() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
AnnotationDrivenStaticEntityMockingControl.playback();
Assert.assertEquals(found, Person.findPerson(id));
}
@Test
public void doesntEverReplay() {
Person.countPeople();
}
@Test
public void doesntEverSetReturn() {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
}
@Test
public void rejectUnexpectedCall() {
AnnotationDrivenStaticEntityMockingControl.playback();
Person.countPeople();
}
@Test(expected=RemoteException.class)
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
// No calls to allow verification failure
throw new RemoteException();
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import java.rmi.RemoteException;
import javax.persistence.PersistenceException;
import junit.framework.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl;
import org.springframework.mock.staticmock.MockStaticEntityMethods;
//Used because verification failures occur after method returns,
//so we can't test for them in the test case itself
@MockStaticEntityMethods
@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl
public class Delegate {
@Test
public void testArgMethodNoMatchExpectReturn() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
AnnotationDrivenStaticEntityMockingControl.playback();
Assert.assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void testArgMethodNoMatchExpectThrow() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException());
AnnotationDrivenStaticEntityMockingControl.playback();
Assert.assertEquals(found, Person.findPerson(id + 1));
}
@Test
public void failTooFewCalls() {
long id = 13;
Person found = new Person();
Person.findPerson(id);
AnnotationDrivenStaticEntityMockingControl.expectReturn(found);
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.expectReturn(25);
AnnotationDrivenStaticEntityMockingControl.playback();
Assert.assertEquals(found, Person.findPerson(id));
}
@Test
public void doesntEverReplay() {
Person.countPeople();
}
@Test
public void doesntEverSetReturn() {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
}
@Test
public void rejectUnexpectedCall() {
AnnotationDrivenStaticEntityMockingControl.playback();
Person.countPeople();
}
@Test(expected=RemoteException.class)
public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException {
Person.countPeople();
AnnotationDrivenStaticEntityMockingControl.playback();
// No calls to allow verification failure
throw new RemoteException();
}
}
@@ -1,24 +1,24 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import javax.persistence.Entity;
@Entity
public class Person {
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
import javax.persistence.Entity;
@Entity
public class Person {
}
@@ -1,100 +1,100 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
privileged aspect Person_Roo_Entity {
@javax.persistence.PersistenceContext
transient javax.persistence.EntityManager Person.entityManager;
@javax.persistence.Id
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
@javax.persistence.Column(name = "id")
private java.lang.Long Person.id;
@javax.persistence.Version
@javax.persistence.Column(name = "version")
private java.lang.Integer Person.version;
public java.lang.Long Person.getId() {
return this.id;
}
public void Person.setId(java.lang.Long id) {
this.id = id;
}
public java.lang.Integer Person.getVersion() {
return this.version;
}
public void Person.setVersion(java.lang.Integer version) {
this.version = version;
}
@org.springframework.transaction.annotation.Transactional
public void Person.persist() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
this.entityManager.persist(this);
}
@org.springframework.transaction.annotation.Transactional
public void Person.remove() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
this.entityManager.remove(this);
}
@org.springframework.transaction.annotation.Transactional
public void Person.flush() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
this.entityManager.flush();
}
@org.springframework.transaction.annotation.Transactional
public void Person.merge() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
Person merged = this.entityManager.merge(this);
this.entityManager.flush();
this.id = merged.getId();
}
public static long Person.countPeople() {
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
}
public static java.util.List<Person> Person.findAllPeople() {
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em.createQuery("select o from Person o").getResultList();
}
public static Person Person.findPerson(java.lang.Long id) {
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em.find(Person.class, id);
}
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
}
}
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mock.staticmock;
privileged aspect Person_Roo_Entity {
@javax.persistence.PersistenceContext
transient javax.persistence.EntityManager Person.entityManager;
@javax.persistence.Id
@javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
@javax.persistence.Column(name = "id")
private java.lang.Long Person.id;
@javax.persistence.Version
@javax.persistence.Column(name = "version")
private java.lang.Integer Person.version;
public java.lang.Long Person.getId() {
return this.id;
}
public void Person.setId(java.lang.Long id) {
this.id = id;
}
public java.lang.Integer Person.getVersion() {
return this.version;
}
public void Person.setVersion(java.lang.Integer version) {
this.version = version;
}
@org.springframework.transaction.annotation.Transactional
public void Person.persist() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
this.entityManager.persist(this);
}
@org.springframework.transaction.annotation.Transactional
public void Person.remove() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
this.entityManager.remove(this);
}
@org.springframework.transaction.annotation.Transactional
public void Person.flush() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
this.entityManager.flush();
}
@org.springframework.transaction.annotation.Transactional
public void Person.merge() {
if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
Person merged = this.entityManager.merge(this);
this.entityManager.flush();
this.id = merged.getId();
}
public static long Person.countPeople() {
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return (Long) em.createQuery("select count(o) from Person o").getSingleResult();
}
public static java.util.List<Person> Person.findAllPeople() {
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em.createQuery("select o from Person o").getResultList();
}
public static Person Person.findPerson(java.lang.Long id) {
if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person");
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em.find(Person.class, id);
}
public static java.util.List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
javax.persistence.EntityManager em = new Person().entityManager;
if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
}
}
@@ -1,178 +1,218 @@
/*
* Copyright 2002-2010 the original author 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.scheduling.aspectj;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import junit.framework.Assert;
import static junit.framework.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
/**
* @author Ramnivas Laddad
*/
public class AnnotationAsyncExecutionAspectTests {
private static final long WAIT_TIME = 1000; //milli seconds
private CountingExecutor executor;
@Before
public void setUp() {
executor = new CountingExecutor();
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
}
@Test
public void asyncMethodGetsRoutedAsynchronously() {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
obj.incrementAsync();
executor.waitForCompletion();
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
Future<Integer> future = obj.incrementReturningAFuture();
// No need to executor.waitForCompletion() as future.get() will have the same effect
assertEquals(5, future.get().intValue());
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void syncMethodGetsRoutedSynchronously() {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
obj.increment();
assertEquals(1, obj.counter);
assertEquals(0, executor.submitStartCounter);
assertEquals(0, executor.submitCompleteCounter);
}
@Test
public void voidMethodInAsyncClassGetsRoutedAsynchronously() {
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
obj.increment();
executor.waitForCompletion();
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
Future<Integer> future = obj.incrementReturningAFuture();
assertEquals(5, future.get().intValue());
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() {
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
int returnValue = obj.return5();
assertEquals(5, returnValue);
assertEquals(0, executor.submitStartCounter);
assertEquals(0, executor.submitCompleteCounter);
}
@SuppressWarnings("serial")
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
int submitStartCounter;
int submitCompleteCounter;
@Override
public <T> Future<T> submit(Callable<T> task) {
submitStartCounter++;
Future<T> future = super.submit(task);
submitCompleteCounter++;
synchronized (this) {
notifyAll();
}
return future;
}
public synchronized void waitForCompletion() {
try {
wait(WAIT_TIME);
} catch (InterruptedException e) {
Assert.fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds");
}
}
}
static class ClassWithoutAsyncAnnotation {
int counter;
@Async public void incrementAsync() {
counter++;
}
public void increment() {
counter++;
}
@Async public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<Integer>(5);
}
// It should be an error to attach @Async to a method that returns a non-void
// or non-Future.
// We need to keep this commented out, otherwise there will be a compile-time error.
// Please uncomment and re-comment this periodically to check that the compiler
// produces an error message due to the 'declare error' statement
// in AnnotationAsyncExecutionAspect
// @Async public int getInt() {
// return 0;
// }
}
@Async
static class ClassWithAsyncAnnotation {
int counter;
public void increment() {
counter++;
}
// Manually check that there is a warning from the 'declare warning' statement in AnnotationAsynchExecutionAspect
public int return5() {
return 5;
}
public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<Integer>(5);
}
}
}
/*
* 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.scheduling.aspectj;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.*;
/**
* Unit tests for {@link AnnotationAsyncExecutionAspect}.
*
* @author Ramnivas Laddad
*/
public class AnnotationAsyncExecutionAspectTests {
private static final long WAIT_TIME = 1000; //milliseconds
private CountingExecutor executor;
@Before
public void setUp() {
executor = new CountingExecutor();
AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor);
}
@Test
public void asyncMethodGetsRoutedAsynchronously() {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
obj.incrementAsync();
executor.waitForCompletion();
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
Future<Integer> future = obj.incrementReturningAFuture();
// No need to executor.waitForCompletion() as future.get() will have the same effect
assertEquals(5, future.get().intValue());
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void syncMethodGetsRoutedSynchronously() {
ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation();
obj.increment();
assertEquals(1, obj.counter);
assertEquals(0, executor.submitStartCounter);
assertEquals(0, executor.submitCompleteCounter);
}
@Test
public void voidMethodInAsyncClassGetsRoutedAsynchronously() {
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
obj.increment();
executor.waitForCompletion();
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException {
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
Future<Integer> future = obj.incrementReturningAFuture();
assertEquals(5, future.get().intValue());
assertEquals(1, obj.counter);
assertEquals(1, executor.submitStartCounter);
assertEquals(1, executor.submitCompleteCounter);
}
@Test
public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() {
ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation();
int returnValue = obj.return5();
assertEquals(5, returnValue);
assertEquals(0, executor.submitStartCounter);
assertEquals(0, executor.submitCompleteCounter);
}
@Test
public void qualifiedAsyncMethodsAreRoutedToCorrectExecutor() throws InterruptedException, ExecutionException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("e1", new RootBeanDefinition(ThreadPoolTaskExecutor.class));
AnnotationAsyncExecutionAspect.aspectOf().setBeanFactory(beanFactory);
ClassWithQualifiedAsyncMethods obj = new ClassWithQualifiedAsyncMethods();
Future<Thread> defaultThread = obj.defaultWork();
assertThat(defaultThread.get(), not(Thread.currentThread()));
assertThat(defaultThread.get().getName(), not(startsWith("e1-")));
Future<Thread> e1Thread = obj.e1Work();
assertThat(e1Thread.get().getName(), startsWith("e1-"));
}
@SuppressWarnings("serial")
private static class CountingExecutor extends SimpleAsyncTaskExecutor {
int submitStartCounter;
int submitCompleteCounter;
@Override
public <T> Future<T> submit(Callable<T> task) {
submitStartCounter++;
Future<T> future = super.submit(task);
submitCompleteCounter++;
synchronized (this) {
notifyAll();
}
return future;
}
public synchronized void waitForCompletion() {
try {
wait(WAIT_TIME);
} catch (InterruptedException e) {
fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds");
}
}
}
static class ClassWithoutAsyncAnnotation {
int counter;
@Async public void incrementAsync() {
counter++;
}
public void increment() {
counter++;
}
@Async public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<Integer>(5);
}
/**
* It should raise an error to attach @Async to a method that returns a non-void
* or non-Future. This method must remain commented-out, otherwise there will be a
* compile-time error. Uncomment to manually verify that the compiler produces an
* error message due to the 'declare error' statement in
* {@link AnnotationAsyncExecutionAspect}.
*/
// @Async public int getInt() {
// return 0;
// }
}
@Async
static class ClassWithAsyncAnnotation {
int counter;
public void increment() {
counter++;
}
// Manually check that there is a warning from the 'declare warning' statement in
// AnnotationAsyncExecutionAspect
public int return5() {
return 5;
}
public Future<Integer> incrementReturningAFuture() {
counter++;
return new AsyncResult<Integer>(5);
}
}
static class ClassWithQualifiedAsyncMethods {
@Async
public Future<Thread> defaultWork() {
return new AsyncResult<Thread>(Thread.currentThread());
}
@Async("e1")
public Future<Thread> e1Work() {
return new AsyncResult<Thread>(Thread.currentThread());
}
}
}
@@ -1,34 +1,34 @@
/*
* Copyright 2002-2006 the original author 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.
*
* Created on 11 Sep 2006 by Adrian Colyer
*/
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Adrian Colyer
* @since 2.0
*/
public class ClassWithPrivateAnnotatedMember {
public void doSomething() {
doInTransaction();
}
@Transactional
private void doInTransaction() {}
}
/*
* Copyright 2002-2006 the original author 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.
*
* Created on 11 Sep 2006 by Adrian Colyer
*/
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Adrian Colyer
* @since 2.0
*/
public class ClassWithPrivateAnnotatedMember {
public void doSomething() {
doInTransaction();
}
@Transactional
private void doInTransaction() {}
}
@@ -1,34 +1,34 @@
/*
* Copyright 2002-2006 the original author 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.
*
* Created on 11 Sep 2006 by Adrian Colyer
*/
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Adrian Colyer
* @since 2.0
*/
public class ClassWithProtectedAnnotatedMember {
public void doSomething() {
doInTransaction();
}
@Transactional
protected void doInTransaction() {}
}
/*
* Copyright 2002-2006 the original author 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.
*
* Created on 11 Sep 2006 by Adrian Colyer
*/
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Adrian Colyer
* @since 2.0
*/
public class ClassWithProtectedAnnotatedMember {
public void doSomething() {
doInTransaction();
}
@Transactional
protected void doInTransaction() {}
}
@@ -1,10 +1,10 @@
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public interface ITransactional {
Object echo(Throwable t) throws Throwable;
}
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public interface ITransactional {
Object echo(Throwable t) throws Throwable;
}
@@ -1,19 +1,19 @@
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
public class MethodAnnotationOnClassWithNoInterface {
@Transactional(rollbackFor=InterruptedException.class)
public Object echo(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return t;
}
public void noTransactionAttribute() {
}
}
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
public class MethodAnnotationOnClassWithNoInterface {
@Transactional(rollbackFor=InterruptedException.class)
public Object echo(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return t;
}
public void noTransactionAttribute() {
}
}
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
<bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<bean class="org.springframework.transaction.aspectj.TransactionalAnnotationOnlyOnClassWithNoInterface"/>
<bean class="org.springframework.transaction.aspectj.ClassWithProtectedAnnotatedMember"/>
<bean class="org.springframework.transaction.aspectj.ClassWithPrivateAnnotatedMember"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="transactionManager" class="org.springframework.transaction.CallCountingTransactionManager"/>
<bean class="org.springframework.transaction.aspectj.AnnotationTransactionAspect" factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<bean class="org.springframework.transaction.aspectj.TransactionalAnnotationOnlyOnClassWithNoInterface"/>
<bean class="org.springframework.transaction.aspectj.ClassWithProtectedAnnotatedMember"/>
<bean class="org.springframework.transaction.aspectj.ClassWithPrivateAnnotatedMember"/>
</beans>
@@ -1,261 +1,261 @@
/*
* Copyright 2002-2007 the original author 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.transaction.aspectj;
import java.lang.reflect.Method;
import junit.framework.AssertionFailedError;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttribute;
/**
* @author Rod Johnson
* @author Ramnivas Laddad
*/
public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests {
private TransactionAspectSupport transactionAspect;
private CallCountingTransactionManager txManager;
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
public void setAnnotationOnlyOnClassWithNoInterface(
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
}
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
this.beanWithAnnotatedProtectedMethod = aBean;
}
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
this.beanWithAnnotatedPrivateMethod = aBean;
}
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
this.transactionAspect = transactionAspect;
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
}
public TransactionAspectSupport getTransactionAspect() {
return this.transactionAspect;
}
@Override
protected String getConfigPath() {
return "TransactionAspectTests-context.xml";
}
public void testCommitOnAnnotatedClass() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
annotationOnlyOnClassWithNoInterface.echo(null);
assertEquals(1, txManager.commits);
}
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
beanWithAnnotatedProtectedMethod.doInTransaction();
assertEquals(1, txManager.commits);
}
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
beanWithAnnotatedPrivateMethod.doSomething();
assertEquals(1, txManager.commits);
}
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
txManager.clear();
assertEquals(0,txManager.begun);
annotationOnlyOnClassWithNoInterface.nonTransactionalMethod();
assertEquals(0,txManager.begun);
}
public void testCommitOnAnnotatedMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
methodAnnotationOnly.echo(null);
assertEquals(1, txManager.commits);
}
public static class NotTransactional {
public void noop() {
}
}
public void testNotTransactional() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
new NotTransactional().noop();
assertEquals(0, txManager.begun);
}
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return annotationOnlyOnClassWithNoInterface.echo(new Exception());
}
}, false);
}
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException());
}
}, true);
}
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
}
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception());
}
}, false);
}
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
}
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception());
}
}, false);
}
public static class ImplementsAnnotatedInterface implements ITransactional {
public Object echo(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return t;
}
}
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
// testRollback(new TransactionOperationCallback() {
// public Object performTransactionalOperation() throws Throwable {
// return new ImplementsAnnotatedInterface().echo(new Exception());
// }
// }, false);
final Exception ex = new Exception();
testNotTransactional(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new ImplementsAnnotatedInterface().echo(ex);
}
}, ex);
}
/**
* Note: resolution does not occur. Thus we can't make a class transactional if
* it implements a transactionally annotated interface. This behaviour could only
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
* @throws SecurityException
* @throws NoSuchMethodException
*/
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException {
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
assertNull(ta);
}
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
// testRollback(new TransactionOperationCallback() {
// public Object performTransactionalOperation() throws Throwable {
// return new ImplementsAnnotatedInterface().echo(new RuntimeException());
// }
// }, true);
final Exception rollbackProvokingException = new RuntimeException();
testNotTransactional(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new ImplementsAnnotatedInterface().echo(rollbackProvokingException);
}
}, rollbackProvokingException);
}
protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
try {
toc.performTransactionalOperation();
assertEquals(1, txManager.commits);
}
catch (Throwable caught) {
if (caught instanceof AssertionFailedError) {
return;
}
}
if (rollback) {
assertEquals(1, txManager.rollbacks);
}
assertEquals(1, txManager.begun);
}
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
try {
toc.performTransactionalOperation();
}
catch (Throwable t) {
if (expected == null) {
fail("Expected " + expected);
}
assertSame(expected, t);
}
finally {
assertEquals(0, txManager.begun);
}
}
private interface TransactionOperationCallback {
Object performTransactionalOperation() throws Throwable;
}
}
/*
* Copyright 2002-2007 the original author 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.transaction.aspectj;
import java.lang.reflect.Method;
import junit.framework.AssertionFailedError;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.transaction.CallCountingTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.interceptor.TransactionAttribute;
/**
* @author Rod Johnson
* @author Ramnivas Laddad
*/
public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests {
private TransactionAspectSupport transactionAspect;
private CallCountingTransactionManager txManager;
private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface;
private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod;
private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod;
private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface();
public void setAnnotationOnlyOnClassWithNoInterface(
TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) {
this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface;
}
public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) {
this.beanWithAnnotatedProtectedMethod = aBean;
}
public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) {
this.beanWithAnnotatedPrivateMethod = aBean;
}
public void setTransactionAspect(TransactionAspectSupport transactionAspect) {
this.transactionAspect = transactionAspect;
this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager();
}
public TransactionAspectSupport getTransactionAspect() {
return this.transactionAspect;
}
@Override
protected String getConfigPath() {
return "TransactionAspectTests-context.xml";
}
public void testCommitOnAnnotatedClass() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
annotationOnlyOnClassWithNoInterface.echo(null);
assertEquals(1, txManager.commits);
}
public void testCommitOnAnnotatedProtectedMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
beanWithAnnotatedProtectedMethod.doInTransaction();
assertEquals(1, txManager.commits);
}
public void testCommitOnAnnotatedPrivateMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
beanWithAnnotatedPrivateMethod.doSomething();
assertEquals(1, txManager.commits);
}
public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable {
txManager.clear();
assertEquals(0,txManager.begun);
annotationOnlyOnClassWithNoInterface.nonTransactionalMethod();
assertEquals(0,txManager.begun);
}
public void testCommitOnAnnotatedMethod() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
methodAnnotationOnly.echo(null);
assertEquals(1, txManager.commits);
}
public static class NotTransactional {
public void noop() {
}
}
public void testNotTransactional() throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
new NotTransactional().noop();
assertEquals(0, txManager.begun);
}
public void testDefaultCommitOnAnnotatedClass() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return annotationOnlyOnClassWithNoInterface.echo(new Exception());
}
}, false);
}
public void testDefaultRollbackOnAnnotatedClass() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException());
}
}, true);
}
public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface {
}
public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception());
}
}, false);
}
public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface {
}
public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable {
testRollback(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception());
}
}, false);
}
public static class ImplementsAnnotatedInterface implements ITransactional {
public Object echo(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return t;
}
}
public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable {
// testRollback(new TransactionOperationCallback() {
// public Object performTransactionalOperation() throws Throwable {
// return new ImplementsAnnotatedInterface().echo(new Exception());
// }
// }, false);
final Exception ex = new Exception();
testNotTransactional(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new ImplementsAnnotatedInterface().echo(ex);
}
}, ex);
}
/**
* Note: resolution does not occur. Thus we can't make a class transactional if
* it implements a transactionally annotated interface. This behaviour could only
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
* @throws SecurityException
* @throws NoSuchMethodException
*/
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException {
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
assertNull(ta);
}
public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable {
// testRollback(new TransactionOperationCallback() {
// public Object performTransactionalOperation() throws Throwable {
// return new ImplementsAnnotatedInterface().echo(new RuntimeException());
// }
// }, true);
final Exception rollbackProvokingException = new RuntimeException();
testNotTransactional(new TransactionOperationCallback() {
public Object performTransactionalOperation() throws Throwable {
return new ImplementsAnnotatedInterface().echo(rollbackProvokingException);
}
}, rollbackProvokingException);
}
protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
try {
toc.performTransactionalOperation();
assertEquals(1, txManager.commits);
}
catch (Throwable caught) {
if (caught instanceof AssertionFailedError) {
return;
}
}
if (rollback) {
assertEquals(1, txManager.rollbacks);
}
assertEquals(1, txManager.begun);
}
protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable {
txManager.clear();
assertEquals(0, txManager.begun);
try {
toc.performTransactionalOperation();
}
catch (Throwable t) {
if (expected == null) {
fail("Expected " + expected);
}
assertSame(expected, t);
}
finally {
assertEquals(0, txManager.begun);
}
}
private interface TransactionOperationCallback {
Object performTransactionalOperation() throws Throwable;
}
}
@@ -1,20 +1,20 @@
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class TransactionalAnnotationOnlyOnClassWithNoInterface {
public Object echo(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return t;
}
void nonTransactionalMethod() {
// no-op
}
}
package org.springframework.transaction.aspectj;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class TransactionalAnnotationOnlyOnClassWithNoInterface {
public Object echo(Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return t;
}
void nonTransactionalMethod() {
// no-op
}
}
+20 -20
View File
@@ -1,20 +1,20 @@
Bundle-SymbolicName: org.springframework.aspects
Bundle-Name: Spring Aspects
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Template:
javax.persistence;version="[1.0.0,3.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
org.springframework.context.*;version=${spring.osgi.range},
org.springframework.beans.*;version=${spring.osgi.range},
org.springframework.cache.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.orm.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional
Ignored-Existing-Headers:
Bnd-LastModified,
Import-Package,
Tool
Bundle-SymbolicName: org.springframework.aspects
Bundle-Name: Spring Aspects
Bundle-Vendor: SpringSource
Bundle-ManifestVersion: 2
Import-Template:
javax.persistence;version="[1.0.0,3.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.aspectj.*;version=${aj.osgi.range};resolution:=optional,
org.springframework.context.*;version=${spring.osgi.range},
org.springframework.beans.*;version=${spring.osgi.range},
org.springframework.cache.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.core.*;version=${spring.osgi.range},
org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.orm.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional,
org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional
Ignored-Existing-Headers:
Bnd-LastModified,
Import-Package,
Tool
+30 -30
View File
@@ -1,30 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntry type="module" module-name="core" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="library" name="Commons Logging" level="project" />
<orderEntry type="library" name="EasyMock" level="project" />
<orderEntry type="library" name="javax.el" level="project" />
<orderEntry type="library" name="javax.inject" level="project" />
<orderEntry type="library" name="Hamcrest" level="project" />
<orderEntry type="library" name="JUnit" level="project" />
<orderEntry type="library" name="Log4j" level="project" />
</component>
<component name="copyright">
<Base>
<setting name="state" value="2" />
</Base>
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<module relativePaths="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntry type="module" module-name="core" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="library" name="Commons Logging" level="project" />
<orderEntry type="library" name="EasyMock" level="project" />
<orderEntry type="library" name="javax.el" level="project" />
<orderEntry type="library" name="javax.inject" level="project" />
<orderEntry type="library" name="Hamcrest" level="project" />
<orderEntry type="library" name="JUnit" level="project" />
<orderEntry type="library" name="Log4j" level="project" />
</component>
<component name="copyright">
<Base>
<setting name="state" value="2" />
</Base>
</component>
</module>
+14 -6
View File
@@ -1,17 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<packaging>jar</packaging>
<version>3.1.0.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.0.RELEASE</version>
<version>3.1.5.BUILD-SNAPSHOT</version>
</parent>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<dependencies>
<dependency>
<groupId>org.hamcrest</groupId>
@@ -22,13 +30,13 @@
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
@@ -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-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.
@@ -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,282 +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.util.Assert;
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
* <a href="http://download.oracle.com/javase/tutorial/javabeans/properties/indexed.html">
* indexed properties</a> are fully supported.
* 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;
*
* <p>The wrapped {@code BeanInfo} object is not modified in any way.
* 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.
*
* @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;
// PropertyDescriptor instances from the delegate object are never added directly, but always
// copied to the local collection of #propertyDescriptors and returned by calls to
// #getPropertyDescriptors(). this algorithm iterates through all methods (method descriptors)
// in the wrapped BeanInfo object, copying any existing PropertyDescriptor or creating a new
// one for any non-standard setter methods found.
for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
new SimpleNonIndexedPropertyDescriptor(pd));
}
ALL_METHODS:
for (MethodDescriptor md : delegate.getMethodDescriptors()) {
Method method = md.getMethod();
// 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 = pd.getReadMethod();
Method writeMethod = pd.getWriteMethod();
// 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 = ipd.getReadMethod();
Method writeMethod = ipd.getWriteMethod();
Method indexedReadMethod = ipd.getIndexedReadMethod();
Method indexedWriteMethod = ipd.getIndexedWriteMethod();
// has the setter already been found by the wrapped BeanInfo?
if (indexedWriteMethod != null
&& indexedWriteMethod.getName().equals(method.getName())) {
// yes -> copy it, including corresponding getter method (if any -- may be null)
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
continue ALL_METHODS;
}
// has a getter corresponding to this setter already been found by the wrapped BeanInfo?
if (indexedReadMethod != null
&& indexedReadMethod.getName().equals(getterMethodNameFor(propertyName))
&& indexedReadMethod.getReturnType().equals(method.getParameterTypes()[1])) {
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, method);
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?
for (PropertyDescriptor existingPD : this.propertyDescriptors) {
if (method.equals(pd.getReadMethod())
&& existingPD.getName().equals(pd.getName())) {
if (existingPD.getReadMethod() == null) {
// no -> add it now
this.addOrUpdatePropertyDescriptor(pd, pd.getName(), method, pd.getWriteMethod());
}
// yes -> do not add a duplicate
continue ALL_METHODS;
}
}
if (method == pd.getReadMethod()
|| (pd instanceof IndexedPropertyDescriptor && method == ((IndexedPropertyDescriptor) pd).getIndexedReadMethod())) {
// yes -> copy it, including corresponding setter method (if any -- may be null)
if (pd instanceof IndexedPropertyDescriptor) {
this.addOrUpdatePropertyDescriptor(pd, pd.getName(), pd.getReadMethod(), pd.getWriteMethod(), ((IndexedPropertyDescriptor)pd).getIndexedReadMethod(), ((IndexedPropertyDescriptor)pd).getIndexedWriteMethod());
} else {
this.addOrUpdatePropertyDescriptor(pd, pd.getName(), pd.getReadMethod(), pd.getWriteMethod());
}
continue ALL_METHODS;
}
}
for (Method method : findCandidateWriteMethods(delegate.getMethodDescriptors())) {
handleCandidateWriteMethod(method);
}
}
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 (existingPD.getReadMethod() != null) {
if (readMethod != null && existingPD.getReadMethod().getReturnType() != readMethod.getReturnType()
|| writeMethod != null && existingPD.getReadMethod().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 (existingPD.getWriteMethod() != null) {
if (readMethod != null && existingPD.getWriteMethod().getParameterTypes()[0] != readMethod.getReturnType()
|| writeMethod != null && existingPD.getWriteMethod().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.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 (existingIPD.getIndexedReadMethod() != null) {
if (indexedReadMethod != null && existingIPD.getIndexedReadMethod().getReturnType() != indexedReadMethod.getReturnType()
|| indexedWriteMethod != null && existingIPD.getIndexedReadMethod().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 (existingIPD.getIndexedWriteMethod() != null) {
if (indexedReadMethod != null && existingIPD.getIndexedWriteMethod().getParameterTypes()[1] != indexedReadMethod.getReturnType()
|| indexedWriteMethod != null && existingIPD.getIndexedWriteMethod().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.warn(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.setReadMethod(readMethod);
try {
pd.setWriteMethod(writeMethod);
} catch (IntrospectionException ex) {
logger.warn(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
}
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() {
@@ -325,44 +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 alphanumerically 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-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.
@@ -44,6 +44,7 @@ import org.springframework.util.StringUtils;
*
* @author Juergen Hoeller
* @author Rob Harrop
* @author Dave Syer
* @since 2.0
* @see BeanWrapperImpl
* @see SimpleTypeConverter
@@ -158,11 +159,13 @@ class TypeConverterDelegate {
}
}
if (editor == null) {
editor = findDefaultEditor(requiredType, typeDescriptor);
editor = findDefaultEditor(requiredType);
}
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
boolean standardConversion = false;
if (requiredType != null) {
// Try to apply some standard type conversion rules if appropriate.
@@ -178,21 +181,24 @@ class TypeConverterDelegate {
// Convert elements to target type, if determined.
convertedValue = convertToTypedCollection(
(Collection) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
else if (convertedValue instanceof Map) {
// Convert keys and values to respective target type, if determined.
convertedValue = convertToTypedMap(
(Map) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
convertedValue = Array.get(convertedValue, 0);
standardConversion = true;
}
if (String.class.equals(requiredType) && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// We can stringify any primitive value...
return (T) convertedValue.toString();
}
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
if (!requiredType.isInterface() && !requiredType.isEnum()) {
if (firstAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
Constructor strCtor = requiredType.getConstructor(String.class);
return (T) BeanUtils.instantiateClass(strCtor, convertedValue);
@@ -214,8 +220,8 @@ class TypeConverterDelegate {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
standardConversion = true;
}
}
@@ -244,6 +250,9 @@ class TypeConverterDelegate {
}
if (firstAttemptEx != null) {
if (editor == null && !standardConversion && requiredType != null && !Object.class.equals(requiredType)) {
throw firstAttemptEx;
}
logger.debug("Original ConversionService attempt failed - ignored since " +
"PropertyEditor based conversion eventually succeeded", firstAttemptEx);
}
@@ -300,16 +309,11 @@ class TypeConverterDelegate {
/**
* Find a default editor for the given type.
* @param requiredType the type to find an editor for
* @param descriptor the JavaBeans descriptor for the property
* @return the corresponding editor, or <code>null</code> if none
*/
protected PropertyEditor findDefaultEditor(Class requiredType, TypeDescriptor typeDescriptor) {
private PropertyEditor findDefaultEditor(Class requiredType) {
PropertyEditor editor = null;
//if (typeDescriptor instanceof PropertyTypeDescriptor) {
//PropertyDescriptor pd = ((PropertyTypeDescriptor) typeDescriptor).getPropertyDescriptor();
//editor = pd.createPropertyEditor(this.targetObject);
//}
if (editor == null && requiredType != null) {
if (requiredType != null) {
// No custom editor -> check BeanWrapperImpl's default editors.
editor = this.propertyEditorRegistry.getDefaultEditor(requiredType);
if (editor == null && !String.class.equals(requiredType)) {
@@ -331,7 +335,7 @@ class TypeConverterDelegate {
* @return the new value, possibly the result of type conversion
* @throws IllegalArgumentException if type conversion failed
*/
protected Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
private Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) {
Object convertedValue = newValue;
boolean sharedEditor = false;
@@ -418,7 +422,7 @@ class TypeConverterDelegate {
* @param editor the PropertyEditor to use
* @return the converted value
*/
protected Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
private Object doConvertTextValue(Object oldValue, String newTextValue, PropertyEditor editor) {
try {
editor.setValue(oldValue);
}
@@ -432,7 +436,7 @@ class TypeConverterDelegate {
return editor.getValue();
}
protected Object convertToTypedArray(Object input, String propertyName, Class<?> componentType) {
private Object convertToTypedArray(Object input, String propertyName, Class<?> componentType) {
if (input instanceof Collection) {
// Convert Collection elements to array elements.
Collection coll = (Collection) input;
@@ -471,7 +475,7 @@ class TypeConverterDelegate {
}
@SuppressWarnings("unchecked")
protected Collection convertToTypedCollection(
private Collection convertToTypedCollection(
Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
if (!Collection.class.isAssignableFrom(requiredType)) {
@@ -553,7 +557,7 @@ class TypeConverterDelegate {
}
@SuppressWarnings("unchecked")
protected Map convertToTypedMap(
private Map convertToTypedMap(
Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {
if (!Map.class.isAssignableFrom(requiredType)) {
@@ -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.
@@ -16,6 +16,7 @@
package org.springframework.beans.factory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -37,6 +38,7 @@ import org.springframework.util.StringUtils;
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 04.07.2003
*/
public abstract class BeanFactoryUtils {
@@ -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-2008 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.
@@ -19,6 +19,7 @@ package org.springframework.beans.factory.annotation;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.util.Assert;
/**
* Extension of the {@link org.springframework.beans.factory.support.GenericBeanDefinition}
@@ -32,27 +33,46 @@ import org.springframework.core.type.StandardAnnotationMetadata;
* which also implements the AnnotatedBeanDefinition interface).
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 2.5
* @see AnnotatedBeanDefinition#getMetadata()
* @see org.springframework.core.type.StandardAnnotationMetadata
*/
@SuppressWarnings("serial")
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata annotationMetadata;
private final AnnotationMetadata metadata;
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class
*/
public AnnotatedGenericBeanDefinition(Class beanClass) {
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.annotationMetadata = new StandardAnnotationMetadata(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
/**
* Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
* allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that
* a bean was discovered specifically via component-scanning as opposed to other
* means.
* @param metadata the annotation metadata for the bean class in question
* @since 3.1.1
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
setBeanClassName(metadata.getClassName());
this.metadata = metadata;
}
public final AnnotationMetadata getMetadata() {
return this.annotationMetadata;
return this.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.
@@ -405,10 +405,16 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
protected boolean determineRequiredStatus(Annotation annotation) {
try {
Method method = ReflectionUtils.findMethod(annotation.annotationType(), this.requiredParameterName);
if (method == null) {
// annotations like @Inject and @Value don't have a method (attribute) named "required"
// -> default to required status
return true;
}
return (this.requiredParameterValue == (Boolean) ReflectionUtils.invokeMethod(method, annotation));
}
catch (Exception ex) {
// required by default
// an exception was thrown during reflective invocation of the required attribute
// -> default to required status
return true;
}
}
@@ -419,11 +425,12 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private void registerDependentBeans(String beanName, Set<String> autowiredBeanNames) {
if (beanName != null) {
for (String autowiredBeanName : autowiredBeanNames) {
beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (this.beanFactory.containsBean(autowiredBeanName)) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
}
if (logger.isDebugEnabled()) {
logger.debug(
"Autowiring by type from bean name '" + beanName + "' to bean named '" + autowiredBeanName +
"'");
logger.debug("Autowiring by type from bean name '" + beanName +
"' to bean named '" + autowiredBeanName + "'");
}
}
}
@@ -435,11 +442,11 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private Object resolvedCachedArgument(String beanName, Object cachedArgument) {
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
TypeConverter typeConverter = beanFactory.getTypeConverter();
return beanFactory.resolveDependency(descriptor, beanName, null, typeConverter);
TypeConverter typeConverter = this.beanFactory.getTypeConverter();
return this.beanFactory.resolveDependency(descriptor, beanName, null, typeConverter);
}
else if (cachedArgument instanceof RuntimeBeanReference) {
return beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
return this.beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
}
else {
return cachedArgument;
@@ -0,0 +1,137 @@
/*
* 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.beans.factory.annotation;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.util.ObjectUtils;
/**
* Convenience methods performing bean lookups related to annotations, for example
* Spring's {@link Qualifier @Qualifier} annotation.
*
* @author Chris Beams
* @since 3.1.2
* @see BeanFactoryUtils
*/
public class BeanFactoryAnnotationUtils {
/**
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
* qualifier (e.g. via {@code <qualifier>} or {@code @Qualifier}) matching the given
* qualifier, or having a bean name matching the given qualifier.
* @param beanFactory the BeanFactory to get the target bean from
* @param beanType the type of bean to retrieve
* @param qualifier the qualifier for selecting between multiple bean matches
* @return the matching bean of type {@code T} (never {@code null})
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
*/
public static <T> T qualifiedBeanOfType(BeanFactory beanFactory, Class<T> beanType, String qualifier) {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
// Full qualifier matching supported.
return qualifiedBeanOfType((ConfigurableListableBeanFactory) beanFactory, beanType, qualifier);
}
else if (beanFactory.containsBean(qualifier)) {
// Fallback: target bean at least found by bean name.
return beanFactory.getBean(qualifier, beanType);
}
else {
throw new NoSuchBeanDefinitionException(qualifier, "No matching " + beanType.getSimpleName() +
" bean found for bean name '" + qualifier +
"'! (Note: Qualifier matching not supported because given " +
"BeanFactory does not implement ConfigurableListableBeanFactory.)");
}
}
/**
* Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a qualifier
* (e.g. {@code <qualifier>} or {@code @Qualifier}) matching the given qualifier).
* @param bf the BeanFactory to get the target bean from
* @param beanType the type of bean to retrieve
* @param qualifier the qualifier for selecting between multiple bean matches
* @return the matching bean of type {@code T} (never {@code null})
* @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
*/
private static <T> T qualifiedBeanOfType(ConfigurableListableBeanFactory bf, Class<T> beanType, String qualifier) {
Map<String, T> candidateBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, beanType);
T matchingBean = null;
for (String beanName : candidateBeans.keySet()) {
if (isQualifierMatch(qualifier, beanName, bf)) {
if (matchingBean != null) {
throw new NoSuchBeanDefinitionException(qualifier, "No unique " + beanType.getSimpleName() +
" bean found for qualifier '" + qualifier + "'");
}
matchingBean = candidateBeans.get(beanName);
}
}
if (matchingBean != null) {
return matchingBean;
}
else {
throw new NoSuchBeanDefinitionException(qualifier, "No matching " + beanType.getSimpleName() +
" bean found for qualifier '" + qualifier + "' - neither qualifier " + "match nor bean name match!");
}
}
/**
* Check whether the named bean declares a qualifier of the given name.
* @param qualifier the qualifier to match
* @param beanName the name of the candidate bean
* @param bf the {@code BeanFactory} from which to retrieve the named bean
* @return {@code true} if either the bean definition (in the XML case)
* or the bean's factory method (in the {@code @Bean} case) defines a matching
* qualifier value (through {@code <qualifier>} or {@code @Qualifier})
*/
private static boolean isQualifierMatch(String qualifier, String beanName, ConfigurableListableBeanFactory bf) {
if (bf.containsBean(beanName)) {
try {
BeanDefinition bd = bf.getMergedBeanDefinition(beanName);
if (bd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName());
if ((candidate != null && qualifier.equals(candidate.getAttribute(AutowireCandidateQualifier.VALUE_KEY))) ||
qualifier.equals(beanName) || ObjectUtils.containsElement(bf.getAliases(beanName), qualifier)) {
return true;
}
}
if (bd instanceof RootBeanDefinition) {
Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod();
if (factoryMethod != null) {
Qualifier targetAnnotation = factoryMethod.getAnnotation(Qualifier.class);
if (targetAnnotation != null && qualifier.equals(targetAnnotation.value())) {
return true;
}
}
}
}
catch (NoSuchBeanDefinitionException ex) {
// ignore - can't compare qualifiers for a manually registered singleton object
}
}
return false;
}
}
@@ -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,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.
@@ -54,17 +54,22 @@ public class InjectionMetadata {
public InjectionMetadata(Class targetClass, Collection<InjectedElement> elements) {
this.injectedElements = Collections.synchronizedSet(new LinkedHashSet<InjectedElement>());
for (InjectedElement element : elements) {
if (logger.isDebugEnabled()) {
logger.debug("Found injected element on class [" + targetClass.getName() + "]: " + element);
if (!elements.isEmpty()) {
this.injectedElements = Collections.synchronizedSet(new LinkedHashSet<InjectedElement>(elements.size()));
for (InjectedElement element : elements) {
if (logger.isDebugEnabled()) {
logger.debug("Found injected element on class [" + targetClass.getName() + "]: " + element);
}
this.injectedElements.add(element);
}
this.injectedElements.add(element);
}
else {
this.injectedElements = Collections.emptySet();
}
}
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
synchronized(this.injectedElements) {
synchronized (this.injectedElements) {
for (Iterator<InjectedElement> it = this.injectedElements.iterator(); it.hasNext();) {
Member member = it.next().getMember();
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
@@ -170,26 +175,30 @@ public class InjectionMetadata {
* affected property as processed for other processors to ignore it.
*/
protected boolean checkPropertySkipping(PropertyValues pvs) {
if (this.skip == null) {
if (pvs != null) {
synchronized (pvs) {
if (this.skip == null) {
if (this.pd != null) {
if (pvs.contains(this.pd.getName())) {
// Explicit value provided as part of the bean definition.
this.skip = true;
return true;
}
else if (pvs instanceof MutablePropertyValues) {
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
}
}
}
if (this.skip != null) {
return this.skip;
}
if (pvs == null) {
this.skip = false;
return false;
}
synchronized (pvs) {
if (this.skip != null) {
return this.skip;
}
if (this.pd != null) {
if (pvs.contains(this.pd.getName())) {
// Explicit value provided as part of the bean definition.
this.skip = true;
return true;
}
else if (pvs instanceof MutablePropertyValues) {
((MutablePropertyValues) pvs).registerProcessedProperty(this.pd.getName());
}
}
this.skip = false;
return false;
}
return this.skip;
}
/**
@@ -1,61 +1,61 @@
/*
* 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation at the field or method/constructor parameter level
* that indicates a default value expression for the affected argument.
*
* <p>Typically used for expression-driven dependency injection. Also supported
* for dynamic resolution of handler method parameters, e.g. in Spring MVC.
*
* <p>A common use case is to assign default field values using
* "#{systemProperties.myProp}" style expressions.
*
* <p>Note that actual processing of the {@code @Value} annotation is performed
* by a {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} which in turn means that you <em>cannot</em> use
* {@code @Value} within
* {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
* class (which, by default, checks for the presence of this annotation).
*
* @author Juergen Hoeller
* @since 3.0
* @see AutowiredAnnotationBeanPostProcessor
* @see Autowired
* @see org.springframework.beans.factory.config.BeanExpressionResolver
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
/**
* The actual value expression: e.g. "#{systemProperties.myProp}".
*/
String value();
}
/*
* 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation at the field or method/constructor parameter level
* that indicates a default value expression for the affected argument.
*
* <p>Typically used for expression-driven dependency injection. Also supported
* for dynamic resolution of handler method parameters, e.g. in Spring MVC.
*
* <p>A common use case is to assign default field values using
* "#{systemProperties.myProp}" style expressions.
*
* <p>Note that actual processing of the {@code @Value} annotation is performed
* by a {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} which in turn means that you <em>cannot</em> use
* {@code @Value} within
* {@link org.springframework.beans.factory.config.BeanPostProcessor
* BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please
* consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor}
* class (which, by default, checks for the presence of this annotation).
*
* @author Juergen Hoeller
* @since 3.0
* @see AutowiredAnnotationBeanPostProcessor
* @see Autowired
* @see org.springframework.beans.factory.config.BeanExpressionResolver
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
/**
* The actual value expression: e.g. "#{systemProperties.myProp}".
*/
String value();
}
@@ -1,84 +1,84 @@
/*
* Copyright 2002-2009 the original author 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 org.springframework.util.Assert;
/**
* Context object for evaluating an expression within a bean definition.
*
* @author Juergen Hoeller
* @since 3.0
*/
public class BeanExpressionContext {
private final ConfigurableBeanFactory beanFactory;
private final Scope scope;
public BeanExpressionContext(ConfigurableBeanFactory beanFactory, Scope scope) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
this.scope = scope;
}
public final ConfigurableBeanFactory getBeanFactory() {
return this.beanFactory;
}
public final Scope getScope() {
return this.scope;
}
public boolean containsObject(String key) {
return (this.beanFactory.containsBean(key) ||
(this.scope != null && this.scope.resolveContextualObject(key) != null));
}
public Object getObject(String key) {
if (this.beanFactory.containsBean(key)) {
return this.beanFactory.getBean(key);
}
else if (this.scope != null){
return this.scope.resolveContextualObject(key);
}
else {
return null;
}
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof BeanExpressionContext)) {
return false;
}
BeanExpressionContext otherContext = (BeanExpressionContext) other;
return (this.beanFactory == otherContext.beanFactory && this.scope == otherContext.scope);
}
@Override
public int hashCode() {
return this.beanFactory.hashCode();
}
}
/*
* Copyright 2002-2009 the original author 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 org.springframework.util.Assert;
/**
* Context object for evaluating an expression within a bean definition.
*
* @author Juergen Hoeller
* @since 3.0
*/
public class BeanExpressionContext {
private final ConfigurableBeanFactory beanFactory;
private final Scope scope;
public BeanExpressionContext(ConfigurableBeanFactory beanFactory, Scope scope) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
this.scope = scope;
}
public final ConfigurableBeanFactory getBeanFactory() {
return this.beanFactory;
}
public final Scope getScope() {
return this.scope;
}
public boolean containsObject(String key) {
return (this.beanFactory.containsBean(key) ||
(this.scope != null && this.scope.resolveContextualObject(key) != null));
}
public Object getObject(String key) {
if (this.beanFactory.containsBean(key)) {
return this.beanFactory.getBean(key);
}
else if (this.scope != null){
return this.scope.resolveContextualObject(key);
}
else {
return null;
}
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof BeanExpressionContext)) {
return false;
}
BeanExpressionContext otherContext = (BeanExpressionContext) other;
return (this.beanFactory == otherContext.beanFactory && this.scope == otherContext.scope);
}
@Override
public int hashCode() {
return this.beanFactory.hashCode();
}
}
@@ -1,45 +1,45 @@
/*
* Copyright 2002-2008 the original author 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 org.springframework.beans.BeansException;
/**
* Strategy interface for resolving a value through evaluating it
* as an expression, if applicable.
*
* <p>A raw {@link org.springframework.beans.factory.BeanFactory} does not
* contain a default implementation of this strategy. However,
* {@link org.springframework.context.ApplicationContext} implementations
* will provide expression support out of the box.
*
* @author Juergen Hoeller
* @since 3.0
*/
public interface BeanExpressionResolver {
/**
* Evaluate the given value as an expression, if applicable;
* return the value as-is otherwise.
* @param value the value to check
* @param evalContext the evaluation context
* @return the resolved value (potentially the given value as-is)
* @throws BeansException if evaluation failed
*/
Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException;
}
/*
* Copyright 2002-2008 the original author 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 org.springframework.beans.BeansException;
/**
* Strategy interface for resolving a value through evaluating it
* as an expression, if applicable.
*
* <p>A raw {@link org.springframework.beans.factory.BeanFactory} does not
* contain a default implementation of this strategy. However,
* {@link org.springframework.context.ApplicationContext} implementations
* will provide expression support out of the box.
*
* @author Juergen Hoeller
* @since 3.0
*/
public interface BeanExpressionResolver {
/**
* Evaluate the given value as an expression, if applicable;
* return the value as-is otherwise.
* @param value the value to check
* @param evalContext the evaluation context
* @return the resolved value (potentially the given value as-is)
* @throws BeansException if evaluation failed
*/
Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException;
}
@@ -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.
@@ -21,6 +21,7 @@ import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.springframework.core.GenericCollectionTypeResolver;
@@ -56,6 +57,8 @@ public class DependencyDescriptor implements Serializable {
private final boolean eager;
private int nestingLevel = 1;
private transient Annotation[] fieldAnnotations;
@@ -118,6 +121,24 @@ public class DependencyDescriptor implements Serializable {
this.eager = eager;
}
/**
* Copy constructor.
* @param original the original descriptor to create a copy from
*/
public DependencyDescriptor(DependencyDescriptor original) {
this.methodParameter = (original.methodParameter != null ? new MethodParameter(original.methodParameter) : null);
this.field = original.field;
this.declaringClass = original.declaringClass;
this.methodName = original.methodName;
this.parameterTypes = original.parameterTypes;
this.parameterIndex = original.parameterIndex;
this.fieldName = original.fieldName;
this.required = original.required;
this.eager = original.eager;
this.nestingLevel = original.nestingLevel;
this.fieldAnnotations = original.fieldAnnotations;
}
/**
* Return the wrapped MethodParameter, if any.
@@ -153,6 +174,17 @@ public class DependencyDescriptor implements Serializable {
}
/**
* Increase this descriptor's nesting level.
* @see MethodParameter#increaseNestingLevel()
*/
public void increaseNestingLevel() {
this.nestingLevel++;
if (this.methodParameter != null) {
this.methodParameter.increaseNestingLevel();
}
}
/**
* Initialize parameter name discovery for the underlying method parameter, if any.
* <p>This method does not actually try to retrieve the parameter name at
@@ -178,15 +210,30 @@ public class DependencyDescriptor implements Serializable {
* @return the declared type (never <code>null</code>)
*/
public Class<?> getDependencyType() {
return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
}
/**
* Determine the generic type of the wrapped parameter/field.
* @return the generic type (never <code>null</code>)
*/
public Type getGenericDependencyType() {
return (this.field != null ? this.field.getGenericType() : this.methodParameter.getGenericParameterType());
if (this.field != null) {
if (this.nestingLevel > 1) {
Type type = this.field.getGenericType();
if (type instanceof ParameterizedType) {
Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
if (arg instanceof Class) {
return (Class) arg;
}
else if (arg instanceof ParameterizedType) {
arg = ((ParameterizedType) arg).getRawType();
if (arg instanceof Class) {
return (Class) arg;
}
}
}
return Object.class;
}
else {
return this.field.getType();
}
}
else {
return this.methodParameter.getNestedParameterType();
}
}
/**
@@ -195,7 +242,7 @@ public class DependencyDescriptor implements Serializable {
*/
public Class<?> getCollectionType() {
return (this.field != null ?
GenericCollectionTypeResolver.getCollectionFieldType(this.field) :
GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter));
}
@@ -205,7 +252,7 @@ public class DependencyDescriptor implements Serializable {
*/
public Class<?> getMapKeyType() {
return (this.field != null ?
GenericCollectionTypeResolver.getMapKeyFieldType(this.field) :
GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter));
}
@@ -215,7 +262,7 @@ public class DependencyDescriptor implements Serializable {
*/
public Class<?> getMapValueType() {
return (this.field != null ?
GenericCollectionTypeResolver.getMapValueFieldType(this.field) :
GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel) :
GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter));
}
@@ -248,13 +295,18 @@ public class DependencyDescriptor implements Serializable {
if (this.fieldName != null) {
this.field = this.declaringClass.getDeclaredField(this.fieldName);
}
else if (this.methodName != null) {
this.methodParameter = new MethodParameter(
this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
}
else {
this.methodParameter = new MethodParameter(
this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
if (this.methodName != null) {
this.methodParameter = new MethodParameter(
this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
}
else {
this.methodParameter = new MethodParameter(
this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
}
for (int i = 1; i < this.nestingLevel; i++) {
this.methodParameter.increaseNestingLevel();
}
}
}
catch (Throwable ex) {
@@ -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,95 +1,95 @@
/*
* Copyright 2002-2010 the original author 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 javax.inject.Provider;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.Assert;
/**
* A {@link org.springframework.beans.factory.FactoryBean} implementation that
* returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn
* returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
*
* <p>This is basically a JSR-330 compliant variant of Spring's good old
* {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional
* external dependency injection configuration that targets a property or
* constructor argument of type <code>javax.inject.Provider</code>, as an
* alternative to JSR-330's <code>@Inject</code> annotation-driven approach.
*
* @author Juergen Hoeller
* @since 3.0.2
* @see javax.inject.Provider
* @see ObjectFactoryCreatingFactoryBean
*/
public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider> {
private String targetBeanName;
/**
* Set the name of the target bean.
* <p>The target does not <i>have</> to be a non-singleton bean, but realisticially
* 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).
*/
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
super.afterPropertiesSet();
}
@Override
public Class getObjectType() {
return Provider.class;
}
@Override
protected Provider createInstance() {
return new TargetBeanProvider(getBeanFactory(), this.targetBeanName);
}
/**
* Independent inner class - for serialization purposes.
*/
private static class TargetBeanProvider implements Provider, Serializable {
private final BeanFactory beanFactory;
private final String targetBeanName;
public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) {
this.beanFactory = beanFactory;
this.targetBeanName = targetBeanName;
}
public Object get() throws BeansException {
return this.beanFactory.getBean(this.targetBeanName);
}
}
}
/*
* 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.beans.factory.config;
import java.io.Serializable;
import javax.inject.Provider;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.Assert;
/**
* A {@link org.springframework.beans.factory.FactoryBean} implementation that
* returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn
* returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
*
* <p>This is basically a JSR-330 compliant variant of Spring's good old
* {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional
* external dependency injection configuration that targets a property or
* constructor argument of type <code>javax.inject.Provider</code>, as an
* alternative to JSR-330's <code>@Inject</code> annotation-driven approach.
*
* @author Juergen Hoeller
* @since 3.0.2
* @see javax.inject.Provider
* @see ObjectFactoryCreatingFactoryBean
*/
public class ProviderCreatingFactoryBean extends AbstractFactoryBean<Provider> {
private String targetBeanName;
/**
* Set the name of the target bean.
* <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).
*/
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
super.afterPropertiesSet();
}
@Override
public Class getObjectType() {
return Provider.class;
}
@Override
protected Provider createInstance() {
return new TargetBeanProvider(getBeanFactory(), this.targetBeanName);
}
/**
* Independent inner class - for serialization purposes.
*/
private static class TargetBeanProvider implements Provider, Serializable {
private final BeanFactory beanFactory;
private final String targetBeanName;
public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) {
this.beanFactory = beanFactory;
this.targetBeanName = targetBeanName;
}
public Object get() throws BeansException {
return this.beanFactory.getBean(this.targetBeanName);
}
}
}
@@ -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) {
@@ -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.
@@ -672,12 +672,12 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
// Try to obtain the FactoryBean's object type without instantiating it at all.
BeanDefinition fbDef = getBeanDefinition(factoryBeanName);
if (fbDef instanceof AbstractBeanDefinition) {
Class<?> fbClass = ((AbstractBeanDefinition)fbDef).getBeanClass();
Class<?> fbClass = ((AbstractBeanDefinition) fbDef).getBeanClass();
if (ClassUtils.isCglibProxyClass(fbClass)) {
// CGLIB subclass methods hide generic parameters. look at the superclass.
fbClass = fbClass.getSuperclass();
}
// find the given factory method, taking into account that in the case of
// Find the given factory method, taking into account that in the case of
// @Bean methods, there may be parameters present.
ReflectionUtils.doWithMethods(fbClass,
new ReflectionUtils.MethodCallback() {
@@ -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.
@@ -1328,8 +1328,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @param mbd the corresponding bean definition
*/
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class);
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
Class<?> predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
return (predictedType != null && FactoryBean.class.isAssignableFrom(predictedType)) ||
(mbd.hasBeanClass() && FactoryBean.class.isAssignableFrom(mbd.getBeanClass()));
}
/**
@@ -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.
@@ -38,6 +38,7 @@ import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -208,7 +209,7 @@ class BeanDefinitionValueResolver {
*/
protected Object evaluate(TypedStringValue value) {
Object result = this.beanFactory.evaluateBeanDefinitionString(value.getValue(), this.beanDefinition);
if (result != value.getValue()) {
if (!ObjectUtils.nullSafeEquals(result, value.getValue())) {
value.setDynamic();
}
return result;
@@ -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.
@@ -24,8 +24,6 @@ import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
@@ -90,6 +88,7 @@ import org.springframework.util.StringUtils;
* @author Juergen Hoeller
* @author Sam Brannen
* @author Costin Leau
* @author Chris Beams
* @since 16 April 2001
* @see StaticListableBeanFactory
* @see PropertiesBeanDefinitionReader
@@ -98,7 +97,7 @@ import org.springframework.util.StringUtils;
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
private static Class javaxInjectProviderClass = null;
private static Class<?> javaxInjectProviderClass = null;
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
@@ -128,11 +127,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/** Map from dependency type to corresponding autowired value */
private final Map<Class, Object> resolvableDependencies = new HashMap<Class, Object>();
private final Map<Class<?>, Object> resolvableDependencies = new HashMap<Class<?>, Object>();
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
/** Map of singleton bean names keyed by bean class */
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>();
/** Map of non-singleton bean names keyed by bean class */
private final Map<Class<?>, String[]> nonSingletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>();
/** List of bean definition names, in registration order */
private final List<String> beanDefinitionNames = new ArrayList<String>();
@@ -294,11 +299,26 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
public String[] getBeanNamesForType(Class type) {
public String[] getBeanNamesForType(Class<?> type) {
return getBeanNamesForType(type, true, true);
}
public String[] getBeanNamesForType(Class type, boolean includeNonSingletons, boolean allowEagerInit) {
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache = includeNonSingletons ?
this.nonSingletonBeanNamesByType : this.singletonBeanNamesByType;
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(type, includeNonSingletons, allowEagerInit);
cache.put(type, resolvedBeanNames);
return resolvedBeanNames;
}
private String[] doGetBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<String>();
// Check all bean definitions.
@@ -441,7 +461,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
*/
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) {
A ann = null;
Class beanType = getType(beanName);
Class<?> beanType = getType(beanName);
if (beanType != null) {
ann = AnnotationUtils.findAnnotation(beanType, annotationType);
}
@@ -556,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);
}
}
}
}
@@ -630,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 {
@@ -648,9 +669,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
this.beanDefinitionNames.remove(beanName);
this.frozenBeanDefinitionNames = null;
resetBeanDefinition(beanName);
}
resetBeanDefinition(beanName);
}
/**
@@ -665,9 +686,11 @@ 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();
this.nonSingletonBeanNamesByType.clear();
// Reset all bean definitions that have the given bean as parent (recursively).
for (String bdName : this.beanDefinitionNames) {
@@ -723,7 +746,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
if (type.isArray()) {
Class componentType = type.getComponentType();
Class<?> componentType = type.getComponentType();
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType, descriptor);
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
@@ -738,7 +761,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return converter.convertIfNecessary(matchingBeans.values(), type);
}
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class elementType = descriptor.getCollectionType();
Class<?> elementType = descriptor.getCollectionType();
if (elementType == null) {
if (descriptor.isRequired()) {
throw new FatalBeanException("No element type declared for collection [" + type.getName() + "]");
@@ -759,7 +782,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return converter.convertIfNecessary(matchingBeans.values(), type);
}
else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
Class keyType = descriptor.getMapKeyType();
Class<?> keyType = descriptor.getMapKeyType();
if (keyType == null || !String.class.isAssignableFrom(keyType)) {
if (descriptor.isRequired()) {
throw new FatalBeanException("Key type [" + keyType + "] of map [" + type.getName() +
@@ -767,7 +790,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
return null;
}
Class valueType = descriptor.getMapValueType();
Class<?> valueType = descriptor.getMapValueType();
if (valueType == null) {
if (descriptor.isRequired()) {
throw new FatalBeanException("No value type declared for map [" + type.getName() + "]");
@@ -828,12 +851,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* @see #autowireConstructor
*/
protected Map<String, Object> findAutowireCandidates(
String beanName, Class requiredType, DependencyDescriptor descriptor) {
String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
for (Class autowiringType : this.resolvableDependencies.keySet()) {
for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
@@ -918,7 +941,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* Raise a NoSuchBeanDefinitionException for an unresolvable dependency.
*/
private void raiseNoSuchBeanDefinitionException(
Class type, String dependencyDescription, DependencyDescriptor descriptor)
Class<?> type, String dependencyDescription, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException {
throw new NoSuchBeanDefinitionException(type, dependencyDescription,
@@ -967,6 +990,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
* Minimal id reference to the factory.
* Resolved to the actual factory instance on deserialization.
*/
@SuppressWarnings("serial")
private static class SerializedBeanFactoryReference implements Serializable {
private final String id;
@@ -976,7 +1000,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
private Object readResolve() {
Reference ref = serializableFactories.get(this.id);
Reference<?> ref = serializableFactories.get(this.id);
if (ref == null) {
throw new IllegalStateException(
"Cannot deserialize BeanFactory with id " + this.id + ": no factory registered for this id");
@@ -994,33 +1018,21 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/**
* Serializable ObjectFactory for lazy resolution of a dependency.
*/
private class DependencyObjectFactory implements ObjectFactory, Serializable {
@SuppressWarnings("serial")
private class DependencyObjectFactory implements ObjectFactory<Object>, Serializable {
private final DependencyDescriptor descriptor;
private final String beanName;
private final Class type;
public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) {
this.descriptor = descriptor;
this.descriptor = new DependencyDescriptor(descriptor);
this.descriptor.increaseNestingLevel();
this.beanName = beanName;
this.type = determineObjectFactoryType();
}
private Class determineObjectFactoryType() {
Type type = this.descriptor.getGenericDependencyType();
if (type instanceof ParameterizedType) {
Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
if (arg instanceof Class) {
return (Class) arg;
}
}
return Object.class;
}
public Object getObject() throws BeansException {
return doResolveDependency(this.descriptor, this.type, this.beanName, null, null);
return doResolveDependency(this.descriptor, this.descriptor.getDependencyType(), this.beanName, null, null);
}
}
@@ -1028,7 +1040,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/**
* Serializable ObjectFactory for lazy resolution of a dependency.
*/
private class DependencyProvider extends DependencyObjectFactory implements Provider {
@SuppressWarnings("serial")
private class DependencyProvider extends DependencyObjectFactory implements Provider<Object> {
public DependencyProvider(DependencyDescriptor descriptor, String beanName) {
super(descriptor, beanName);
@@ -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.
@@ -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;
@@ -303,7 +303,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
/**
* Callback after singleton creation.
* <p>Default implementation marks the singleton as not in creation anymore.
* <p>The default implementation marks the singleton as not in creation anymore.
* @param beanName the name of the singleton that has been created
* @see #isSingletonCurrentlyInCreation
*/
@@ -316,7 +316,8 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
public final void setCurrentlyInCreation(String beanName, boolean inCreation) {
if (!inCreation) {
this.inCreationCheckExclusions.add(beanName);
} else {
}
else {
this.inCreationCheckExclusions.remove(beanName);
}
}
@@ -333,7 +334,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
/**
* Add the given bean to the list of disposable beans in this registry.
* Disposable beans usually correspond to registered singletons,
* <p>Disposable beans usually correspond to registered singletons,
* matching the bean name but potentially being a different instance
* (for example, a DisposableBean adapter for a singleton that does not
* naturally implement Spring's DisposableBean interface).
@@ -436,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();
@@ -1,45 +1,45 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import org.springframework.util.Assert;
/**
* Tag collection class used to hold managed array elements, which may
* include runtime bean references (to be resolved into bean objects).
*
* @author Juergen Hoeller
* @since 3.0
*/
public class ManagedArray extends ManagedList<Object> {
/** Resolved element type for runtime creation of the target array */
volatile Class resolvedElementType;
/**
* Create a new managed array placeholder.
* @param elementTypeName the target element type as a class name
* @param size the size of the array
*/
public ManagedArray(String elementTypeName, int size) {
super(size);
Assert.notNull(elementTypeName, "elementTypeName must not be null");
setElementTypeName(elementTypeName);
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import org.springframework.util.Assert;
/**
* Tag collection class used to hold managed array elements, which may
* include runtime bean references (to be resolved into bean objects).
*
* @author Juergen Hoeller
* @since 3.0
*/
public class ManagedArray extends ManagedList<Object> {
/** Resolved element type for runtime creation of the target array */
volatile Class resolvedElementType;
/**
* Create a new managed array placeholder.
* @param elementTypeName the target element type as a class name
* @param size the size of the array
*/
public ManagedArray(String elementTypeName, int size) {
super(size);
Assert.notNull(elementTypeName, "elementTypeName must not be null");
setElementTypeName(elementTypeName);
}
}
@@ -1,35 +1,35 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import java.security.AccessControlContext;
/**
* Provider of the security context of the code running inside the bean factory.
*
* @author Costin Leau
* @since 3.0
*/
public interface SecurityContextProvider {
/**
* Provides a security access control context relevant to a bean factory.
* @return bean factory security control context
*/
AccessControlContext getAccessControlContext();
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import java.security.AccessControlContext;
/**
* Provider of the security context of the code running inside the bean factory.
*
* @author Costin Leau
* @since 3.0
*/
public interface SecurityContextProvider {
/**
* Provides a security access control context relevant to a bean factory.
* @return bean factory security control context
*/
AccessControlContext getAccessControlContext();
}
@@ -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.
@@ -44,6 +44,17 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
private static final ThreadLocal<Method> currentlyInvokedFactoryMethod = new ThreadLocal<Method>();
/**
* Return the factory method currently being invoked or {@code null} if none.
* <p>Allows factory method implementations to determine whether the current
* caller is the container itself as opposed to user code.
*/
public static Method getCurrentlyInvokedFactoryMethod() {
return currentlyInvokedFactoryMethod.get();
}
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (beanDefinition.getMethodOverrides().isEmpty()) {
@@ -147,7 +158,8 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
return factoryMethod.invoke(factoryBean, args);
} finally {
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
@@ -171,12 +183,4 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
}
}
/**
* Return the factory method currently being invoked or {@code null} if none.
* Allows factory method implementations to determine whether the current
* caller is the container itself as opposed to user code.
*/
public static Method getCurrentlyInvokedFactoryMethod() {
return currentlyInvokedFactoryMethod.get();
}
}
@@ -1,58 +1,58 @@
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import java.security.AccessControlContext;
import java.security.AccessController;
/**
* Simple {@link SecurityContextProvider} implementation.
*
* @author Costin Leau
* @since 3.0
*/
public class SimpleSecurityContextProvider implements SecurityContextProvider {
private final AccessControlContext acc;
/**
* Construct a new <code>SimpleSecurityContextProvider</code> instance.
* <p>The security context will be retrieved on each call from the current
* thread.
*/
public SimpleSecurityContextProvider() {
this(null);
}
/**
* Construct a new <code>SimpleSecurityContextProvider</code> instance.
* <p>If the given control context is null, the security context will be
* retrieved on each call from the current thread.
* @param acc access control context (can be <code>null</code>)
* @see AccessController#getContext()
*/
public SimpleSecurityContextProvider(AccessControlContext acc) {
this.acc = acc;
}
public AccessControlContext getAccessControlContext() {
return (this.acc != null ? acc : AccessController.getContext());
}
}
/*
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import java.security.AccessControlContext;
import java.security.AccessController;
/**
* Simple {@link SecurityContextProvider} implementation.
*
* @author Costin Leau
* @since 3.0
*/
public class SimpleSecurityContextProvider implements SecurityContextProvider {
private final AccessControlContext acc;
/**
* Construct a new <code>SimpleSecurityContextProvider</code> instance.
* <p>The security context will be retrieved on each call from the current
* thread.
*/
public SimpleSecurityContextProvider() {
this(null);
}
/**
* Construct a new <code>SimpleSecurityContextProvider</code> instance.
* <p>If the given control context is null, the security context will be
* retrieved on each call from the current thread.
* @param acc access control context (can be <code>null</code>)
* @see AccessController#getContext()
*/
public SimpleSecurityContextProvider(AccessControlContext acc) {
this.acc = acc;
}
public AccessControlContext getAccessControlContext() {
return (this.acc != null ? acc : AccessController.getContext());
}
}
@@ -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.
@@ -826,7 +826,11 @@ public class BeanDefinitionParserDelegate {
// Look for arg-type match elements.
List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT);
for (Element argTypeEle : argTypeEles) {
replaceOverride.addTypeIdentifier(argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE));
String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE);
match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle));
if (StringUtils.hasText(match)) {
replaceOverride.addTypeIdentifier(match);
}
}
replaceOverride.setSource(extractSource(replacedMethodEle));
overrides.addOverride(replaceOverride);
@@ -1,151 +1,151 @@
/*
* Copyright 2010 the original author 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.xml;
import java.util.Collection;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.core.Conventions;
import org.springframework.util.StringUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Simple <code>NamespaceHandler</code> implementation that maps custom
* attributes directly through to bean properties. An important point to note is
* that this <code>NamespaceHandler</code> does not have a corresponding schema
* since there is no way to know in advance all possible attribute names.
*
* <p>
* An example of the usage of this <code>NamespaceHandler</code> is shown below:
*
* <pre class="code">
* &lt;bean id=&quot;author&quot; class=&quot;..TestBean&quot; c:name=&quot;Enescu&quot; c:work-ref=&quot;compositions&quot;/&gt;
* </pre>
*
* Here the '<code>c:name</code>' corresponds directly to the '<code>name</code>
* ' argument declared on the constructor of class '<code>TestBean</code>'. The
* '<code>c:work-ref</code>' attributes corresponds to the '<code>work</code>'
* argument and, rather than being the concrete value, it contains the name of
* the bean that will be considered as a parameter.
*
* <b>Note</b>: This implementation supports only named parameters - there is no
* support for indexes or types. Further more, the names are used as hints by
* the container which, by default, does type introspection.
*
* @see SimplePropertyNamespaceHandler
* @author Costin Leau
*/
public class SimpleConstructorNamespaceHandler implements NamespaceHandler {
private static final String REF_SUFFIX = "-ref";
private static final String DELIMITER_PREFIX = "_";
public void init() {
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
parserContext.getReaderContext().error(
"Class [" + getClass().getName() + "] does not support custom elements.", element);
return null;
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
String argValue = StringUtils.trimWhitespace(attr.getValue());
ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
boolean ref = false;
// handle -ref arguments
if (argName.endsWith(REF_SUFFIX)) {
ref = true;
argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
}
ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));
// handle "escaped"/"_" arguments
if (argName.startsWith(DELIMITER_PREFIX)) {
String arg = argName.substring(1).trim();
// fast default check
if (!StringUtils.hasText(arg)) {
cvs.addGenericArgumentValue(valueHolder);
}
// assume an index otherwise
else {
int index = -1;
try {
index = Integer.parseInt(arg);
} catch (NumberFormatException ex) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' specifies an invalid integer", attr);
}
if (index < 0) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' specifies a negative index", attr);
}
if (cvs.hasIndexedArgumentValue(index)){
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' with index "+ index+" already defined using <constructor-arg>." +
" Only one approach may be used per argument.", attr);
}
cvs.addIndexedArgumentValue(index, valueHolder);
}
}
// no escaping -> ctr name
else {
String name = Conventions.attributeNameToPropertyName(argName);
if (containsArgWithName(name, cvs)){
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' already defined using <constructor-arg>." +
" Only one approach may be used per argument.", attr);
}
valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
cvs.addGenericArgumentValue(valueHolder);
}
}
return definition;
}
private boolean containsArgWithName(String name, ConstructorArgumentValues cvs) {
if (!checkName(name, cvs.getGenericArgumentValues())) {
return checkName(name, cvs.getIndexedArgumentValues().values());
}
return true;
}
private boolean checkName(String name, Collection<ValueHolder> values) {
for (ValueHolder holder : values) {
if (name.equals(holder.getName())) {
return true;
}
}
return false;
}
/*
* Copyright 2010 the original author 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.xml;
import java.util.Collection;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.core.Conventions;
import org.springframework.util.StringUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Simple <code>NamespaceHandler</code> implementation that maps custom
* attributes directly through to bean properties. An important point to note is
* that this <code>NamespaceHandler</code> does not have a corresponding schema
* since there is no way to know in advance all possible attribute names.
*
* <p>
* An example of the usage of this <code>NamespaceHandler</code> is shown below:
*
* <pre class="code">
* &lt;bean id=&quot;author&quot; class=&quot;..TestBean&quot; c:name=&quot;Enescu&quot; c:work-ref=&quot;compositions&quot;/&gt;
* </pre>
*
* Here the '<code>c:name</code>' corresponds directly to the '<code>name</code>
* ' argument declared on the constructor of class '<code>TestBean</code>'. The
* '<code>c:work-ref</code>' attributes corresponds to the '<code>work</code>'
* argument and, rather than being the concrete value, it contains the name of
* the bean that will be considered as a parameter.
*
* <b>Note</b>: This implementation supports only named parameters - there is no
* support for indexes or types. Further more, the names are used as hints by
* the container which, by default, does type introspection.
*
* @see SimplePropertyNamespaceHandler
* @author Costin Leau
*/
public class SimpleConstructorNamespaceHandler implements NamespaceHandler {
private static final String REF_SUFFIX = "-ref";
private static final String DELIMITER_PREFIX = "_";
public void init() {
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
parserContext.getReaderContext().error(
"Class [" + getClass().getName() + "] does not support custom elements.", element);
return null;
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
String argValue = StringUtils.trimWhitespace(attr.getValue());
ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
boolean ref = false;
// handle -ref arguments
if (argName.endsWith(REF_SUFFIX)) {
ref = true;
argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
}
ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));
// handle "escaped"/"_" arguments
if (argName.startsWith(DELIMITER_PREFIX)) {
String arg = argName.substring(1).trim();
// fast default check
if (!StringUtils.hasText(arg)) {
cvs.addGenericArgumentValue(valueHolder);
}
// assume an index otherwise
else {
int index = -1;
try {
index = Integer.parseInt(arg);
} catch (NumberFormatException ex) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' specifies an invalid integer", attr);
}
if (index < 0) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' specifies a negative index", attr);
}
if (cvs.hasIndexedArgumentValue(index)){
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' with index "+ index+" already defined using <constructor-arg>." +
" Only one approach may be used per argument.", attr);
}
cvs.addIndexedArgumentValue(index, valueHolder);
}
}
// no escaping -> ctr name
else {
String name = Conventions.attributeNameToPropertyName(argName);
if (containsArgWithName(name, cvs)){
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' already defined using <constructor-arg>." +
" Only one approach may be used per argument.", attr);
}
valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
cvs.addGenericArgumentValue(valueHolder);
}
}
return definition;
}
private boolean containsArgWithName(String name, ConstructorArgumentValues cvs) {
if (!checkName(name, cvs.getGenericArgumentValues())) {
return checkName(name, cvs.getIndexedArgumentValues().values());
}
return true;
}
private boolean checkName(String name, Collection<ValueHolder> values) {
for (ValueHolder holder : values) {
if (name.equals(holder.getName())) {
return true;
}
}
return false;
}
}
@@ -1,43 +1,43 @@
/*
* 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.propertyeditors;
import java.beans.PropertyEditorSupport;
import java.util.Currency;
/**
* Editor for <code>java.util.Currency</code>, translating currency codes into Currency
* objects. Exposes the currency code as text representation of a Currency object.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.Currency
*/
public class CurrencyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(Currency.getInstance(text));
}
@Override
public String getAsText() {
Currency value = (Currency) getValue();
return (value != null ? value.getCurrencyCode() : "");
}
}
/*
* 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.propertyeditors;
import java.beans.PropertyEditorSupport;
import java.util.Currency;
/**
* Editor for <code>java.util.Currency</code>, translating currency codes into Currency
* objects. Exposes the currency code as text representation of a Currency object.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.Currency
*/
public class CurrencyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(Currency.getInstance(text));
}
@Override
public String getAsText() {
Currency value = (Currency) getValue();
return (value != null ? value.getCurrencyCode() : "");
}
}
@@ -1,46 +1,46 @@
/*
* Copyright 2002-2009 the original author 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.propertyeditors;
import java.beans.PropertyEditorSupport;
import java.util.TimeZone;
/**
* Editor for <code>java.util.TimeZone</code>, translating timezone IDs into
* TimeZone objects. Does not expose a text representation for TimeZone objects.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.TimeZone
*/
public class TimeZoneEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(TimeZone.getTimeZone(text));
}
/**
* This implementation returns <code>null</code> to indicate that
* there is no appropriate text representation.
*/
@Override
public String getAsText() {
return null;
}
}
/*
* Copyright 2002-2009 the original author 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.propertyeditors;
import java.beans.PropertyEditorSupport;
import java.util.TimeZone;
/**
* Editor for <code>java.util.TimeZone</code>, translating timezone IDs into
* TimeZone objects. Does not expose a text representation for TimeZone objects.
*
* @author Juergen Hoeller
* @since 3.0
* @see java.util.TimeZone
*/
public class TimeZoneEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
setValue(TimeZone.getTimeZone(text));
}
/**
* This implementation returns <code>null</code> to indicate that
* there is no appropriate text representation.
*/
@Override
public String getAsText() {
return null;
}
}

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