Compare commits

...

131 Commits

Author SHA1 Message Date
Spring Buildmaster c734ee12b3 Release version 4.1.6.RELEASE 2015-03-25 09:20:27 -07:00
Juergen Hoeller 97f779674f Polishing 2015-03-25 15:28:30 +01:00
Stephane Nicoll 5f6ae13002 Only require an exception CacheResolver if necessary
Previously, a cache infrastructure with only a CacheResolver would have
worked fine until the JSR-107 API is added to the classpath. When this is
the case, the JCache support kicks in and an exception cache resolver is
all of the sudden required.

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

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

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

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

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

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

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

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

This case only happened for form POSTs requests.

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

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

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

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

In addition, this commit polishes FormattingConversionServiceTests and
MvcNamespaceTests.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 - Simplified tests in InlinedPropertiesTestPropertySourceTests.

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

This commit addresses this issue by making such utilities public.

 - TestPropertySourceUtils is now a public class.

 - Various utility methods in TestPropertySourceUtils have been made
   public.

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

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

 - All public methods in TestPropertySourceUtils are now fully
   documented.

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

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

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

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

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

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

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

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

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

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

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

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

This covers rfc7230 Section 3.3.3.

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

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

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

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

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

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

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

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

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

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

This syntax is allowed by RFC 3986.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Issue: SPR-12577
2014-12-31 16:01:56 +01:00
Juergen Hoeller 8c700b19da Polishing 2014-12-30 21:04:28 +01:00
Juergen Hoeller 9542313710 Polishing 2014-12-30 15:29:48 +01:00
Juergen Hoeller dcb821edb5 Polishing
(cherry picked from commit 730bd02)
2014-12-30 15:07:19 +01:00
Stephane Nicoll daa4adf2ed Next Development Version 2014-12-30 14:29:42 +01:00
284 changed files with 6084 additions and 3538 deletions
+31 -29
View File
@@ -27,34 +27,34 @@ configure(allprojects) { project ->
group = "org.springframework"
version = qualifyVersionIfNecessary(version)
ext.aspectjVersion = "1.8.4"
ext.aspectjVersion = "1.8.5"
ext.eclipseLinkVersion = "2.4.2"
ext.ehcacheVersion = "2.9.0"
ext.ehcacheJCacheVersion = "1.0.0"
ext.groovyVersion = "2.3.9"
ext.ehcacheVersion = "2.9.1"
ext.ehcacheJCacheVersion = "1.0.1"
ext.groovyVersion = "2.3.11"
ext.gsonVersion = "2.3.1"
ext.hibernate3Version = "3.6.10.Final"
ext.hibernate4Version = "4.3.7.Final"
ext.hibernate4Version = "4.3.8.Final"
ext.hibVal4Version = "4.3.2.Final"
ext.hibVal5Version = "5.1.3.Final"
ext.hsqldbVersion = "2.3.2"
ext.jackson2Version = "2.4.4"
ext.jasperReportsVersion = "6.0.0"
ext.jettyVersion = "9.2.6.v20141205"
ext.jodaVersion = "2.6"
ext.jackson2Version = "2.4.5"
ext.jasperReportsVersion = "6.0.3"
ext.jettyVersion = "9.2.10.v20150310"
ext.jodaVersion = "2.7"
ext.junitVersion = "4.12"
ext.nettyVersion = "4.0.24.Final"
ext.nettyVersion = "4.0.26.Final"
ext.openJpaVersion = "2.2.2" // 2.3.0 not Java 8 compatible (based on ASM 4)
ext.protobufVersion = "2.6.1"
ext.reactorVersion = "1.1.5.RELEASE"
ext.slf4jVersion = "1.7.9"
ext.snakeYamlVersion = "1.14"
ext.slf4jVersion = "1.7.10"
ext.snakeYamlVersion = "1.15"
ext.snifferVersion = "1.11"
ext.tiles2Version = "2.2.2"
ext.tiles3Version = "3.0.5"
ext.tomcatVersion = "8.0.15"
ext.tomcatVersion = "8.0.20"
ext.tyrusVersion = "1.3.5" // constrained by WebLogic 12.1.3 support
ext.undertowVersion = "1.1.1.Final"
ext.undertowVersion = "1.1.3.Final"
ext.woodstoxVersion = "4.4.1"
ext.xstreamVersion = "1.4.7"
@@ -143,7 +143,6 @@ configure(allprojects) { project ->
inputs.dir sourceSets.main.output.classesDir
inputs.dir copyJavaApiSignature.to
outputs.upToDateWhen { true }
doLast {
ant.taskdef(
@@ -334,7 +333,7 @@ project("spring-core") {
optional("net.sf.jopt-simple:jopt-simple:4.8")
optional("log4j:log4j:1.2.17")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("org.codehaus.woodstox:woodstox-core-asl:${woodstoxVersion}") {
exclude group: "stax", module: "stax-api"
}
@@ -405,7 +404,7 @@ project("spring-aop") {
compile("aopalliance:aopalliance:1.0")
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("commons-pool:commons-pool:1.6")
optional("com.jamonapi:jamon:2.79")
optional("com.jamonapi:jamon:2.81")
}
}
@@ -460,7 +459,7 @@ project("spring-context") {
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("org.beanshell:bsh:2.0b4")
optional("org.jruby:jruby:1.7.17")
optional("org.jruby:jruby:1.7.19")
testCompile("javax.inject:javax.inject-tck:1")
testCompile("commons-dbcp:commons-dbcp:1.4")
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
@@ -552,9 +551,9 @@ project("spring-oxm") {
exclude group: 'xpp3', module: 'xpp3_min'
exclude group: 'xmlpull', module: 'xmlpull'
}
optional("org.jibx:jibx-run:1.2.5")
optional("org.jibx:jibx-run:1.2.6")
testCompile(project(":spring-context"))
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("xpp3:xpp3:1.1.4c")
testCompile("org.codehaus.jettison:jettison:1.3.7") {
exclude group: 'stax', module: 'stax-api'
@@ -595,7 +594,7 @@ project("spring-jdbc") {
optional("javax.transaction:javax.transaction-api:1.2")
optional("com.mchange:c3p0:0.9.2.1")
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
optional("com.h2database:h2:1.4.182")
optional("com.h2database:h2:1.4.186")
optional("org.apache.derby:derby:10.11.1.1")
optional("org.apache.derby:derbyclient:10.11.1.1")
}
@@ -617,7 +616,7 @@ project("spring-context-support") {
optional("org.quartz-scheduler:quartz:2.2.1")
optional("org.codehaus.fabric3.api:commonj:1.1.0")
optional("org.apache.velocity:velocity:1.7")
optional("org.freemarker:freemarker:2.3.21")
optional("org.freemarker:freemarker:2.3.22")
optional("com.lowagie:itext:2.1.7")
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
exclude group: "com.fasterxml.jackson.core", module: "jackson-annotations"
@@ -625,9 +624,10 @@ project("spring-context-support") {
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
exclude group: "org.olap4j", module: "olap4j"
exclude group: "xml-apis", module: "xml-apis"
exclude group: "org.springframework", module: "spring-context"
}
testCompile(project(":spring-context"))
testCompile("org.apache.poi:poi:3.10.1")
testCompile("org.apache.poi:poi:3.11")
testCompile("commons-beanutils:commons-beanutils:1.8.0") // for Velocity/JasperReports
testCompile("commons-digester:commons-digester:1.8.1") // for Velocity/JasperReports
testCompile("org.hsqldb:hsqldb:${hsqldbVersion}")
@@ -692,11 +692,12 @@ project("spring-web") {
optional("com.google.protobuf:protobuf-java:${protobufVersion}")
optional("javax.mail:javax.mail-api:1.5.2")
testCompile(project(":spring-context-support")) // for JafMediaTypeFactory
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
testCompile("org.apache.taglibs:taglibs-standard-jstlel:1.2.1") {
exclude group: "org.apache.taglibs", module: "taglibs-standard-spec"
}
testCompile("com.fasterxml.jackson.datatype:jackson-datatype-joda:${jackson2Version}")
testRuntime("com.sun.mail:javax.mail:1.5.2")
}
@@ -826,10 +827,10 @@ project("spring-webmvc") {
optional("javax.servlet.jsp:javax.servlet.jsp-api:2.2.1")
optional("javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1")
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
optional("org.apache.poi:poi:3.10.1")
optional("org.apache.poi:poi:3.11")
optional("org.apache.velocity:velocity:1.7")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.20")
optional("org.freemarker:freemarker:2.3.22")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("com.lowagie:itext:2.1.7")
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion") {
@@ -838,6 +839,7 @@ project("spring-webmvc") {
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
exclude group: "org.olap4j", module: "olap4j"
exclude group: "xml-apis", module: "xml-apis"
exclude group: "org.springframework", module: "spring-context"
}
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:${jackson2Version}")
@@ -862,7 +864,7 @@ project("spring-webmvc") {
}
testCompile(project(":spring-aop"))
testCompile("rhino:js:1.7R1")
testCompile("xmlunit:xmlunit:1.5")
testCompile("xmlunit:xmlunit:1.6")
testCompile("dom4j:dom4j:1.6.1") {
exclude group: "xml-apis", module: "xml-apis"
}
@@ -967,9 +969,9 @@ project("spring-test") {
optional("org.aspectj:aspectjweaver:${aspectjVersion}")
optional("org.codehaus.groovy:groovy-all:${groovyVersion}")
optional("org.hamcrest:hamcrest-core:1.3")
optional("com.jayway.jsonpath:json-path:1.1.0")
optional("com.jayway.jsonpath:json-path:1.2.0")
optional("org.skyscreamer:jsonassert:1.2.3")
optional("xmlunit:xmlunit:1.5")
optional("xmlunit:xmlunit:1.6")
testCompile(project(":spring-context-support"))
testCompile(project(":spring-oxm"))
testCompile("javax.mail:javax.mail-api:1.5.2")
+1 -1
View File
@@ -1 +1 @@
version=4.1.4.BUILD-SNAPSHOT
version=4.1.6.RELEASE
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -165,7 +165,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @param params the parameters used to invoke the method
*/
protected void handleError(Throwable ex, Method method, Object... params) throws Exception {
if (method.getReturnType().isAssignableFrom(Future.class)) {
if (Future.class.isAssignableFrom(method.getReturnType())) {
ReflectionUtils.rethrowException(ex);
}
else {
@@ -78,7 +78,7 @@ public class CommonsPoolTargetSource extends AbstractPoolingTargetSource impleme
private byte whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
/**
* The Jakarta Commons {@code ObjectPool} used to pool target objects
* The Apache Commons {@code ObjectPool} used to pool target objects
*/
private ObjectPool pool;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,50 +32,55 @@ import static org.mockito.BDDMockito.*;
*/
public class JamonPerformanceMonitorInterceptorTests {
private JamonPerformanceMonitorInterceptor interceptor = new JamonPerformanceMonitorInterceptor();
private final JamonPerformanceMonitorInterceptor interceptor = new JamonPerformanceMonitorInterceptor();
private MethodInvocation mi = mock(MethodInvocation.class);
private final MethodInvocation mi = mock(MethodInvocation.class);
private Log log = mock(Log.class);
private final Log log = mock(Log.class);
@Before
public void setUp() {
MonitorFactory.reset();
}
@Before
public void setUp() {
MonitorFactory.reset();
}
@After
public void tearDown() {
MonitorFactory.reset();
}
@After
public void tearDown() {
MonitorFactory.reset();
}
@Test
public void testInvokeUnderTraceWithNormalProcessing() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
@Test
public void testInvokeUnderTraceWithNormalProcessing() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
interceptor.invokeUnderTrace(mi, log);
interceptor.invokeUnderTrace(mi, log);
assertEquals("jamon must track the method being invoked", 1, MonitorFactory.getNumRows());
assertTrue("The jamon report must contain the toString method that was invoked", MonitorFactory.getReport().contains("toString"));
}
assertTrue("jamon must track the method being invoked", MonitorFactory.getNumRows() > 0);
assertTrue("The jamon report must contain the toString method that was invoked",
MonitorFactory.getReport().contains("toString"));
}
@Test
public void testInvokeUnderTraceWithExceptionTracking() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
given(mi.proceed()).willThrow(new IllegalArgumentException());
@Test
public void testInvokeUnderTraceWithExceptionTracking() throws Throwable {
given(mi.getMethod()).willReturn(String.class.getMethod("toString"));
given(mi.proceed()).willThrow(new IllegalArgumentException());
try {
interceptor.invokeUnderTrace(mi, log);
fail("Must have propagated the IllegalArgumentException");
}
try {
interceptor.invokeUnderTrace(mi, log);
fail("Must have propagated the IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
}
}
assertEquals("Monitors must exist for the method invocation and 2 exceptions", 3, MonitorFactory.getNumRows());
assertTrue("The jamon report must contain the toString method that was invoked", MonitorFactory.getReport().contains("toString"));
assertTrue("The jamon report must contain the generic exception: " + MonitorFactory.EXCEPTIONS_LABEL, MonitorFactory.getReport().contains(MonitorFactory.EXCEPTIONS_LABEL));
assertTrue("The jamon report must contain the specific exception: IllegalArgumentException'", MonitorFactory.getReport().contains("IllegalArgumentException"));
}
assertEquals("Monitors must exist for the method invocation and 2 exceptions",
3, MonitorFactory.getNumRows());
assertTrue("The jamon report must contain the toString method that was invoked",
MonitorFactory.getReport().contains("toString"));
assertTrue("The jamon report must contain the generic exception: " + MonitorFactory.EXCEPTIONS_LABEL,
MonitorFactory.getReport().contains(MonitorFactory.EXCEPTIONS_LABEL));
assertTrue("The jamon report must contain the specific exception: IllegalArgumentException'",
MonitorFactory.getReport().contains("IllegalArgumentException"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,9 +28,9 @@ import org.springframework.context.annotation.Role;
* annotated with @{@link org.springframework.beans.factory.annotation.Configurable
* Configurable}.
*
* <p>This configuration class is automatically imported when using the @{@link
* EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured} Javadoc for
* complete usage details.
* <p>This configuration class is automatically imported when using the
* @{@link EnableSpringConfigured} annotation. See {@code @EnableSpringConfigured}'s
* javadoc for complete usage details.
*
* @author Chris Beams
* @since 3.1
@@ -42,9 +42,10 @@ public class SpringConfiguredConfiguration {
public static final String BEAN_CONFIGURER_ASPECT_BEAN_NAME =
"org.springframework.context.config.internalBeanConfigurerAspect";
@Bean(name=BEAN_CONFIGURER_ASPECT_BEAN_NAME)
@Bean(name = BEAN_CONFIGURER_ASPECT_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AnnotationBeanConfigurerAspect beanConfigurerAspect() {
return AnnotationBeanConfigurerAspect.aspectOf();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ import groovy.lang.GroovyObjectSupport;
import groovy.lang.GroovyShell;
import groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.InvokerHelper;
@@ -58,8 +59,17 @@ import org.springframework.util.StringUtils;
/**
* A Groovy-based reader for Spring bean definitions: like a Groovy builder,
* but more of a DSL for Spring configuration. Allows syntax like:
* but more of a DSL for Spring configuration.
*
* <p>This bean definition reader also understands XML bean definition files,
* allowing for seamless mixing and matching with Groovy bean definition files.
*
* <p>Typically applied to a
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
* or a {@link org.springframework.context.support.GenericApplicationContext},
* but can be used against any {@link BeanDefinitionRegistry} implementation.
*
* <h3>Example Syntax</h3>
* <pre class="code">
* import org.hibernate.SessionFactory
* import org.apache.commons.dbcp.BasicDataSource
@@ -84,8 +94,9 @@ import org.springframework.util.StringUtils;
* }</pre>
*
* <p>You can also load resources containing beans defined in a Groovy script using
* either the {@link #loadBeanDefinitions(org.springframework.core.io.Resource...)}
* or {@link #loadBeanDefinitions(String...)} method, with a script looking as follows:
* either the {@link #loadBeanDefinitions(Resource...)} or
* {@link #loadBeanDefinitions(String...)} method, with a script looking similar to
* the following.
*
* <pre class="code">
* import org.hibernate.SessionFactory
@@ -109,17 +120,10 @@ import org.springframework.util.StringUtils;
* }
* }</pre>
*
* <p><b>This bean definition reader also understands XML bean definition files,
* allowing for seamless mixing and matching with Groovy bean definition files.</b>
*
* <p>Typically applied to a
* {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
* or a {@link org.springframework.context.support.GenericApplicationContext},
* but can be used against any {@link BeanDefinitionRegistry} implementation.
*
* @author Jeff Brown
* @author Graeme Rocher
* @author Juergen Hoeller
* @author Sam Brannen
* @since 4.0
* @see BeanDefinitionRegistry
* @see org.springframework.beans.factory.support.DefaultListableBeanFactory
@@ -128,7 +132,21 @@ import org.springframework.util.StringUtils;
*/
public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader implements GroovyObject {
private final XmlBeanDefinitionReader xmlBeanDefinitionReader;
/**
* Standard {@code XmlBeanDefinitionReader} created with default
* settings for loading bean definitions from XML files.
*/
private final XmlBeanDefinitionReader standardXmlBeanDefinitionReader;
/**
* Groovy DSL {@code XmlBeanDefinitionReader} for loading bean definitions
* via the Groovy DSL, typically configured with XML validation disabled.
*/
private final XmlBeanDefinitionReader groovyDslXmlBeanDefinitionReader;
private final Map<String, String> namespaces = new HashMap<String, String>();
private final Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
private MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(getClass());
@@ -136,31 +154,28 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
private GroovyBeanDefinitionWrapper currentBeanDefinition;
private final Map <String, String> namespaces = new HashMap<String, String>();
private final Map<String, DeferredProperty> deferredProperties = new HashMap<String, DeferredProperty>();
/**
* Create new GroovyBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
* Create a new {@code GroovyBeanDefinitionReader} for the given {@link BeanDefinitionRegistry}.
* @param registry the {@code BeanDefinitionRegistry} to load bean definitions into
*/
public GroovyBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
this.xmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
this.xmlBeanDefinitionReader.setValidating(false);
this.standardXmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
this.groovyDslXmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
this.groovyDslXmlBeanDefinitionReader.setValidating(false);
}
/**
* Create new GroovyBeanDefinitionReader based on the given XmlBeanDefinitionReader,
* using the same registry and delegating XML loading to it.
* @param xmlBeanDefinitionReader the XmlBeanDefinitionReader to derive the registry
* Create a new {@code GroovyBeanDefinitionReader} based on the given {@link XmlBeanDefinitionReader},
* using its {@code BeanDefinitionRegistry} and delegating Groovy DSL loading to it.
* @param xmlBeanDefinitionReader the {@code XmlBeanDefinitionReader} to derive the registry
* from and to delegate XML loading to
*/
public GroovyBeanDefinitionReader(XmlBeanDefinitionReader xmlBeanDefinitionReader) {
super(xmlBeanDefinitionReader.getRegistry());
this.xmlBeanDefinitionReader = xmlBeanDefinitionReader;
this.standardXmlBeanDefinitionReader = new XmlBeanDefinitionReader(xmlBeanDefinitionReader.getRegistry());
this.groovyDslXmlBeanDefinitionReader = xmlBeanDefinitionReader;
}
@@ -174,7 +189,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Set the binding, i.e. the Groovy variables available in the scope
* of a GroovyBeanDefinitionReader closure.
* of a {@code GroovyBeanDefinitionReader} closure.
*/
public void setBinding(Binding binding) {
this.binding = binding;
@@ -192,9 +207,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Load bean definitions from the specified Groovy script or XML file.
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
* <p>Note that {@code ".xml"} files will be parsed as XML content; all other kinds
* of resources will be parsed as Groovy scripts.
* @param resource the resource descriptor for the Groovy script
* @param resource the resource descriptor for the Groovy script or XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
@@ -204,18 +219,18 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Load bean definitions from the specified Groovy script or XML file.
* <p>Note that ".xml" files will be parsed as XML content; all other kinds
* <p>Note that {@code ".xml"} files will be parsed as XML content; all other kinds
* of resources will be parsed as Groovy scripts.
* @param encodedResource the resource descriptor for the Groovy script,
* allowing to specify an encoding to use for parsing the file
* @param encodedResource the resource descriptor for the Groovy script or XML file,
* allowing specification of an encoding to use for parsing the file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
// Check for XML files and redirect them to the XmlBeanDefinitionReader
// Check for XML files and redirect them to the "standard" XmlBeanDefinitionReader
String filename = encodedResource.getResource().getFilename();
if (StringUtils.endsWithIgnoreCase(filename, ".xml")) {
return this.xmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
return this.standardXmlBeanDefinitionReader.loadBeanDefinitions(encodedResource);
}
Closure beans = new Closure(this) {
@@ -255,14 +270,14 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* Defines a set of beans for the given block or closure.
* @param closure the block or closure
* @return this GroovyBeanDefinitionReader instance
* @return this {@code GroovyBeanDefinitionReader} instance
*/
public GroovyBeanDefinitionReader beans(Closure closure) {
return invokeBeanDefiningClosure(closure);
}
/**
* Defines an inner bean definition.
* Define an inner bean definition.
* @param type the bean type
* @return the bean definition
*/
@@ -307,7 +322,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* Define a Spring namespace definition to use.
* Define a Spring XML namespace definition to use.
* @param definition the namespace definition
*/
public void xmlns(Map<String, String> definition) {
@@ -318,7 +333,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
if (uri == null) {
throw new IllegalArgumentException("Namespace definition must supply a non-null URI");
}
NamespaceHandler namespaceHandler = this.xmlBeanDefinitionReader.getNamespaceHandlerResolver().resolve(uri);
NamespaceHandler namespaceHandler = this.groovyDslXmlBeanDefinitionReader.getNamespaceHandlerResolver().resolve(
uri);
if (namespaceHandler == null) {
throw new BeanDefinitionParsingException(new Problem("No namespace handler found for URI: " + uri,
new Location(new DescriptiveResource(("Groovy")))));
@@ -419,7 +435,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* When a method argument is only a closure it is a set of bean definitions.
* @param callable the closure argument
* @return this GroovyBeanDefinitionReader instance
* @return this {@code GroovyBeanDefinitionReader} instance
*/
protected GroovyBeanDefinitionReader invokeBeanDefiningClosure(Closure callable) {
callable.setDelegate(this);
@@ -534,8 +550,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* Checks whether there are any {@link RuntimeBeanReference}s inside the Map
* and converts it to a ManagedMap if necessary.
* Checks whether there are any {@link RuntimeBeanReference}s inside the {@link Map}
* and converts it to a {@link ManagedMap} if necessary.
* @param map the original Map
* @return either the original map or a managed copy of it
*/
@@ -556,8 +572,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* Checks whether there are any {@link RuntimeBeanReference}s inside the List
* and converts it to a ManagedList if necessary.
* Checks whether there are any {@link RuntimeBeanReference}s inside the {@link List}
* and converts it to a {@link ManagedList} if necessary.
* @param list the original List
* @return either the original list or a managed copy of it
*/
@@ -578,7 +594,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
/**
* This method overrides property setting in the scope of the GroovyBeanDefinitionReader
* This method overrides property setting in the scope of the {@code GroovyBeanDefinitionReader}
* to set properties on the current bean definition.
*/
public void setProperty(String name, Object value) {
@@ -619,12 +635,12 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
/**
* This method overrides property retrieval in the scope of the
* GroovyBeanDefinitionReader to either:
* {@code GroovyBeanDefinitionReader} to either:
* <ul>
* <li>Retrieve a variable from the bean builder's binding if it exists
* <li>Retrieve a RuntimeBeanReference for a specific bean if it exists
* <li>Otherwise just delegate to MetaClass.getProperty which will resolve
* properties from the GroovyBeanDefinitionReader itself
* properties from the {@code GroovyBeanDefinitionReader} itself
* </ul>
*/
public Object getProperty(String name) {
@@ -670,7 +686,8 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
}
private GroovyDynamicElementReader createDynamicElementReader(String namespace) {
XmlReaderContext readerContext = this.xmlBeanDefinitionReader.createReaderContext(new DescriptiveResource("Groovy"));
XmlReaderContext readerContext = this.groovyDslXmlBeanDefinitionReader.createReaderContext(new DescriptiveResource(
"Groovy"));
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
boolean decorating = (this.currentBeanDefinition != null);
if (!decorating) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,6 +78,7 @@ import org.springframework.util.StringUtils;
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rob Harrop
* @author Stephane Nicoll
* @since 15 April 2001
* @see #registerCustomEditor
* @see #setPropertyValues
@@ -978,6 +979,14 @@ public class BeanWrapperImpl extends AbstractPropertyAccessor implements BeanWra
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, TypeDescriptor.nested(property(pd), tokens.keys.length));
int length = Array.getLength(propValue);
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(actualName, newArray);
propValue = getPropertyValue(actualName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -114,6 +114,7 @@ public interface BeanFactory {
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* Return an instance, which may be shared or independent, of the specified bean.
* <p>This method allows a Spring BeanFactory to be used as a replacement for the
@@ -202,6 +203,7 @@ public interface BeanFactory {
*/
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
/**
* Does this bean factory contain a bean definition or externally registered singleton
* instance with the given name?
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
package org.springframework.beans.factory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -219,8 +219,7 @@ public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport
throws BeansException {
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
this.doProcessProperties(beanFactoryToProcess, valueResolver);
doProcessProperties(beanFactoryToProcess, valueResolver);
}
/**
@@ -130,9 +130,10 @@ public abstract class YamlProcessor {
* Properties. Depending on the {@link #setResolutionMethod(ResolutionMethod)} not all
* of the documents will be parsed.
* @param callback a callback to delegate to once matching documents are found
* @see #createYaml()
*/
protected void process(MatchCallback callback) {
Yaml yaml = new Yaml(new StrictMapAppenderConstructor());
Yaml yaml = createYaml();
for (Resource resource : this.resources) {
boolean found = process(callback, yaml, resource);
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
@@ -141,6 +142,13 @@ public abstract class YamlProcessor {
}
}
/**
* Create the {@link Yaml} instance to use.
*/
protected Yaml createYaml() {
return new Yaml(new StrictMapAppenderConstructor());
}
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
int count = 0;
try {
@@ -331,7 +339,7 @@ public abstract class YamlProcessor {
/**
* Status returned from {@link DocumentMatcher#matches(java.util.Properties)}
*/
public static enum MatchStatus {
public enum MatchStatus {
/**
* A match was found.
@@ -360,7 +368,7 @@ public abstract class YamlProcessor {
/**
* Method to use for resolving resources.
*/
public static enum ResolutionMethod {
public enum ResolutionMethod {
/**
* Replace values from earlier in the list.
@@ -382,7 +390,7 @@ public abstract class YamlProcessor {
/**
* A specialized {@link Constructor} that checks for duplicate keys.
*/
private static class StrictMapAppenderConstructor extends Constructor {
protected static class StrictMapAppenderConstructor extends Constructor {
public StrictMapAppenderConstructor() {
super();
@@ -897,6 +897,14 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
instance = bw.getWrappedInstance();
}
}
catch (BeanCreationException ex) {
// Can only happen when getting a FactoryBean.
if (logger.isDebugEnabled()) {
logger.debug("Bean creation exception on non-singleton FactoryBean type check: " + ex);
}
onSuppressedException(ex);
return null;
}
finally {
// Finished partial creation of this bean.
afterPrototypeCreation(beanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -279,7 +279,7 @@ public class BeanDefinitionBuilder {
*/
public BeanDefinitionBuilder addDependsOn(String beanName) {
if (this.beanDefinition.getDependsOn() == null) {
this.beanDefinition.setDependsOn(new String[] {beanName});
this.beanDefinition.setDependsOn(beanName);
}
else {
String[] added = ObjectUtils.addObjectToArray(this.beanDefinition.getDependsOn(), beanName);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -150,8 +150,8 @@ public class BeanDefinitionReaderUtils {
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -323,7 +323,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
//---------------------------------------------------------------------
// Implementation of ListableBeanFactory interface
// Implementation of remaining BeanFactory methods
//---------------------------------------------------------------------
@Override
@@ -562,17 +562,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
Map<String, Object> results = new LinkedHashMap<String, Object>();
for (String beanName : this.beanDefinitionNames) {
BeanDefinition beanDefinition = getBeanDefinition(beanName);
if (!beanDefinition.isAbstract() && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
}
for (String beanName : this.manualSingletonNames) {
if (!results.containsKey(beanName) && findAnnotationOnBean(beanName, annotationType) != null) {
results.put(beanName, getBean(beanName));
}
String[] beanNames = getBeanNamesForAnnotation(annotationType);
Map<String, Object> results = new LinkedHashMap<String, Object>(beanNames.length);
for (String beanName : beanNames) {
results.put(beanName, getBean(beanName));
}
return results;
}
@@ -811,7 +804,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
@@ -820,7 +813,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
" with a framework-generated bean definition ': replacing [" +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -607,13 +607,13 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
/**
* Expose the singleton mutex to subclasses.
* Exposes the singleton mutex to subclasses and external collaborators.
* <p>Subclasses should synchronize on the given Object if they perform
* any sort of extended singleton creation phase. In particular, subclasses
* should <i>not</i> have their own mutexes involved in singleton creation,
* to avoid the potential for deadlocks in lazy-init situations.
*/
protected final Object getSingletonMutex() {
public final Object getSingletonMutex() {
return this.singletonObjects;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,12 +49,13 @@ import org.springframework.util.StringUtils;
*/
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
/** Constant for the id attribute */
/** Constant for the "id" attribute */
public static final String ID_ATTRIBUTE = "id";
/** Constant for the name attribute */
/** Constant for the "name" attribute */
public static final String NAME_ATTRIBUTE = "name";
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
@@ -66,10 +67,12 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = new String[0];
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
@@ -170,7 +173,18 @@ public abstract class AbstractBeanDefinitionParser implements BeanDefinitionPars
}
/**
* Controls whether this parser is supposed to fire a
* Determine whether the element's "name" attribute should get parsed as
* bean definition aliases, i.e. alternative bean definition names.
* <p>The default implementation returns {@code true}.
* @return whether the parser should evaluate the "name" attribute as aliases
* @since 4.1.5
*/
protected boolean shouldParseNameAsAliases() {
return true;
}
/**
* Determine whether this parser is supposed to fire a
* {@link org.springframework.beans.factory.parsing.BeanComponentDefinition}
* event after parsing the bean definition.
* <p>This implementation returns {@code true} by default; that is,
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
package org.springframework.beans.factory.xml;
import java.io.IOException;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -45,7 +44,9 @@ public class BeansDtdResolver implements EntityResolver {
private static final String DTD_EXTENSION = ".dtd";
private static final String[] DTD_NAMES = {"spring-beans-2.0", "spring-beans"};
private static final String DTD_FILENAME = "spring-beans-2.0";
private static final String DTD_NAME = "spring-beans";
private static final Log logger = LogFactory.getLog(BeansDtdResolver.class);
@@ -58,30 +59,28 @@ public class BeansDtdResolver implements EntityResolver {
}
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
int lastPathSeparator = systemId.lastIndexOf("/");
for (String DTD_NAME : DTD_NAMES) {
int dtdNameStart = systemId.indexOf(DTD_NAME);
if (dtdNameStart > lastPathSeparator) {
String dtdFile = systemId.substring(dtdNameStart);
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex);
}
}
int dtdNameStart = systemId.indexOf(DTD_NAME);
if (dtdNameStart > lastPathSeparator) {
String dtdFile = DTD_FILENAME + DTD_EXTENSION;
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
}
}
}
}
@@ -92,7 +91,7 @@ public class BeansDtdResolver implements EntityResolver {
@Override
public String toString() {
return "EntityResolver for DTDs " + Arrays.toString(DTD_NAMES);
return "EntityResolver for spring-beans DTD";
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -518,6 +518,36 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor
assertTrue("correct values", pt.stringArray[0].equals("a1") && pt.stringArray[1].equals("b2"));
}
@Test
public void testStringArrayAutoGrow() throws Exception {
StringArrayBean target = new StringArrayBean();
BeanWrapper bw = new BeanWrapperImpl(target);
bw.setAutoGrowNestedPaths(true);
bw.setPropertyValue("array[0]", "Test0");
assertEquals(1, target.getArray().length);
bw.setPropertyValue("array[2]", "Test2");
assertEquals(3, target.getArray().length);
assertTrue("correct values", target.getArray()[0].equals("Test0") && target.getArray()[1] == null &&
target.getArray()[2].equals("Test2"));
}
@Test
public void testPrimitiveArrayAutoGrow() throws Exception {
PrimitiveArrayBean target = new PrimitiveArrayBean();
BeanWrapper bw = new BeanWrapperImpl(target);
bw.setAutoGrowNestedPaths(true);
bw.setPropertyValue("array[0]", 1);
assertEquals(1, target.getArray().length);
bw.setPropertyValue("array[2]", 3);
assertEquals(3, target.getArray().length);
assertTrue("correct values", target.getArray()[0] == 1 && target.getArray()[1] == 0 &&
target.getArray()[2] == 3);
}
@Test
public void testStringPropertyWithCustomEditor() throws Exception {
TestBean tb = new TestBean();
@@ -1723,6 +1753,20 @@ public final class BeanWrapperTests extends AbstractConfigurablePropertyAccessor
}
}
@SuppressWarnings("unused")
private static class StringArrayBean {
private String[] array;
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
}
@SuppressWarnings("unused")
private static class NumberPropertyBean {
@@ -841,19 +841,24 @@ public class ExtendedBeanInfoTests {
public String getAddress(int index){ return null; }
}
{ // baseline. ExtendedBeanInfo needs to behave exactly like the following
// Baseline: ExtendedBeanInfo needs to behave exactly like the following...
boolean hasReadMethod;
boolean hasWriteMethod;
boolean hasIndexedReadMethod;
boolean hasIndexedWriteMethod;
{
BeanInfo bi = Introspector.getBeanInfo(A.class);
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
hasReadMethod = hasReadMethodForProperty(bi, "address");
hasWriteMethod = hasWriteMethodForProperty(bi, "address");
hasIndexedReadMethod = hasIndexedReadMethodForProperty(bi, "address");
hasIndexedWriteMethod = hasIndexedWriteMethodForProperty(bi, "address");
}
{
BeanInfo bi = new ExtendedBeanInfo(Introspector.getBeanInfo(A.class));
assertThat(hasReadMethodForProperty(bi, "address"), is(false));
assertThat(hasWriteMethodForProperty(bi, "address"), is(false));
assertThat(hasIndexedReadMethodForProperty(bi, "address"), is(true));
assertThat(hasIndexedWriteMethodForProperty(bi, "address"), is(true));
assertEquals(hasReadMethodForProperty(bi, "address"), hasReadMethod);
assertEquals(hasWriteMethodForProperty(bi, "address"), hasWriteMethod);
assertEquals(hasIndexedReadMethodForProperty(bi, "address"), hasIndexedReadMethod);
assertEquals(hasIndexedWriteMethodForProperty(bi, "address"), hasIndexedWriteMethod);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@@ -53,16 +51,16 @@ public final class BeanFactoryUtilsTests {
private static final Resource LEAF_CONTEXT = qualifiedResource(CLASS, "leaf.xml");
private static final Resource DEPENDENT_BEANS_CONTEXT = qualifiedResource(CLASS, "dependentBeans.xml");
private ConfigurableListableBeanFactory listableBeanFactory;
private DefaultListableBeanFactory listableBeanFactory;
private DefaultListableBeanFactory dependentBeansFactory;
private ConfigurableListableBeanFactory dependentBeansBF;
@Before
public void setUp() {
// Interesting hierarchical factory to test counts.
// Slow to read so we cache it.
DefaultListableBeanFactory grandParent = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(grandParent).loadBeanDefinitions(ROOT_CONTEXT);
DefaultListableBeanFactory parent = new DefaultListableBeanFactory(grandParent);
@@ -70,12 +68,13 @@ public final class BeanFactoryUtilsTests {
DefaultListableBeanFactory child = new DefaultListableBeanFactory(parent);
new XmlBeanDefinitionReader(child).loadBeanDefinitions(LEAF_CONTEXT);
this.dependentBeansBF = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader((BeanDefinitionRegistry) this.dependentBeansBF).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
dependentBeansBF.preInstantiateSingletons();
this.dependentBeansFactory = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(this.dependentBeansFactory).loadBeanDefinitions(DEPENDENT_BEANS_CONTEXT);
dependentBeansFactory.preInstantiateSingletons();
this.listableBeanFactory = child;
}
@Test
public void testHierarchicalCountBeansWithNonHierarchicalFactory() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
@@ -92,22 +91,21 @@ public final class BeanFactoryUtilsTests {
// Leaf count
assertTrue(this.listableBeanFactory.getBeanDefinitionCount() == 1);
// Count minus duplicate
assertTrue("Should count 7 beans, not "
+ BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
assertTrue("Should count 7 beans, not " + BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory),
BeanFactoryUtils.countBeansIncludingAncestors(this.listableBeanFactory) == 7);
}
@Test
public void testHierarchicalNamesWithNoMatch() throws Exception {
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
NoOp.class));
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, NoOp.class));
assertEquals(0, names.size());
}
@Test
public void testHierarchicalNamesWithMatchOnlyInRoot() throws Exception {
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
IndexedTestBean.class));
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, IndexedTestBean.class));
assertEquals(1, names.size());
assertTrue(names.contains("indexedBean"));
// Distinguish from default ListableBeanFactory behavior
@@ -116,8 +114,8 @@ public final class BeanFactoryUtilsTests {
@Test
public void testGetBeanNamesForTypeWithOverride() throws Exception {
List<String> names = Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory,
ITestBean.class));
List<String> names = Arrays.asList(
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class));
// includes 2 TestBeans from FactoryBeans (DummyFactory definitions)
assertEquals(4, names.size());
assertTrue(names.contains("test"));
@@ -130,7 +128,7 @@ public final class BeanFactoryUtilsTests {
public void testNoBeansOfType() {
StaticListableBeanFactory lbf = new StaticListableBeanFactory();
lbf.addBean("foo", new Object());
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
assertTrue(beans.isEmpty());
}
@@ -147,7 +145,7 @@ public final class BeanFactoryUtilsTests {
lbf.addBean("t3", t3);
lbf.addBean("t4", t4);
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
Map<String, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf, ITestBean.class, true, false);
assertEquals(2, beans.size());
assertEquals(t1, beans.get("t1"));
assertEquals(t2, beans.get("t2"));
@@ -191,8 +189,8 @@ public final class BeanFactoryUtilsTests {
this.listableBeanFactory.registerSingleton("t3", t3);
this.listableBeanFactory.registerSingleton("t4", t4);
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
false);
Map<String, ?> beans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
assertEquals(6, beans.size());
assertEquals(test3, beans.get("test3"));
assertEquals(test, beans.get("test"));
@@ -200,12 +198,9 @@ public final class BeanFactoryUtilsTests {
assertEquals(t2, beans.get("t2"));
assertEquals(t3.getObject(), beans.get("t3"));
assertTrue(beans.get("t4") instanceof TestBean);
// t3 and t4 are found here as of Spring 2.0, since they are
// pre-registered
// singleton instances, while testFactory1 and testFactory are *not*
// found
// because they are FactoryBean definitions that haven't been
// initialized yet.
// t3 and t4 are found here as of Spring 2.0, since they are pre-registered
// singleton instances, while testFactory1 and testFactory are *not* found
// because they are FactoryBean definitions that haven't been initialized yet.
beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, false, true);
Object testFactory1 = this.listableBeanFactory.getBean("testFactory1");
@@ -247,8 +242,8 @@ public final class BeanFactoryUtilsTests {
Object test3 = this.listableBeanFactory.getBean("test3");
Object test = this.listableBeanFactory.getBean("test");
Map<?, ?> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true,
false);
Map<String, ?> beans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(this.listableBeanFactory, ITestBean.class, true, false);
assertEquals(2, beans.size());
assertEquals(test3, beans.get("test3"));
assertEquals(test, beans.get("test"));
@@ -283,25 +278,25 @@ public final class BeanFactoryUtilsTests {
@Test
public void testADependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("a");
String[] deps = this.dependentBeansFactory.getDependentBeans("a");
assertTrue(ObjectUtils.isEmpty(deps));
}
@Test
public void testBDependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("b");
String[] deps = this.dependentBeansFactory.getDependentBeans("b");
assertTrue(Arrays.equals(new String[] { "c" }, deps));
}
@Test
public void testCDependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("c");
String[] deps = this.dependentBeansFactory.getDependentBeans("c");
assertTrue(Arrays.equals(new String[] { "int", "long" }, deps));
}
@Test
public void testIntDependencies() {
String[] deps = this.dependentBeansBF.getDependentBeans("int");
String[] deps = this.dependentBeansFactory.getDependentBeans("int");
assertTrue(Arrays.equals(new String[] { "buffer" }, deps));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -200,7 +200,7 @@ public class DefaultListableBeanFactoryTests {
}
@Test
public void testPrototypeSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
public void testSingletonFactoryBeanIgnoredByNonEagerTypeMatching() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
Properties p = new Properties();
p.setProperty("x1.(class)", DummyFactory.class.getName());
@@ -1340,10 +1340,10 @@ public class DefaultListableBeanFactoryTests {
public void testDependsOnCycle() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
bd1.setDependsOn(new String[] {"tb2"});
bd1.setDependsOn("tb2");
lbf.registerBeanDefinition("tb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setDependsOn(new String[] {"tb1"});
bd2.setDependsOn("tb1");
lbf.registerBeanDefinition("tb2", bd2);
try {
lbf.preInstantiateSingletons();
@@ -1361,13 +1361,13 @@ public class DefaultListableBeanFactoryTests {
public void testImplicitDependsOnCycle() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
bd1.setDependsOn(new String[] {"tb2"});
bd1.setDependsOn("tb2");
lbf.registerBeanDefinition("tb1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
bd2.setDependsOn(new String[] {"tb3"});
bd2.setDependsOn("tb3");
lbf.registerBeanDefinition("tb2", bd2);
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
bd3.setDependsOn(new String[] {"tb1"});
bd3.setDependsOn("tb1");
lbf.registerBeanDefinition("tb3", bd3);
try {
lbf.preInstantiateSingletons();
@@ -1381,7 +1381,7 @@ public class DefaultListableBeanFactoryTests {
}
}
@Test(expected=NoSuchBeanDefinitionException.class)
@Test(expected = NoSuchBeanDefinitionException.class)
public void testGetBeanByTypeWithNoneFound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.getBean(TestBean.class);
@@ -1397,7 +1397,7 @@ public class DefaultListableBeanFactoryTests {
assertThat(bean.getBeanName(), equalTo("bd1"));
}
@Test(expected=NoUniqueBeanDefinitionException.class)
@Test(expected = NoUniqueBeanDefinitionException.class)
public void testGetBeanByTypeWithAmbiguity() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
@@ -1540,7 +1540,7 @@ public class DefaultListableBeanFactoryTests {
}
@Test
public void testGetBeanByTypeInstanceWithPrimary() throws Exception {
public void testGetBeanByTypeInstanceWithPrimary() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
@@ -1553,7 +1553,7 @@ public class DefaultListableBeanFactoryTests {
}
@Test
public void testGetBeanByTypeInstanceWithMultiplePrimary() throws Exception {
public void testGetBeanByTypeInstanceWithMultiplePrimary() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
@@ -1584,16 +1584,35 @@ public class DefaultListableBeanFactoryTests {
try {
lbf.getBean(TestBean.class, 67);
fail("Should have thrown NoSuchBeanDefinitionException");
} catch (NoSuchBeanDefinitionException ex) {
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
@Test
public void testGetBeanWithArgsNotCreatedForFactoryBeanChecking() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd1 = new RootBeanDefinition(ConstructorDependency.class);
bd1.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bd1.getConstructorArgumentValues().addGenericArgumentValue(String.valueOf(age));
return bd1;
lbf.registerBeanDefinition("bd1", bd1);
RootBeanDefinition bd2 = new RootBeanDefinition(ConstructorDependencyFactoryBean.class);
bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("bd2", bd2);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class, 42);
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(42));
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependency.class).length);
assertEquals(1, lbf.getBeanNamesForType(ConstructorDependencyFactoryBean.class).length);
}
private RootBeanDefinition createConstructorDependencyBeanDefinition(int age) {
RootBeanDefinition bd = new RootBeanDefinition(ConstructorDependency.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bd.getConstructorArgumentValues().addGenericArgumentValue(String.valueOf(age));
return bd;
}
@Test
@@ -1641,7 +1660,7 @@ public class DefaultListableBeanFactoryTests {
* Java method names. In other words, you can't name a method
* {@code set&amp;FactoryBean(...)}.
*/
@Test(expected=TypeMismatchException.class)
@Test(expected = TypeMismatchException.class)
public void testAutowireBeanWithFactoryBeanByName() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
RootBeanDefinition bd = new RootBeanDefinition(LazyInitFactory.class);
@@ -1664,8 +1683,8 @@ public class DefaultListableBeanFactoryTests {
}
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().indexOf("test") != -1);
assertTrue(ex.getMessage().indexOf("spouse") != -1);
assertTrue(ex.getMessage().contains("test"));
assertTrue(ex.getMessage().contains("spouse"));
}
}
@@ -1682,8 +1701,8 @@ public class DefaultListableBeanFactoryTests {
}
catch (UnsatisfiedDependencyException ex) {
// expected
assertTrue(ex.getMessage().indexOf("test") != -1);
assertTrue(ex.getMessage().indexOf("spouse") != -1);
assertTrue(ex.getMessage().contains("test"));
assertTrue(ex.getMessage().contains("spouse"));
}
}
@@ -2518,7 +2537,7 @@ public class DefaultListableBeanFactoryTests {
assertEquals(expectedNameFromArgs, tb2.getName());
}
@Test(expected=IllegalStateException.class)
@Test(expected = IllegalStateException.class)
public void testScopingBeanToUnregisteredScopeResultsInAnException() throws Exception {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@ import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import java.util.prefs.PreferencesFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
@@ -53,13 +52,13 @@ import static org.springframework.tests.TestResourceUtils.*;
* {@link PropertyPlaceholderConfigurer}, {@link PropertyOverrideConfigurer} and
* {@link PreferencesPlaceholderConfigurer}.
*
* @see PropertyPlaceholderConfigurerTests
* @since 02.10.2003
* @author Juergen Hoeller
* @author Chris Beams
* @author Phillip Webb
* @since 02.10.2003
* @see PropertyPlaceholderConfigurerTests
*/
public final class PropertyResourceConfigurerTests {
public class PropertyResourceConfigurerTests {
static {
System.setProperty("java.util.prefs.PreferencesFactory", MockPreferencesFactory.class.getName());
@@ -70,23 +69,15 @@ public final class PropertyResourceConfigurerTests {
private static final Resource XTEST_PROPS = qualifiedResource(CLASS, "xtest.properties"); // does not exist
private static final Resource TEST_PROPS_XML = qualifiedResource(CLASS, "test.properties.xml");
private DefaultListableBeanFactory factory;
private final DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
@Before
public void setUp() {
factory = new DefaultListableBeanFactory();
}
@Test
public void testPropertyOverrideConfigurer() {
BeanDefinition def1 = BeanDefinitionBuilder
.genericBeanDefinition(TestBean.class)
.getBeanDefinition();
BeanDefinition def1 = BeanDefinitionBuilder.genericBeanDefinition(TestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb1", def1);
BeanDefinition def2 = BeanDefinitionBuilder
.genericBeanDefinition(TestBean.class)
.getBeanDefinition();
BeanDefinition def2 = BeanDefinitionBuilder.genericBeanDefinition(TestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb2", def2);
PropertyOverrideConfigurer poc1;
@@ -123,9 +114,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithNestedProperty() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc;
@@ -143,9 +132,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithNestedPropertyAndDotInBeanName() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("my.tb", def);
PropertyOverrideConfigurer poc;
@@ -164,9 +151,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithNestedMapPropertyAndDotInMapKey() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc;
@@ -184,9 +169,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithHeldProperties() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(PropertiesHolder.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(PropertiesHolder.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc;
@@ -200,23 +183,9 @@ public final class PropertyResourceConfigurerTests {
assertEquals("true", tb.getHeldProperties().getProperty("mail.smtp.auth"));
}
static class PropertiesHolder {
private Properties props = new Properties();
public Properties getHeldProperties() {
return props;
}
public void setHeldProperties(Properties props) {
this.props = props;
}
}
@Test
public void testPropertyOverrideConfigurerWithPropertiesFile() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
@@ -230,13 +199,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithInvalidPropertiesFile() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
poc.setLocations(new Resource[] { TEST_PROPS, XTEST_PROPS });
poc.setLocations(TEST_PROPS, XTEST_PROPS);
poc.setIgnoreResourceNotFound(true);
poc.postProcessBeanFactory(factory);
@@ -247,9 +214,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithPropertiesXmlFile() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
PropertyOverrideConfigurer poc = new PropertyOverrideConfigurer();
@@ -263,9 +228,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyOverrideConfigurerWithConvertProperties() {
BeanDefinition def = BeanDefinitionBuilder
.genericBeanDefinition(IndexedTestBean.class)
.getBeanDefinition();
BeanDefinition def = BeanDefinitionBuilder.genericBeanDefinition(IndexedTestBean.class).getBeanDefinition();
factory.registerBeanDefinition("tb", def);
ConvertingOverrideConfigurer bfpp = new ConvertingOverrideConfigurer();
@@ -389,7 +352,6 @@ public final class PropertyResourceConfigurerTests {
cas.addGenericArgumentValue("${var}name${age}");
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("stringArray", new String[] {"${os.name}", "${age}"});
List<Object> friends = new ManagedList<Object>();
@@ -409,7 +371,7 @@ public final class PropertyResourceConfigurerTests {
someMap.put("key1", new RuntimeBeanReference("${ref}"));
someMap.put("key2", "${age}name");
MutablePropertyValues innerPvs = new MutablePropertyValues();
innerPvs.add("touchy", "${os.name}");
innerPvs.add("country", "${os.name}");
RootBeanDefinition innerBd = new RootBeanDefinition(TestBean.class);
innerBd.setPropertyValues(innerPvs);
someMap.put("key3", innerBd);
@@ -459,30 +421,28 @@ public final class PropertyResourceConfigurerTests {
TestBean inner2 = (TestBean) tb2.getSomeMap().get("mykey4");
assertEquals(0, inner1.getAge());
assertEquals(null, inner1.getName());
assertEquals(System.getProperty("os.name"), inner1.getTouchy());
assertEquals(System.getProperty("os.name"), inner1.getCountry());
assertEquals(98, inner2.getAge());
assertEquals("namemyvarmyvar${", inner2.getName());
assertEquals(System.getProperty("os.name"), inner2.getTouchy());
assertEquals(System.getProperty("os.name"), inner2.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithSystemPropertyFallback() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("country", "${os.name}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals(System.getProperty("os.name"), tb.getTouchy());
assertEquals(System.getProperty("os.name"), tb.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithSystemPropertyNotUsed() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("country", "${os.name}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -491,14 +451,13 @@ public final class PropertyResourceConfigurerTests {
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals("myos", tb.getTouchy());
assertEquals("myos", tb.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithOverridingSystemProperty() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${os.name}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("country", "${os.name}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -508,14 +467,13 @@ public final class PropertyResourceConfigurerTests {
ppc.postProcessBeanFactory(factory);
TestBean tb = (TestBean) factory.getBean("tb");
assertEquals(System.getProperty("os.name"), tb.getTouchy());
assertEquals(System.getProperty("os.name"), tb.getCountry());
}
@Test
public void testPropertyPlaceholderConfigurerWithUnresolvableSystemProperty() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${user.dir}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${user.dir}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_NEVER);
@@ -532,9 +490,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithUnresolvablePlaceholder() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -550,9 +507,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithIgnoreUnresolvablePlaceholder() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setIgnoreUnresolvablePlaceholders(true);
@@ -564,9 +520,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithEmptyStringAsNull() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setNullValue("");
@@ -578,9 +533,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithEmptyStringInPlaceholderAsNull() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${ref}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setNullValue("");
@@ -595,9 +549,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithNestedPlaceholderInKey() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my${key}key}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my${key}key}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -612,8 +565,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithPlaceholderInAlias() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerAlias("tb", "${alias}");
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -629,8 +581,7 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithSelfReferencingPlaceholderInAlias() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class).getBeanDefinition());
factory.registerAlias("tb", "${alias}");
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -646,11 +597,10 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithCircularReference() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("age", "${age}")
.addPropertyValue("name", "name${var}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("age", "${age}")
.addPropertyValue("name", "name${var}")
.getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -670,9 +620,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithDefaultProperties() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
@@ -686,9 +635,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithInlineDefault() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test:mytest}").getBeanDefinition());
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.postProcessBeanFactory(factory);
@@ -699,9 +647,8 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPropertyPlaceholderConfigurerWithAliases() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("touchy", "${test}").getBeanDefinition());
factory.registerAlias("tb", "${myAlias}");
factory.registerAlias("${myTarget}", "alias2");
@@ -724,12 +671,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPreferencesPlaceholderConfigurer() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
Properties props = new Properties();
@@ -752,12 +698,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPreferencesPlaceholderConfigurerWithCustomTreePaths() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myTouchy}")
.getBeanDefinition());
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
Properties props = new Properties();
@@ -782,12 +727,11 @@ public final class PropertyResourceConfigurerTests {
@Test
public void testPreferencesPlaceholderConfigurerWithPathInPlaceholder() {
factory.registerBeanDefinition("tb",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${mypath/myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myotherpath/myTouchy}")
.getBeanDefinition());
factory.registerBeanDefinition("tb", genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${mypath/myName}")
.addPropertyValue("age", "${myAge}")
.addPropertyValue("touchy", "${myotherpath/myTouchy}")
.getBeanDefinition());
PreferencesPlaceholderConfigurer ppc = new PreferencesPlaceholderConfigurer();
Properties props = new Properties();
@@ -811,6 +755,20 @@ public final class PropertyResourceConfigurerTests {
}
static class PropertiesHolder {
private Properties props = new Properties();
public Properties getHeldProperties() {
return props;
}
public void setHeldProperties(Properties props) {
this.props = props;
}
}
private static class ConvertingOverrideConfigurer extends PropertyOverrideConfigurer {
@Override
@@ -819,26 +777,28 @@ public final class PropertyResourceConfigurerTests {
}
}
/**
* {@link PreferencesFactory} to create {@link MockPreferences}.
*/
public static class MockPreferencesFactory implements PreferencesFactory {
private Preferences systemRoot = new MockPreferences();
private final Preferences userRoot = new MockPreferences();
private Preferences userRoot = new MockPreferences();
private final Preferences systemRoot = new MockPreferences();
@Override
public Preferences systemRoot() {
return systemRoot;
return this.systemRoot;
}
@Override
public Preferences userRoot() {
return userRoot;
return this.userRoot;
}
}
/**
* Mock implementation of {@link Preferences} that behaves the same regardless of the
* underlying operating system and will never throw security exceptions.
@@ -904,4 +864,5 @@ public final class PropertyResourceConfigurerTests {
protected void flushSpi() throws BackingStoreException {
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -770,7 +770,7 @@ public class BeanFactoryGenericsTests {
}
@Test
public void testSpr11250() {
public void testGenericMatchingWithBeanNameDifferentiation() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
@@ -780,8 +780,23 @@ public class BeanFactoryGenericsTests {
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
NumberBean nb = bf.getBean(NumberBean.class);
assertNotNull(nb.getDoubleStore());
assertNotNull(nb.getFloatStore());
assertSame(bf.getBean("doubleStore"), nb.getDoubleStore());
assertSame(bf.getBean("floatStore"), nb.getFloatStore());
}
@Test
public void testGenericMatchingWithFullTypeDifferentiation() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new GenericTypeAwareAutowireCandidateResolver());
bf.registerBeanDefinition("store1", new RootBeanDefinition(DoubleStore.class));
bf.registerBeanDefinition("store2", new RootBeanDefinition(FloatStore.class));
bf.registerBeanDefinition("numberBean",
new RootBeanDefinition(NumberBean.class, RootBeanDefinition.AUTOWIRE_CONSTRUCTOR, false));
NumberBean nb = bf.getBean(NumberBean.class);
assertSame(bf.getBean("store1"), nb.getDoubleStore());
assertSame(bf.getBean("store2"), nb.getFloatStore());
}
@@ -851,6 +866,14 @@ public class BeanFactoryGenericsTests {
}
public static class DoubleStore extends NumberStore<Double> {
}
public static class FloatStore extends NumberStore<Float> {
}
public static class NumberBean {
private final NumberStore<Double> doubleStore;
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,9 @@ import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;
@@ -88,8 +91,16 @@ public class GuavaCache implements Cache {
@Override
public ValueWrapper get(Object key) {
Object value = this.cache.getIfPresent(key);
return toWrapper(value);
if (this.cache instanceof LoadingCache) {
try {
Object value = ((LoadingCache<Object, Object>) this.cache).get(key);
return toWrapper(value);
}
catch (ExecutionException ex) {
throw new UncheckedExecutionException(ex.getMessage(), ex);
}
}
return toWrapper(this.cache.getIfPresent(key));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.cache.jcache.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cache.annotation.AbstractCachingConfiguration;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
import org.springframework.cache.jcache.interceptor.JCacheOperationSource;
@@ -34,14 +35,16 @@ import org.springframework.context.annotation.Role;
* @see JCacheConfigurer
*/
@Configuration
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration<JCacheConfigurer> {
public class AbstractJCacheConfiguration extends AbstractCachingConfiguration {
protected CacheResolver exceptionCacheResolver;
@Override
protected void useCachingConfigurer(JCacheConfigurer config) {
protected void useCachingConfigurer(CachingConfigurer config) {
super.useCachingConfigurer(config);
this.exceptionCacheResolver = config.exceptionCacheResolver();
if (config instanceof JCacheConfigurer) {
this.exceptionCacheResolver = ((JCacheConfigurer) config).exceptionCacheResolver();
}
}
@Bean(name = "jCacheOperationSource")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -128,9 +128,9 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc
@Override
public void afterSingletonsInstantiated() {
// Make sure those are initialized on startup...
// Make sure that the cache resolver is initialized. An exception cache resolver is only
// required if the exceptionCacheName attribute is set on an operation
Assert.notNull(getDefaultCacheResolver(), "Cache resolver should have been initialized");
Assert.notNull(getDefaultExceptionCacheResolver(), "Exception cache resolver should have been initialized");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,21 +28,21 @@ import org.springframework.cache.interceptor.CacheResolver;
* <p>A cache operation can be statically cached as it does not contain
* any runtime operation of a specific cache invocation.
*
* @param <A> the type of the JSR-107 annotation
* @author Stephane Nicoll
* @since 4.1
* @param <A> the type of the JSR-107 annotation
*/
public interface JCacheOperation<A extends Annotation> extends BasicOperation, CacheMethodDetails<A> {
/**
* Return the {@link CacheResolver} instance to use to resolve the cache to
* use for this operation.
* Return the {@link CacheResolver} instance to use to resolve the cache
* to use for this operation.
*/
CacheResolver getCacheResolver();
/**
* Return the {@link CacheInvocationParameter} instances based on the specified
* method arguments.
* Return the {@link CacheInvocationParameter} instances based on the
* specified method arguments.
* <p>The method arguments must match the signature of the related method invocation
* @param values the parameters value for a particular invocation
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,10 @@ package org.springframework.cache.guava;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
@@ -32,6 +35,9 @@ import static org.mockito.Mockito.*;
*/
public class GuavaCacheManagerTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void testDynamicMode() {
CacheManager cm = new GuavaCacheManager();
@@ -150,6 +156,28 @@ public class GuavaCacheManagerTests {
assertNotNull(cm.getCache("someCache"));
}
@Test
public void cacheLoaderUseLoadingCache() {
GuavaCacheManager cm = new GuavaCacheManager("c1");
cm.setCacheLoader(new CacheLoader<Object, Object>() {
@Override
public Object load(Object key) throws Exception {
if ("ping".equals(key)) {
return "pong";
}
throw new IllegalArgumentException("I only know ping");
}
});
Cache cache1 = cm.getCache("c1");
Cache.ValueWrapper value = cache1.get("ping");
assertNotNull(value);
assertEquals("pong", value.get());
thrown.expect(UncheckedExecutionException.class);
thrown.expectMessage("I only know ping");
assertNull(cache1.get("foo"));
}
@SuppressWarnings("unchecked")
private CacheLoader<Object, Object> mockCacheLoader() {
return mock(CacheLoader.class);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,12 +18,15 @@ package org.springframework.cache.jcache.config;
import java.util.Arrays;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.config.SomeKeyGenerator;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
@@ -35,7 +38,6 @@ import org.springframework.cache.interceptor.SimpleKeyGenerator;
import org.springframework.cache.jcache.interceptor.AnnotatedJCacheableService;
import org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource;
import org.springframework.cache.jcache.interceptor.JCacheInterceptor;
import org.springframework.cache.jcache.interceptor.SimpleExceptionCacheResolver;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.ApplicationContext;
@@ -51,6 +53,9 @@ import static org.junit.Assert.*;
*/
public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Override
protected ApplicationContext getApplicationContext() {
return new AnnotationConfigApplicationContext(EnableCachingConfig.class);
@@ -80,10 +85,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
assertEquals(SimpleCacheResolver.class, cos.getCacheResolver().getClass());
assertSame(context.getBean(CacheManager.class),
((SimpleCacheResolver) cos.getCacheResolver()).getCacheManager());
assertNotNull(cos.getExceptionCacheResolver());
assertEquals(SimpleExceptionCacheResolver.class, cos.getExceptionCacheResolver().getClass());
assertSame(context.getBean(CacheManager.class),
((SimpleExceptionCacheResolver) cos.getExceptionCacheResolver()).getCacheManager());
assertNull(cos.getExceptionCacheResolver());
context.close();
}
@@ -99,6 +101,28 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
context.close();
}
@Test
public void exceptionCacheResolverFallbacksToMainOne() {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(
NoExceptionCacheResolverConfig.class);
try {
DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class);
assertSame(context.getBean("cacheResolver"), cos.getCacheResolver());
assertNull(cos.getExceptionCacheResolver());
JCacheableService<?> service = context.getBean(JCacheableService.class);
service.cache("id");
// This call requires the cache manager to be set
thrown.expect(IllegalStateException.class);
service.cacheWithException("test", false);
}
finally {
context.close();
}
}
@Configuration
@EnableCaching
@@ -200,4 +224,20 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests {
}
}
@Configuration
@EnableCaching
static class NoExceptionCacheResolverConfig extends JCacheConfigurerSupport {
@Override
@Bean
public CacheResolver cacheResolver() {
return new NamedCacheResolver(new ConcurrentMapCacheManager(), "default");
}
@Bean
public JCacheableService<?> cacheableService() {
return new AnnotatedJCacheableService(new ConcurrentMapCache("default"));
}
}
}
@@ -381,17 +381,20 @@ public class QuartzSupportTests {
/**
* SPR-6038: detect HSQL and stop illegal locks being taken.
* TODO: Against Quartz 2.2, this test's job doesn't actually execute anymore...
*/
@Test
public void schedulerWithHsqlDataSource() throws Exception {
Assume.group(TestGroup.PERFORMANCE);
// Assume.group(TestGroup.PERFORMANCE);
DummyJob.param = 0;
DummyJob.count = 0;
ClassPathXmlApplicationContext ctx = context("databasePersistence.xml");
JdbcTemplate jdbcTemplate = new JdbcTemplate(ctx.getBean(DataSource.class));
assertTrue("No triggers were persisted", jdbcTemplate.queryForList("SELECT * FROM qrtz_triggers").size()>0);
assertFalse("No triggers were persisted", jdbcTemplate.queryForList("SELECT * FROM qrtz_triggers").isEmpty());
/*
Thread.sleep(3000);
try {
assertTrue(DummyJob.count > 0);
@@ -399,6 +402,7 @@ public class QuartzSupportTests {
finally {
ctx.close();
}
*/
}
private ClassPathXmlApplicationContext context(String path) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
package org.springframework.cache.annotation;
import java.util.Collection;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
@@ -28,12 +27,11 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Abstract base {@code @Configuration} class providing common structure for enabling
* Spring's annotation-driven cache management capability.
* Abstract base {@code @Configuration} class providing common structure
* for enabling Spring's annotation-driven cache management capability.
*
* @author Chris Beams
* @author Stephane Nicoll
@@ -41,7 +39,7 @@ import org.springframework.util.CollectionUtils;
* @see EnableCaching
*/
@Configuration
public abstract class AbstractCachingConfiguration<C extends CachingConfigurer> implements ImportAware {
public abstract class AbstractCachingConfiguration implements ImportAware {
protected AnnotationAttributes enableCaching;
@@ -53,17 +51,19 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
protected CacheErrorHandler errorHandler;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableCaching = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableCaching.class.getName(), false));
Assert.notNull(this.enableCaching,
"@EnableCaching is not present on importing class " +
importMetadata.getClassName());
if (this.enableCaching == null) {
throw new IllegalArgumentException(
"@EnableCaching is not present on importing class " + importMetadata.getClassName());
}
}
@Autowired(required = false)
void setConfigurers(Collection<C> configurers) {
void setConfigurers(Collection<CachingConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
@@ -73,14 +73,14 @@ public abstract class AbstractCachingConfiguration<C extends CachingConfigurer>
"Refactor the configuration such that CachingConfigurer is " +
"implemented only once or not at all.");
}
C configurer = configurers.iterator().next();
CachingConfigurer configurer = configurers.iterator().next();
useCachingConfigurer(configurer);
}
/**
* Extract the configuration from the nominated {@link CachingConfigurer}.
*/
protected void useCachingConfigurer(C config) {
protected void useCachingConfigurer(CachingConfigurer config) {
this.cacheManager = config.cacheManager();
this.cacheResolver = config.cacheResolver();
this.keyGenerator = config.keyGenerator();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ import org.springframework.context.annotation.Role;
* @see CachingConfigurationSelector
*/
@Configuration
public class ProxyCachingConfiguration extends AbstractCachingConfiguration<CachingConfigurer> {
public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
@Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import org.springframework.cache.Cache;
/**
* Determine the {@link Cache} instance(s) to use for an intercepted method invocation.
*
* <p>Implementations MUST be thread-safe.
* <p>Implementations must be thread-safe.
*
* @author Stephane Nicoll
* @since 4.1
@@ -32,9 +32,8 @@ public interface CacheResolver {
/**
* Return the cache(s) to use for the specified invocation.
*
* @param context the context of the particular invocation
* @return the cache(s) to use (never null)
* @return the cache(s) to use (never {@code null})
*/
Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,9 +28,9 @@ import org.springframework.util.Assert;
* based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*}
* annotations).
*
* @param <A> Annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute}
* @author Chris Beams
* @since 3.1
* @param <A> annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute}
*/
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.context.annotation;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -63,6 +64,8 @@ final class ConfigurationClass {
private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
new LinkedHashMap<ImportBeanDefinitionRegistrar, AnnotationMetadata>();
final Set<String> skippedBeanMethods = new HashSet<String>();
/**
* Create a new {@link ConfigurationClass} with the given name.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -182,33 +182,25 @@ class ConfigurationClassBeanDefinitionReader {
* with the BeanDefinitionRegistry based on its contents.
*/
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
if (this.conditionEvaluator.shouldSkip(beanMethod.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
return;
}
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName();
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(metadata.getMethodName());
// Do we need to mark the bean as skipped by its condition?
if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
configClass.skippedBeanMethods.add(methodName);
return;
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(metadata.getMethodName());
if (configClass.skippedBeanMethods.contains(methodName)) {
return;
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
// Consider name and any aliases
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
List<String> names = new ArrayList<String>(Arrays.asList(bean.getStringArray("name")));
String beanName = (names.size() > 0 ? names.remove(0) : beanMethod.getMetadata().getMethodName());
String beanName = (names.size() > 0 ? names.remove(0) : methodName);
// Register aliases even when overridden
for (String alias : names) {
this.registry.registerAlias(beanName, alias);
}
@@ -218,6 +210,23 @@ class ConfigurationClassBeanDefinitionReader {
return;
}
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setResource(configClass.getResource());
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
if (metadata.isStatic()) {
// static @Bean method
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
beanDef.setFactoryMethodName(methodName);
}
else {
// instance @Bean method
beanDef.setFactoryBeanName(configClass.getBeanName());
beanDef.setUniqueFactoryMethodName(methodName);
}
beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
Autowire autowire = bean.getEnum("autowire");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -133,7 +133,7 @@ class ConfigurationClassParser {
private final ImportStack importStack = new ImportStack();
private final List<DeferredImportSelectorHolder> deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
private List<DeferredImportSelectorHolder> deferredImportSelectors;
/**
@@ -156,6 +156,8 @@ class ConfigurationClassParser {
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
@@ -177,6 +179,7 @@ class ConfigurationClassParser {
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
@@ -269,7 +272,7 @@ class ConfigurationClassParser {
}
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true, false);
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
@@ -416,12 +419,15 @@ class ConfigurationClassParser {
}
private void processDeferredImportSelectors() {
Collections.sort(this.deferredImportSelectors, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : this.deferredImportSelectors) {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false, true);
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
@@ -431,11 +437,10 @@ class ConfigurationClassParser {
configClass.getMetadata().getClassName() + "]", ex);
}
}
this.deferredImportSelectors.clear();
}
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports, boolean deferred) throws IOException {
Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
if (importCandidates.isEmpty()) {
return;
@@ -453,14 +458,14 @@ class ConfigurationClassParser {
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
invokeAwareMethods(selector);
if (!deferred && selector instanceof DeferredImportSelector) {
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false, false);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
@@ -474,7 +479,7 @@ class ConfigurationClassParser {
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as a @Configuration class
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,9 +26,6 @@ import org.springframework.context.weaving.DefaultContextLoadTimeWeaver;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.util.Assert;
import static org.springframework.context.weaving.AspectJWeavingEnabler.*;
/**
* {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean.
@@ -47,7 +44,6 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
private AnnotationAttributes enableLTW;
@Autowired(required=false)
private LoadTimeWeavingConfigurer ltwConfigurer;
private ClassLoader beanClassLoader;
@@ -56,8 +52,15 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableLTW = AnnotationConfigUtils.attributesFor(importMetadata, EnableLoadTimeWeaving.class);
Assert.notNull(this.enableLTW,
"@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
if (this.enableLTW == null) {
throw new IllegalArgumentException(
"@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
}
}
@Autowired(required = false)
public void setLoadTimeWeavingConfigurer(LoadTimeWeavingConfigurer ltwConfigurer) {
this.ltwConfigurer = ltwConfigurer;
}
@Override
@@ -66,7 +69,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
}
@Bean(name=ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
@Bean(name = ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public LoadTimeWeaver loadTimeWeaver() {
LoadTimeWeaver loadTimeWeaver = null;
@@ -87,7 +90,7 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
// AJ weaving is disabled -> do nothing
break;
case AUTODETECT:
if (this.beanClassLoader.getResource(ASPECTJ_AOP_XML_RESOURCE) == null) {
if (this.beanClassLoader.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) == null) {
// No aop.xml present on the classpath -> treat as 'disabled'
break;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
private static final String MBEAN_EXPORTER_BEAN_NAME = "mbeanExporter";
private AnnotationAttributes attributes;
private AnnotationAttributes enableMBeanExport;
private Environment environment;
@@ -61,8 +61,8 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
Map<String, Object> map = importMetadata.getAnnotationAttributes(EnableMBeanExport.class.getName());
this.attributes = AnnotationAttributes.fromMap(map);
if (this.attributes == null) {
this.enableMBeanExport = AnnotationAttributes.fromMap(map);
if (this.enableMBeanExport == null) {
throw new IllegalArgumentException(
"@EnableMBeanExport is not present on importing class " + importMetadata.getClassName());
}
@@ -90,7 +90,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
}
private void setupDomain(AnnotationMBeanExporter exporter) {
String defaultDomain = this.attributes.getString("defaultDomain");
String defaultDomain = this.enableMBeanExport.getString("defaultDomain");
if (defaultDomain != null && this.environment != null) {
defaultDomain = this.environment.resolvePlaceholders(defaultDomain);
}
@@ -100,7 +100,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
}
private void setupServer(AnnotationMBeanExporter exporter) {
String server = this.attributes.getString("server");
String server = this.enableMBeanExport.getString("server");
if (server != null && this.environment != null) {
server = this.environment.resolvePlaceholders(server);
}
@@ -116,7 +116,7 @@ public class MBeanExportConfiguration implements ImportAware, EnvironmentAware,
}
private void setupRegistrationPolicy(AnnotationMBeanExporter exporter) {
RegistrationPolicy registrationPolicy = this.attributes.getEnum("registration");
RegistrationPolicy registrationPolicy = this.enableMBeanExport.getEnum("registration");
exporter.setRegistrationPolicy(registrationPolicy);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,16 +28,16 @@ import org.springframework.beans.factory.config.BeanDefinition;
* Indicates the 'role' hint for a given bean.
*
* <p>May be used on any class directly or indirectly annotated with
* {@link org.springframework.stereotype.Component} or on methods annotated with
* {@link Bean}.
* {@link org.springframework.stereotype.Component} or on methods
* annotated with {@link Bean}.
*
* <p>If this annotation is not present on a Component or Bean definition, the
* default value of {@link BeanDefinition#ROLE_APPLICATION} will apply.
* <p>If this annotation is not present on a Component or Bean definition,
* the default value of {@link BeanDefinition#ROLE_APPLICATION} will apply.
*
* <p>If Role is present on a {@link Configuration @Configuration} class, this
* indicates the role of the configuration class bean definition and does not
* cascade to all @{@code Bean} methods defined within. This behavior is
* different than that of the @{@link Lazy} annotation, for example.
* <p>If Role is present on a {@link Configuration @Configuration} class,
* this indicates the role of the configuration class bean definition and
* does not cascade to all @{@code Bean} methods defined within. This behavior
* is different than that of the @{@link Lazy} annotation, for example.
*
* @author Chris Beams
* @since 3.1
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.OrderComparator;
@@ -65,47 +66,8 @@ public abstract class AbstractApplicationEventMulticaster
private BeanFactory beanFactory;
private Object retrievalMutex = this.defaultRetriever;
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListenerBean(String listenerBeanName) {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeAllListeners() {
synchronized (this.defaultRetriever) {
this.defaultRetriever.applicationListeners.clear();
this.defaultRetriever.applicationListenerBeans.clear();
this.retrieverCache.clear();
}
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
@@ -118,6 +80,9 @@ public abstract class AbstractApplicationEventMulticaster
if (this.beanClassLoader == null && beanFactory instanceof ConfigurableBeanFactory) {
this.beanClassLoader = ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader();
}
if (beanFactory instanceof AbstractBeanFactory) {
this.retrievalMutex = ((AbstractBeanFactory) beanFactory).getSingletonMutex();
}
}
private BeanFactory getBeanFactory() {
@@ -129,13 +94,55 @@ public abstract class AbstractApplicationEventMulticaster
}
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
@Override
public void addApplicationListenerBean(String listenerBeanName) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListenerBeans.add(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListenerBean(String listenerBeanName) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListenerBeans.remove(listenerBeanName);
this.retrieverCache.clear();
}
}
@Override
public void removeAllListeners() {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.clear();
this.defaultRetriever.applicationListenerBeans.clear();
this.retrieverCache.clear();
}
}
/**
* Return a Collection containing all ApplicationListeners.
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener<?>> getApplicationListeners() {
synchronized (this.defaultRetriever) {
synchronized (this.retrievalMutex) {
return this.defaultRetriever.getApplicationListeners();
}
}
@@ -163,13 +170,14 @@ public abstract class AbstractApplicationEventMulticaster
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.defaultRetriever) {
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(event, sourceType, retriever);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(event, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
@@ -193,7 +201,7 @@ public abstract class AbstractApplicationEventMulticaster
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -152,7 +152,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* Set the default charset to use for parsing resource bundle files.
* <p>Default is none, using the {@code java.util.ResourceBundle}
* default encoding: ISO-8859-1.
* and more flexibility in setting of an encoding per file.
* @since 3.1.3
*/
public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
@@ -167,6 +167,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* {@code java.util.ResourceBundle}. However, this is often not desirable
* in an application server environment, where the system Locale is not relevant
* to the application at all: Set this flag to "false" in such a scenario.
* @since 3.1.3
*/
public void setFallbackToSystemLocale(boolean fallbackToSystemLocale) {
this.fallbackToSystemLocale = fallbackToSystemLocale;
@@ -188,6 +189,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* Consider {@link ReloadableResourceBundleMessageSource} in combination
* with resource bundle files in a non-classpath location.
* </ul>
* @since 3.1.3
*/
public void setCacheSeconds(int cacheSeconds) {
this.cacheMillis = (cacheSeconds * 1000);
@@ -304,7 +306,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* @param locale the Locale to look for
* @return the corresponding ResourceBundle
* @throws MissingResourceException if no matching bundle could be found
* @see java.util.ResourceBundle#getBundle(String, java.util.Locale, ClassLoader)
* @see java.util.ResourceBundle#getBundle(String, Locale, ClassLoader)
* @see #getBundleClassLoader()
*/
protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
@@ -394,6 +396,8 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
// Special handling of default encoding
if (format.equals("java.properties")) {
String bundleName = toBundleName(baseName, locale);
final String resourceName = toResourceName(bundleName, "properties");
@@ -441,6 +445,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
}
}
else {
// Delegate handling of "java.class" format to standard Control
return super.newBundle(baseName, locale, format, loader, reload);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.format.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -28,19 +29,19 @@ import java.lang.annotation.Target;
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long},
* Joda-Time value types; and as of Spring 4 and JDK 8, to JSR-310 <code>java.time</code> types too.
*
* <p>For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
* <p>For style-based formatting, set the {@link #style} attribute to be the style pattern code.
* The first character of the code is the date style, and the second character is the time style.
* Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
* A date or time may be omitted by specifying the style character '-'.
*
* <p>For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format,
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern()} attribute to be the
* <p>For ISO-based formatting, set the {@link #iso} attribute to be the desired {@link ISO} format,
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern} attribute to be the
* DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
*
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
* (the one most convenient one for your formatting needs).
* (the most convenient one for your formatting needs).
* When the pattern attribute is specified, it takes precedence over both the style and ISO attribute.
* When the iso attribute is specified, if takes precedence over the style attribute.
* When the iso attribute is specified, it takes precedence over the style attribute.
* When no annotation attributes are specified, the default format applied is style-based
* with a style code of 'SS' (short date, short time).
*
@@ -49,8 +50,9 @@ import java.lang.annotation.Target;
* @since 3.0
* @see org.joda.time.format.DateTimeFormat
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface DateTimeFormat {
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.format.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -23,23 +24,27 @@ import java.lang.annotation.Target;
/**
* Declares that a field should be formatted as a number.
* Supports formatting by style or custom pattern string.
*
* <p>Supports formatting by style or custom pattern string.
* Can be applied to any JDK {@code java.lang.Number} type.
*
* <p>For style-based formatting, set the {@link #style()} attribute to be the desired {@link Style}.
* For custom formatting, set the {@link #pattern()} attribute to be the number pattern, such as {@code #, ###.##}.
* <p>For style-based formatting, set the {@link #style} attribute to be the
* desired {@link Style}. For custom formatting, set the {@link #pattern}
* attribute to be the number pattern, such as {@code #, ###.##}.
*
* <p>Each attribute is mutually exclusive, so only set one attribute per annotation instance
* (the one most convenient one for your formatting needs). When the pattern attribute is specified,
* it takes precedence over the style attribute. When no annotation attributes are specified,
* <p>Each attribute is mutually exclusive, so only set one attribute per
* annotation instance (the one most convenient one for your formatting needs).
* When the {@link #pattern} attribute is specified, it takes precedence over
* the {@link #style} attribute. When no annotation attributes are specified,
* the default format applied is style-based with a style of {@link Style#NUMBER}.
*
* @author Keith Donald
* @since 3.0
* @see java.text.NumberFormat
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface NumberFormat {
/**
@@ -161,7 +161,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
private boolean exposeManagedResourceClassLoader = true;
/** A set of bean names that should be excluded from autodetection */
private Set<String> excludedBeans;
private Set<String> excludedBeans = new HashSet<String>();
/** The MBeanExporterListeners registered with this exporter. */
private MBeanExporterListener[] listeners;
@@ -314,7 +314,18 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
* Set the list of names for beans that should be excluded from autodetection.
*/
public void setExcludedBeans(String... excludedBeans) {
this.excludedBeans = (excludedBeans != null ? new HashSet<String>(Arrays.asList(excludedBeans)) : null);
this.excludedBeans.clear();
if (excludedBeans != null) {
this.excludedBeans.addAll(Arrays.asList(excludedBeans));
}
}
/**
* Add the name of bean that should be excluded from autodetection.
*/
public void addExcludedBean(String excludedBean) {
Assert.notNull(excludedBean, "ExcludedBean must not be null");
this.excludedBeans.add(excludedBean);
}
/**
@@ -922,10 +933,9 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo
* Indicates whether or not a particular bean name is present in the excluded beans list.
*/
private boolean isExcluded(String beanName) {
return (this.excludedBeans != null &&
(this.excludedBeans.contains(beanName) ||
(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length())))));
return (this.excludedBeans.contains(beanName) ||
(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()))));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
@@ -43,6 +42,7 @@ public abstract class AbstractAsyncConfiguration implements ImportAware {
protected AnnotationAttributes enableAsync;
protected Executor executor;
protected AsyncUncaughtExceptionHandler exceptionHandler;
@@ -50,14 +50,16 @@ public abstract class AbstractAsyncConfiguration implements ImportAware {
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableAsync = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableAsync.class.getName(), false));
Assert.notNull(this.enableAsync,
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
if (this.enableAsync == null) {
throw new IllegalArgumentException(
"@EnableAsync is not present on importing class " + importMetadata.getClassName());
}
}
/**
* Collect any {@link AsyncConfigurer} beans through autowiring.
*/
@Autowired(required=false)
@Autowired(required = false)
void setConfigurers(Collection<AsyncConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
@@ -44,7 +44,7 @@ public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
Class<? extends Annotation> customAsyncAnnotation = enableAsync.getClass("annotation");
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +39,10 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.TaskScheduler;
@@ -61,12 +64,12 @@ import org.springframework.util.StringValueResolver;
* to the "fixedRate", "fixedDelay", or "cron" expression provided via the annotation.
*
* <p>This post-processor is automatically registered by Spring's
* {@code <task:annotation-driven>} XML element, and also by the @{@link EnableScheduling}
* annotation.
* {@code <task:annotation-driven>} XML element, and also by the
* @{@link EnableScheduling} annotation.
*
* <p>Auto-detects any {@link SchedulingConfigurer} instances in the container,
* allowing for customization of the scheduler to be used or for fine-grained control
* over task registration (e.g. registration of {@link Trigger} tasks.
* <p>Autodetects any {@link SchedulingConfigurer} instances in the container,
* allowing for customization of the scheduler to be used or for fine-grained
* control over task registration (e.g. registration of {@link Trigger} tasks.
* See the @{@link EnableScheduling} javadocs for complete usage details.
*
* @author Mark Fisher
@@ -80,7 +83,8 @@ import org.springframework.util.StringValueResolver;
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
*/
public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered,
EmbeddedValueResolverAware, BeanFactoryAware, SmartInitializingSingleton, DisposableBean {
EmbeddedValueResolverAware, BeanFactoryAware, ApplicationContextAware,
SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
@@ -90,6 +94,8 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();
private final Set<Class<?>> nonAnnotatedClasses =
@@ -126,10 +132,13 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
}
/**
* @deprecated as of Spring 4.1, in favor of {@link #setBeanFactory}
* Setting an {@link ApplicationContext} is optional: If set, registered
* tasks will be activated in the {@link ContextRefreshedEvent} phase;
* if not set, it will happen at {@link #afterSingletonsInstantiated} time.
*/
@Deprecated
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
if (this.beanFactory == null) {
this.beanFactory = applicationContext;
}
@@ -138,6 +147,23 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
@Override
public void afterSingletonsInstantiated() {
if (this.applicationContext == null) {
// Not running in an ApplicationContext -> register tasks early...
finishRegistration();
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() == this.applicationContext) {
// Running in an ApplicationContext -> register tasks this late...
// giving other ContextRefreshedEvent listeners a chance to perform
// their work at the same time (e.g. Spring Batch's job registration).
finishRegistration();
}
}
private void finishRegistration() {
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
@@ -190,9 +216,9 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName) {
if (!this.nonAnnotatedClasses.contains(bean.getClass())) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
if (!this.nonAnnotatedClasses.contains(targetClass)) {
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
Class<?> targetClass = AopUtils.getTargetClass(bean);
ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
@@ -204,7 +230,7 @@ public class ScheduledAnnotationBeanPostProcessor implements BeanPostProcessor,
}
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(bean.getClass());
this.nonAnnotatedClasses.add(targetClass);
if (logger.isDebugEnabled()) {
logger.debug("No @Scheduled annotations found on bean class: " + bean.getClass());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,11 +32,14 @@ import org.springframework.jndi.JndiTemplate;
* for JSR-236's "java:comp/DefaultManagedThreadFactory" in a Java EE 7 environment,
* falling back to the local {@link CustomizableThreadFactory} setup if not found.
*
* <p>This is a convenient way to use managed threads when running in a Java EE 7 environment,
* simply using regular local threads otherwise - without conditional setup (like profiles).
* <p>This is a convenient way to use managed threads when running in a Java EE 7
* environment, simply using regular local threads otherwise - without conditional
* setup (i.e. without profiles).
*
* <p>Note: This class is not strictly JSR-236 based; it can work with any regular
* {@link java.util.concurrent.ThreadFactory} that can be found in JNDI.
* {@link java.util.concurrent.ThreadFactory} that can be found in JNDI. Therefore,
* the default JNDI name "java:comp/DefaultManagedThreadFactory" can be customized
* through the {@link #setJndiName "jndiName"} bean property.
*
* @author Juergen Hoeller
* @since 4.0
@@ -50,7 +53,7 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory
private String jndiName = "java:comp/DefaultManagedThreadFactory";
private ThreadFactory threadFactory = this;
private ThreadFactory threadFactory;
/**
@@ -98,12 +101,10 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory
}
catch (NamingException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to find [java:comp/DefaultManagedThreadFactory] in JNDI", ex);
}
if (logger.isInfoEnabled()) {
logger.info("Could not find default managed thread factory in JNDI - " +
"proceeding with default local thread factory");
logger.debug("Failed to retrieve [" + this.jndiName + "] from JNDI", ex);
}
logger.info("Could not find default managed thread factory in JNDI - " +
"proceeding with default local thread factory");
}
}
}
@@ -111,7 +112,12 @@ public class DefaultManagedAwareThreadFactory extends CustomizableThreadFactory
@Override
public Thread newThread(Runnable runnable) {
return this.threadFactory.newThread(runnable);
if (this.threadFactory != null) {
return this.threadFactory.newThread(runnable);
}
else {
return super.newThread(runnable);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
@@ -39,6 +40,7 @@ import static org.junit.Assert.*;
* Test for {@link Conditional} beans.
*
* @author Phillip Webb
* @author Juergen Hoeller
*/
@SuppressWarnings("resource")
public class ConfigurationClassWithConditionTests {
@@ -117,6 +119,29 @@ public class ConfigurationClassWithConditionTests {
ctx.refresh();
}
@Test
public void conditionOnOverriddenMethodHonored() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanSkipped.class);
assertEquals(0, context.getBeansOfType(ExampleBean.class).size());
}
@Test
public void noConditionOnOverriddenMethodHonored() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanReactivated.class);
Map<String, ExampleBean> beans = context.getBeansOfType(ExampleBean.class);
assertEquals(1, beans.size());
assertEquals("baz", beans.keySet().iterator().next());
}
@Test
public void configWithAlternativeBeans() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithAlternativeBeans.class);
Map<String, ExampleBean> beans = context.getBeansOfType(ExampleBean.class);
assertEquals(1, beans.size());
assertEquals("baz", beans.keySet().iterator().next());
}
@Configuration
static class BeanOneConfiguration {
@Bean
@@ -197,12 +222,21 @@ public class ConfigurationClassWithConditionTests {
}
static class NeverCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
static class AlwaysCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
@Component
@Never
static class NonConfigurationClass {
@@ -261,4 +295,48 @@ public class ConfigurationClassWithConditionTests {
static class ExampleBean {
}
@Configuration
static class ConfigWithBeanActive {
@Bean
public ExampleBean baz() {
return new ExampleBean();
}
}
static class ConfigWithBeanSkipped extends ConfigWithBeanActive {
@Override
@Bean
@Conditional(NeverCondition.class)
public ExampleBean baz() {
return new ExampleBean();
}
}
static class ConfigWithBeanReactivated extends ConfigWithBeanSkipped {
@Override
@Bean
public ExampleBean baz() {
return new ExampleBean();
}
}
@Configuration
static class ConfigWithAlternativeBeans {
@Bean(name = "baz")
@Conditional(AlwaysCondition.class)
public ExampleBean baz1() {
return new ExampleBean();
}
@Bean(name = "baz")
@Conditional(NeverCondition.class)
public ExampleBean baz2() {
return new ExampleBean();
}
}
}
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="foo" class="java.lang.String">
<constructor-arg value="hello"/>
<qualifier value="foo" />
</bean>
</beans>
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import java.util.Properties;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -48,6 +49,7 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.Formatter;
import org.springframework.format.Printer;
import org.springframework.format.annotation.NumberFormat;
import org.springframework.format.datetime.joda.DateTimeParser;
import org.springframework.format.datetime.joda.JodaDateTimeFormatAnnotationFormatterFactory;
import org.springframework.format.datetime.joda.ReadablePartialPrinter;
@@ -58,6 +60,8 @@ import static org.junit.Assert.*;
/**
* @author Keith Donald
* @author Juergen Hoeller
* @author Kazuki Shimizu
* @author Sam Brannen
*/
public class FormattingConversionServiceTests {
@@ -101,6 +105,7 @@ public class FormattingConversionServiceTests {
}
@Test
@SuppressWarnings("resource")
public void testFormatFieldForValueInjection() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.registerBeanDefinition("valueBean", new RootBeanDefinition(ValueBean.class));
@@ -111,6 +116,7 @@ public class FormattingConversionServiceTests {
}
@Test
@SuppressWarnings("resource")
public void testFormatFieldForValueInjectionUsingMetaAnnotations() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
RootBeanDefinition bd = new RootBeanDefinition(MetaValueBean.class);
@@ -120,12 +126,15 @@ public class FormattingConversionServiceTests {
ac.registerBeanDefinition("ppc", new RootBeanDefinition(PropertyPlaceholderConfigurer.class));
ac.refresh();
System.setProperty("myDate", "10-31-09");
System.setProperty("myNumber", "99.99%");
try {
MetaValueBean valueBean = ac.getBean(MetaValueBean.class);
assertEquals(new LocalDate(2009, 10, 31), new LocalDate(valueBean.date));
assertEquals(Double.valueOf(0.9999), valueBean.number);
}
finally {
System.clearProperty("myDate");
System.clearProperty("myNumber");
}
}
@@ -142,6 +151,7 @@ public class FormattingConversionServiceTests {
}
@Test
@SuppressWarnings("resource")
public void testFormatFieldForAnnotationWithPlaceholders() throws Exception {
GenericApplicationContext context = new GenericApplicationContext();
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -157,6 +167,7 @@ public class FormattingConversionServiceTests {
}
@Test
@SuppressWarnings("resource")
public void testFormatFieldForAnnotationWithPlaceholdersAndFactoryBean() throws Exception {
GenericApplicationContext context = new GenericApplicationContext();
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
@@ -336,13 +347,14 @@ public class FormattingConversionServiceTests {
public Date date;
}
public static class MetaValueBean {
@MyDateAnn
public Date date;
}
@MyNumberAnn
public Double number;
}
@Value("${myDate}")
@org.springframework.format.annotation.DateTimeFormat(pattern="MM-d-yy")
@@ -350,6 +362,11 @@ public class FormattingConversionServiceTests {
public static @interface MyDateAnn {
}
@Value("${myNumber}")
@NumberFormat(style = NumberFormat.Style.PERCENT)
@Retention(RetentionPolicy.RUNTIME)
public static @interface MyNumberAnn {
}
public static class Model {
@@ -368,7 +385,6 @@ public class FormattingConversionServiceTests {
}
}
public static class ModelWithPlaceholders {
@org.springframework.format.annotation.DateTimeFormat(style="${dateStyle}")
@@ -386,13 +402,11 @@ public class FormattingConversionServiceTests {
}
}
@org.springframework.format.annotation.DateTimeFormat(pattern="${datePattern}")
@Retention(RetentionPolicy.RUNTIME)
public static @interface MyDatePattern {
}
public static class NullReturningFormatter implements Formatter<Integer> {
@Override
@@ -407,12 +421,10 @@ public class FormattingConversionServiceTests {
}
@SuppressWarnings("serial")
public static class MyDate extends Date {
}
private static class ModelWithSubclassField {
@org.springframework.format.annotation.DateTimeFormat(style = "S-")
@@ -17,6 +17,8 @@
package org.springframework.jmx.export;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -643,6 +645,28 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
ObjectNameManager.getInstance(objectName2));
}
@Test
public void testIgnoreBeanName() throws MalformedObjectNameException {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
String firstBeanName = "spring:type=TestBean";
factory.registerSingleton(firstBeanName, new TestBean("test"));
String secondBeanName = "spring:type=TestBean2";
factory.registerSingleton(secondBeanName, new TestBean("test2"));
MBeanExporter exporter = new MBeanExporter();
exporter.setServer(getServer());
exporter.setAssembler(new NamedBeanAutodetectCapableMBeanInfoAssemblerStub(firstBeanName, secondBeanName));
exporter.setBeanFactory(factory);
exporter.setAutodetectMode(MBeanExporter.AUTODETECT_ALL);
exporter.addExcludedBean(secondBeanName);
start(exporter);
assertIsRegistered("Bean not autodetected in (AUTODETECT_ALL) mode",
ObjectNameManager.getInstance(firstBeanName));
assertIsNotRegistered("Bean should have been excluded",
ObjectNameManager.getInstance(secondBeanName));
}
private ConfigurableApplicationContext load(String context) {
return new ClassPathXmlApplicationContext(context, getClass());
}
@@ -763,15 +787,15 @@ public final class MBeanExporterTests extends AbstractMBeanServerTests {
private static final class NamedBeanAutodetectCapableMBeanInfoAssemblerStub extends
SimpleReflectiveMBeanInfoAssembler implements AutodetectCapableMBeanInfoAssembler {
private String namedBean;
private Collection<String> namedBeans;
public NamedBeanAutodetectCapableMBeanInfoAssemblerStub(String namedBean) {
this.namedBean = namedBean;
public NamedBeanAutodetectCapableMBeanInfoAssemblerStub(String... namedBeans) {
this.namedBeans = Arrays.asList(namedBeans);
}
@Override
public boolean includeBean(Class<?> beanClass, String beanName) {
return this.namedBean.equals(beanName);
return this.namedBeans.contains(beanName);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,15 +25,20 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
import static org.junit.Assert.*;
@@ -106,10 +111,32 @@ public class AsyncAnnotationBeanPostProcessorTests {
@Test
public void handleExceptionWithFuture() {
ConfigurableApplicationContext context = initContext(
new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
ConfigurableApplicationContext context =
new AnnotationConfigApplicationContext(ConfigWithExceptionHandler.class);
ITestBean testBean = context.getBean("target", ITestBean.class);
final Future<Object> result = testBean.failWithFuture();
TestableAsyncUncaughtExceptionHandler exceptionHandler =
context.getBean("exceptionHandler", TestableAsyncUncaughtExceptionHandler.class);
assertFalse("handler should not have been called yet", exceptionHandler.isCalled());
Future<Object> result = testBean.failWithFuture();
assertFutureWithException(result, exceptionHandler);
}
@Test
public void handleExceptionWithListenableFuture() {
ConfigurableApplicationContext context =
new AnnotationConfigApplicationContext(ConfigWithExceptionHandler.class);
ITestBean testBean = context.getBean("target", ITestBean.class);
TestableAsyncUncaughtExceptionHandler exceptionHandler =
context.getBean("exceptionHandler", TestableAsyncUncaughtExceptionHandler.class);
assertFalse("handler should not have been called yet", exceptionHandler.isCalled());
Future<Object> result = testBean.failWithListenableFuture();
assertFutureWithException(result, exceptionHandler);
}
private void assertFutureWithException(Future<Object> result,
TestableAsyncUncaughtExceptionHandler exceptionHandler) {
try {
result.get();
@@ -121,6 +148,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
// expected
assertEquals("Wrong exception cause", UnsupportedOperationException.class, ex.getCause().getClass());
}
assertFalse("handler should never be called with Future return type", exceptionHandler.isCalled());
}
@Test
@@ -173,7 +201,7 @@ public class AsyncAnnotationBeanPostProcessorTests {
}
private static interface ITestBean {
private interface ITestBean {
Thread getThread();
@@ -181,6 +209,8 @@ public class AsyncAnnotationBeanPostProcessorTests {
Future<Object> failWithFuture();
ListenableFuture<Object> failWithListenableFuture();
void failWithVoid();
void await(long timeout);
@@ -206,11 +236,19 @@ public class AsyncAnnotationBeanPostProcessorTests {
}
@Async
@Override
public Future<Object> failWithFuture() {
throw new UnsupportedOperationException("failWithFuture");
}
@Async
@Override
public ListenableFuture<Object> failWithListenableFuture() {
throw new UnsupportedOperationException("failWithListenableFuture");
}
@Async
@Override
public void failWithVoid() {
throw new UnsupportedOperationException("failWithVoid");
}
@@ -234,4 +272,25 @@ public class AsyncAnnotationBeanPostProcessorTests {
}
}
@Configuration
@EnableAsync
static class ConfigWithExceptionHandler extends AsyncConfigurerSupport {
@Bean
public ITestBean target() {
return new TestBean();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return exceptionHandler();
}
@Bean
public TestableAsyncUncaughtExceptionHandler exceptionHandler() {
return new TestableAsyncUncaughtExceptionHandler();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -309,6 +309,7 @@ public class MethodParameter {
/**
* Return the generic type of the method/constructor parameter.
* @return the parameter type (never {@code null})
* @since 3.0
*/
public Type getGenericParameterType() {
if (this.genericParameterType == null) {
@@ -324,6 +325,12 @@ public class MethodParameter {
return this.genericParameterType;
}
/**
* Return the nested type of the method/constructor parameter.
* @return the parameter type (never {@code null})
* @see #getNestingLevel()
* @since 3.1
*/
public Class<?> getNestedParameterType() {
if (this.nestingLevel > 1) {
Type type = getGenericParameterType();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -122,6 +122,17 @@ public final class ResolvableType implements Serializable {
private ResolvableType[] generics;
/**
* Private constructor used to create a new {@link ResolvableType} for cache key purposes.
*/
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) {
this.type = type;
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
this.componentType = null;
this.resolved = null;
}
/**
* Private constructor used to create a new {@link ResolvableType} for resolution purposes.
*/
@@ -135,17 +146,6 @@ public final class ResolvableType implements Serializable {
this.resolved = resolveClass();
}
/**
* Private constructor used to create a new {@link ResolvableType} for cache key purposes.
*/
private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) {
this.type = type;
this.typeProvider = typeProvider;
this.variableResolver = variableResolver;
this.componentType = null;
this.resolved = null;
}
/**
* Return the underling Java {@link Type} being managed. With the exception of
@@ -156,7 +156,7 @@ public final class ResolvableType implements Serializable {
}
/**
* Return the underlying Java {@link Class} being managed, if available;
* Return the underlying Java {@link Class} being managed, if available;
* otherwise {@code null}.
*/
public Class<?> getRawClass() {
@@ -598,7 +598,7 @@ public final class ResolvableType implements Serializable {
return EMPTY_TYPES_ARRAY;
}
if (this.generics == null) {
if (this.type instanceof Class<?>) {
if (this.type instanceof Class) {
Class<?> typeClass = (Class<?>) this.type;
this.generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
}
@@ -691,7 +691,7 @@ public final class ResolvableType implements Serializable {
}
private Class<?> resolveClass() {
if (this.type instanceof Class<?> || this.type == null) {
if (this.type instanceof Class || this.type == null) {
return (Class<?>) this.type;
}
if (this.type instanceof GenericArrayType) {
@@ -762,6 +762,66 @@ public final class ResolvableType implements Serializable {
return null;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ResolvableType)) {
return false;
}
ResolvableType otherType = (ResolvableType) other;
return (ObjectUtils.nullSafeEquals(this.type, otherType.type) &&
ObjectUtils.nullSafeEquals(getSource(), otherType.getSource()) &&
variableResolverSourceEquals(otherType.variableResolver) &&
ObjectUtils.nullSafeEquals(this.componentType, otherType.componentType));
}
@Override
public int hashCode() {
int hashCode = ObjectUtils.nullSafeHashCode(this.type);
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(getSource());
hashCode = 31 * hashCode + variableResolverSourceHashCode();
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.componentType);
return hashCode;
}
private boolean variableResolverSourceEquals(VariableResolver other) {
if (this.variableResolver == null) {
return (other == null);
}
if (other == null) {
return false;
}
return ObjectUtils.nullSafeEquals(this.variableResolver.getSource(), other.getSource());
}
private int variableResolverSourceHashCode() {
int hashCode = 0;
if (this.variableResolver != null) {
hashCode = ObjectUtils.nullSafeHashCode(this.variableResolver.getSource());
}
return hashCode;
}
/**
* Adapts this {@link ResolvableType} to a {@link VariableResolver}.
*/
VariableResolver asVariableResolver() {
if (this == NONE) {
return null;
}
return new DefaultVariableResolver();
}
/**
* Custom serialization support for {@link #NONE}.
*/
private Object readResolve() throws ObjectStreamException {
return (this.type == null ? NONE : this);
}
/**
* Return a String representation of this type in its fully resolved form
* (including any generic parameters).
@@ -791,76 +851,13 @@ public final class ResolvableType implements Serializable {
return result.toString();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ResolvableType)) {
return false;
}
ResolvableType other = (ResolvableType) obj;
return (ObjectUtils.nullSafeEquals(this.type, other.type) &&
ObjectUtils.nullSafeEquals(getSource(), other.getSource()) &&
variableResolverSourceEquals(other.variableResolver) &&
ObjectUtils.nullSafeEquals(this.componentType, other.componentType));
}
@Override
public int hashCode() {
int hashCode = ObjectUtils.nullSafeHashCode(this.type);
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(getSource());
hashCode = 31 * hashCode + variableResolverSourceHashCode();
hashCode = 31 * hashCode + ObjectUtils.nullSafeHashCode(this.componentType);
return hashCode;
}
// Factory methods
/**
* Custom serialization support for {@link #NONE}.
*/
private Object readResolve() throws ObjectStreamException {
return (this.type == null ? NONE : this);
}
/**
* Adapts this {@link ResolvableType} to a {@link VariableResolver}.
*/
VariableResolver asVariableResolver() {
if (this == NONE) {
return null;
}
return new DefaultVariableResolver();
}
private boolean variableResolverSourceEquals(VariableResolver other) {
if (this.variableResolver == null) {
return (other == null);
}
if (other == null) {
return false;
}
return ObjectUtils.nullSafeEquals(this.variableResolver.getSource(), other.getSource());
}
private int variableResolverSourceHashCode() {
int hashCode = 0;
if (this.variableResolver != null) {
hashCode = ObjectUtils.nullSafeHashCode(this.variableResolver.getSource());
}
return hashCode;
}
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) {
ResolvableType[] result = new ResolvableType[types.length];
for (int i = 0; i < types.length; i++) {
result[i] = forType(types[i], owner);
}
return result;
}
/**
* Return a {@link ResolvableType} for the specified {@link Class}. For example
* {@code ResolvableType.forClass(MyArrayList.class)}.
* Return a {@link ResolvableType} for the specified {@link Class},
* using the full generic type information for assignability checks.
* For example: {@code ResolvableType.forClass(MyArrayList.class)}.
* @param sourceClass the source class (must not be {@code null}
* @return a {@link ResolvableType} for the specified class
* @see #forClass(Class, Class)
@@ -872,9 +869,9 @@ public final class ResolvableType implements Serializable {
}
/**
* Return a {@link ResolvableType} for the specified {@link Class} with a given
* implementation. For example
* {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
* Return a {@link ResolvableType} for the specified {@link Class}
* with a given implementation.
* For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}.
* @param sourceClass the source class (must not be {@code null}
* @param implementationClass the implementation class
* @return a {@link ResolvableType} for the specified class backed by the given
@@ -888,6 +885,38 @@ public final class ResolvableType implements Serializable {
return (asType == NONE ? forType(sourceClass) : asType);
}
/**
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
* @param sourceClass the source class
* @param generics the generics of the class
* @return a {@link ResolvableType} for the specific class and generics
* @see #forClassWithGenerics(Class, ResolvableType...)
*/
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, Class<?>... generics) {
Assert.notNull(sourceClass, "Source class must not be null");
Assert.notNull(generics, "Generics must not be null");
ResolvableType[] resolvableGenerics = new ResolvableType[generics.length];
for (int i = 0; i < generics.length; i++) {
resolvableGenerics[i] = forClass(generics[i]);
}
return forClassWithGenerics(sourceClass, resolvableGenerics);
}
/**
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
* @param sourceClass the source class
* @param generics the generics of the class
* @return a {@link ResolvableType} for the specific class and generics
* @see #forClassWithGenerics(Class, Class...)
*/
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, ResolvableType... generics) {
Assert.notNull(sourceClass, "Source class must not be null");
Assert.notNull(generics, "Generics must not be null");
TypeVariable<?>[] variables = sourceClass.getTypeParameters();
Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified");
return forType(sourceClass, new TypeVariablesVariableResolver(variables, generics));
}
/**
* Return a {@link ResolvableType} for the specified {@link Field}.
* @param field the source field
@@ -1092,9 +1121,8 @@ public final class ResolvableType implements Serializable {
public static ResolvableType forMethodParameter(MethodParameter methodParameter, Type targetType) {
Assert.notNull(methodParameter, "MethodParameter must not be null");
ResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass());
return forType(targetType, new MethodParameterTypeProvider(methodParameter),
owner.asVariableResolver()).getNested(methodParameter.getNestingLevel(),
methodParameter.typeIndexesPerLevel);
return forType(targetType, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).
getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel);
}
/**
@@ -1103,40 +1131,17 @@ public final class ResolvableType implements Serializable {
* @return a {@link ResolvableType} as an array of the specified component type
*/
public static ResolvableType forArrayComponent(ResolvableType componentType) {
Assert.notNull(componentType, "ComponentType must not be null");
Assert.notNull(componentType, "componentType must not be null");
Class<?> arrayClass = Array.newInstance(componentType.resolve(), 0).getClass();
return new ResolvableType(arrayClass, null, null, componentType);
}
/**
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
* @param sourceClass the source class
* @param generics the generics of the class
* @return a {@link ResolvableType} for the specific class and generics
* @see #forClassWithGenerics(Class, ResolvableType...)
*/
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, Class<?>... generics) {
Assert.notNull(sourceClass, "Source class must not be null");
Assert.notNull(generics, "Generics must not be null");
ResolvableType[] resolvableGenerics = new ResolvableType[generics.length];
for (int i = 0; i < generics.length; i++) {
resolvableGenerics[i] = forClass(generics[i]);
private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) {
ResolvableType[] result = new ResolvableType[types.length];
for (int i = 0; i < types.length; i++) {
result[i] = forType(types[i], owner);
}
return forClassWithGenerics(sourceClass, resolvableGenerics);
}
/**
* Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics.
* @param sourceClass the source class
* @param generics the generics of the class
* @return a {@link ResolvableType} for the specific class and generics
* @see #forClassWithGenerics(Class, Class...)
*/
public static ResolvableType forClassWithGenerics(Class<?> sourceClass, ResolvableType... generics) {
Assert.notNull(sourceClass, "Source class must not be null");
Assert.notNull(generics, "Generics must not be null");
TypeVariable<?>[] typeVariables = sourceClass.getTypeParameters();
return forType(sourceClass, new TypeVariablesVariableResolver(typeVariables, generics));
return result;
}
/**
@@ -1198,7 +1203,7 @@ public final class ResolvableType implements Serializable {
// For simple Class references, build the wrapper right away -
// no expensive resolution necessary, so not worth caching...
if (type instanceof Class<?>) {
if (type instanceof Class) {
return new ResolvableType(type, typeProvider, variableResolver, null);
}
@@ -1250,20 +1255,19 @@ public final class ResolvableType implements Serializable {
@SuppressWarnings("serial")
private static class TypeVariablesVariableResolver implements VariableResolver {
private final TypeVariable<?>[] typeVariables;
private final TypeVariable<?>[] variables;
private final ResolvableType[] generics;
public TypeVariablesVariableResolver(TypeVariable<?>[] typeVariables, ResolvableType[] generics) {
Assert.isTrue(typeVariables.length == generics.length, "Mismatched number of generics specified");
this.typeVariables = typeVariables;
public TypeVariablesVariableResolver(TypeVariable<?>[] variables, ResolvableType[] generics) {
this.variables = variables;
this.generics = generics;
}
@Override
public ResolvableType resolveVariable(TypeVariable<?> variable) {
for (int i = 0; i < this.typeVariables.length; i++) {
if (SerializableTypeWrapper.unwrap(this.typeVariables[i]).equals(
for (int i = 0; i < this.variables.length; i++) {
if (SerializableTypeWrapper.unwrap(this.variables[i]).equals(
SerializableTypeWrapper.unwrap(variable))) {
return this.generics[i];
}
@@ -35,6 +35,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
* General utility methods for working with annotations, handling bridge methods
@@ -654,6 +655,9 @@ public abstract class AnnotationUtils {
* @see #getValue(Annotation)
*/
public static Object getValue(Annotation annotation, String attributeName) {
if (annotation == null || !StringUtils.hasLength(attributeName)) {
return null;
}
try {
Method method = annotation.annotationType().getDeclaredMethod(attributeName);
ReflectionUtils.makeAccessible(method);
@@ -683,6 +687,9 @@ public abstract class AnnotationUtils {
* @see #getDefaultValue(Class, String)
*/
public static Object getDefaultValue(Annotation annotation, String attributeName) {
if (annotation == null) {
return null;
}
return getDefaultValue(annotation.annotationType(), attributeName);
}
@@ -706,6 +713,9 @@ public abstract class AnnotationUtils {
* @see #getDefaultValue(Annotation, String)
*/
public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
if (annotationType == null || !StringUtils.hasLength(attributeName)) {
return null;
}
try {
return annotationType.getDeclaredMethod(attributeName).getDefaultValue();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@ package org.springframework.core.convert.converter;
*
* @author Keith Donald
* @since 3.0
* @see ConditionalConverter
* @param <S> The source type
* @param <T> The target type
*/
@@ -32,8 +31,8 @@ public interface Converter<S, T> {
/**
* Convert the source of type S to target type T.
* @param source the source object to convert, which must be an instance of S
* @return the converted object, which must be an instance of T
* @param source the source object to convert, which must be an instance of S (never {@code null})
* @return the converted object, which must be an instance of T (potentially {@code null})
* @throws IllegalArgumentException if the source could not be converted to the desired target type
*/
T convert(S source);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@ package org.springframework.core.convert.converter;
* @author Keith Donald
* @since 3.0
* @see ConditionalConverter
* @param <S> The source type converters created by this factory can convert from
* @param <R> The target range (or base) type converters created by this factory can convert to;
* @param <S> the source type converters created by this factory can convert from
* @param <R> the target range (or base) type converters created by this factory can convert to;
* for example {@link Number} for a set of number subtypes.
*/
public interface ConverterFactory<S, R> {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,9 +29,9 @@ import org.springframework.util.comparator.ComparableComparator;
* {@code Comparator}.
*
* @author Phillip Webb
* @since 3.2
* @param <S> the source type
* @param <T> the target type
* @since 3.2
*/
public class ConvertingComparator<S, T> implements Comparator<S> {
@@ -42,7 +42,6 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
/**
* Create a new {@link ConvertingComparator} instance.
*
* @param converter the converter
*/
@SuppressWarnings("unchecked")
@@ -52,7 +51,6 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
/**
* Create a new {@link ConvertingComparator} instance.
*
* @param comparator the underlying comparator used to compare the converted values
* @param converter the converter
*/
@@ -65,15 +63,14 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
/**
* Create a new {@link ComparableComparator} instance.
*
* @param comparator the underlying comparator
* @param conversionService the conversion service
* @param targetType the target type
*/
public ConvertingComparator(Comparator<T> comparator,
ConversionService conversionService, Class<? extends T> targetType) {
this(comparator, new ConversionServiceConverter<S, T>(
conversionService, targetType));
public ConvertingComparator(
Comparator<T> comparator, ConversionService conversionService, Class<? extends T> targetType) {
this(comparator, new ConversionServiceConverter<S, T>(conversionService, targetType));
}
@@ -87,14 +84,11 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
/**
* Create a new {@link ConvertingComparator} that compares {@link java.util.Map.Entry
* map * entries} based on their {@link java.util.Map.Entry#getKey() keys}.
*
* @param comparator the underlying comparator used to compare keys
* @return a new {@link ConvertingComparator} instance
*/
public static <K, V> ConvertingComparator<Map.Entry<K, V>, K> mapEntryKeys(
Comparator<K> comparator) {
public static <K, V> ConvertingComparator<Map.Entry<K, V>, K> mapEntryKeys(Comparator<K> comparator) {
return new ConvertingComparator<Map.Entry<K,V>, K>(comparator, new Converter<Map.Entry<K, V>, K>() {
@Override
public K convert(Map.Entry<K, V> source) {
return source.getKey();
@@ -105,14 +99,11 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
/**
* Create a new {@link ConvertingComparator} that compares {@link java.util.Map.Entry
* map entries} based on their {@link java.util.Map.Entry#getValue() values}.
*
* @param comparator the underlying comparator used to compare values
* @return a new {@link ConvertingComparator} instance
*/
public static <K, V> ConvertingComparator<Map.Entry<K, V>, V> mapEntryValues(
Comparator<V> comparator) {
public static <K, V> ConvertingComparator<Map.Entry<K, V>, V> mapEntryValues(Comparator<V> comparator) {
return new ConvertingComparator<Map.Entry<K,V>, V>(comparator, new Converter<Map.Entry<K, V>, V>() {
@Override
public V convert(Map.Entry<K, V> source) {
return source.getValue();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,9 +27,9 @@ import org.springframework.util.Assert;
* <p>This is the most flexible of the Converter SPI interfaces, but also the most complex.
* It is flexible in that a GenericConverter may support converting between multiple source/target
* type pairs (see {@link #getConvertibleTypes()}. In addition, GenericConverter implementations
* have access to source/target {@link TypeDescriptor field context} during the type conversion process.
* This allows for resolving source and target field metadata such as annotations and generics
* information, which can be used influence the conversion logic.
* have access to source/target {@link TypeDescriptor field context} during the type conversion
* process. This allows for resolving source and target field metadata such as annotations and
* generics information, which can be used influence the conversion logic.
*
* <p>This interface should generally not be used when the simpler {@link Converter} or
* {@link ConverterFactory} interfaces are sufficient.
@@ -49,9 +49,8 @@ public interface GenericConverter {
/**
* Return the source and target types which this converter can convert between. Each
* entry is a convertible source-to-target type pair.
* <p>
* For {@link ConditionalConverter conditional} converters this method may return
* {@code null} to indicate all source-to-target pairs should be considered. *
* <p>For {@link ConditionalConverter conditional} converters this method may return
* {@code null} to indicate all source-to-target pairs should be considered.
*/
Set<ConvertiblePair> getConvertibleTypes();
@@ -95,25 +94,25 @@ public interface GenericConverter {
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (obj == null || obj.getClass() != ConvertiblePair.class) {
if (other == null || other.getClass() != ConvertiblePair.class) {
return false;
}
ConvertiblePair other = (ConvertiblePair) obj;
return this.sourceType.equals(other.sourceType) && this.targetType.equals(other.targetType);
ConvertiblePair otherPair = (ConvertiblePair) other;
return (this.sourceType.equals(otherPair.sourceType) && this.targetType.equals(otherPair.targetType));
}
@Override
public int hashCode() {
return this.sourceType.hashCode() * 31 + this.targetType.hashCode();
return (this.sourceType.hashCode() * 31 + this.targetType.hashCode());
}
@Override
public String toString() {
return this.sourceType.getName() + " -> " + this.targetType.getName();
return (this.sourceType.getName() + " -> " + this.targetType.getName());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@ public class GenericConversionService implements ConfigurableConversionService {
new ConcurrentHashMap<ConverterCacheKey, GenericConverter>(64);
// implementing ConverterRegistry
// ConverterRegistry implementation
@Override
public void addConverter(Converter<?, ?> converter) {
@@ -104,7 +104,8 @@ public class GenericConversionService implements ConfigurableConversionService {
@Override
public void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter) {
addConverter(new ConverterAdapter(converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
addConverter(new ConverterAdapter(
converter, ResolvableType.forClass(sourceType), ResolvableType.forClass(targetType)));
}
@Override
@@ -116,7 +117,7 @@ public class GenericConversionService implements ConfigurableConversionService {
@Override
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
ResolvableType[] typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class);
Assert.notNull("Unable to the determine sourceType <S> and targetRangeType R which your " +
Assert.notNull(typeInfo, "Unable to the determine source type <S> and target range type R which your " +
"ConverterFactory<S, R> converts between; declare these generic types.");
addConverter(new ConverterFactoryAdapter(converterFactory,
new ConvertiblePair(typeInfo[0].resolve(), typeInfo[1].resolve())));
@@ -128,7 +129,8 @@ public class GenericConversionService implements ConfigurableConversionService {
invalidateCache();
}
// implementing ConversionService
// ConversionService implementation
@Override
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
@@ -148,17 +150,18 @@ public class GenericConversionService implements ConfigurableConversionService {
}
/**
* Returns true if conversion between the sourceType and targetType can be bypassed.
* More precisely this method will return true if objects of sourceType can be
* Return whether conversion between the sourceType and targetType can be bypassed.
* <p>More precisely, this method will return true if objects of sourceType can be
* converted to the targetType by returning the source object unchanged.
* @param sourceType context about the source type to convert from (may be null if source is null)
* @param sourceType context about the source type to convert from
* (may be {@code null} if source is {@code null})
* @param targetType context about the target type to convert to (required)
* @return true if conversion can be bypassed
* @throws IllegalArgumentException if targetType is null
* @return {@code true} if conversion can be bypassed; {@code false} otherwise
* @throws IllegalArgumentException if targetType is {@code null}
* @since 3.2
*/
public boolean canBypassConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "The targetType to convert to cannot be null");
Assert.notNull(targetType, "targetType to convert to cannot be null");
if (sourceType == null) {
return true;
}
@@ -169,19 +172,19 @@ public class GenericConversionService implements ConfigurableConversionService {
@Override
@SuppressWarnings("unchecked")
public <T> T convert(Object source, Class<T> targetType) {
Assert.notNull(targetType,"The targetType to convert to cannot be null");
Assert.notNull(targetType, "targetType to convert to cannot be null");
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType,"The targetType to convert to cannot be null");
Assert.notNull(targetType, "targetType to convert to cannot be null");
if (sourceType == null) {
Assert.isTrue(source == null, "The source must be [null] if sourceType == [null]");
return handleResult(sourceType, targetType, convertNullSource(sourceType, targetType));
Assert.isTrue(source == null, "source must be [null] if sourceType == [null]");
return handleResult(null, targetType, convertNullSource(null, targetType));
}
if (source != null && !sourceType.getObjectType().isInstance(source)) {
throw new IllegalArgumentException("The source to convert from must be an instance of " +
throw new IllegalArgumentException("source to convert from must be an instance of " +
sourceType + "; instead it was a " + source.getClass().getName());
}
GenericConverter converter = getConverter(sourceType, targetType);
@@ -202,8 +205,8 @@ public class GenericConversionService implements ConfigurableConversionService {
* @param targetType the target type
* @return the converted value
* @throws ConversionException if a conversion exception occurred
* @throws IllegalArgumentException if targetType is null,
* or sourceType is null but source is not null
* @throws IllegalArgumentException if targetType is {@code null},
* or sourceType is {@code null} but source is not {@code null}
*/
public Object convert(Object source, TypeDescriptor targetType) {
return convert(source, TypeDescriptor.forObject(source), targetType);
@@ -218,11 +221,11 @@ public class GenericConversionService implements ConfigurableConversionService {
// Protected template methods
/**
* Template method to convert a null source.
* <p>Default implementation returns {@code null} or the Java 8
* Template method to convert a {@code null} source.
* <p>The default implementation returns {@code null} or the Java 8
* {@link java.util.Optional#empty()} instance if the target type is
* {@code java.uti.Optional}.
* Subclasses may override to return custom null objects for specific target types.
* {@code java.util.Optional}. Subclasses may override this to return
* custom {@code null} objects for specific target types.
* @param sourceType the sourceType to convert from
* @param targetType the targetType to convert to
* @return the converted null object
@@ -239,11 +242,10 @@ public class GenericConversionService implements ConfigurableConversionService {
* First queries this ConversionService's converter cache.
* On a cache miss, then performs an exhaustive search for a matching converter.
* If no converter matches, returns the default converter.
* Subclasses may override.
* @param sourceType the source type to convert from
* @param targetType the target type to convert to
* @return the generic converter that will perform the conversion, or {@code null} if
* no suitable converter was found
* @return the generic converter that will perform the conversion,
* or {@code null} if no suitable converter was found
* @see #getDefaultConverter(TypeDescriptor, TypeDescriptor)
*/
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
@@ -269,9 +271,8 @@ public class GenericConversionService implements ConfigurableConversionService {
/**
* Return the default converter if no converter is found for the given sourceType/targetType pair.
* Returns a NO_OP Converter if the sourceType is assignable to the targetType.
* <p>Returns a NO_OP Converter if the sourceType is assignable to the targetType.
* Returns {@code null} otherwise, indicating no suitable converter could be found.
* Subclasses may override.
* @param sourceType the source type to convert from
* @param targetType the target type to convert to
* @return the default generic converter that will perform the conversion
@@ -280,7 +281,8 @@ public class GenericConversionService implements ConfigurableConversionService {
return (sourceType.isAssignableTo(targetType) ? NO_OP_CONVERTER : null);
}
// internal helpers
// Internal helpers
private ResolvableType[] getRequiredTypeInfo(Object converter, Class<?> genericIfc) {
ResolvableType resolvableType = ResolvableType.forClass(converter.getClass()).as(genericIfc);
@@ -303,7 +305,7 @@ public class GenericConversionService implements ConfigurableConversionService {
private Object handleConverterNotFound(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
return source;
return null;
}
if (sourceType.isAssignableTo(targetType) && targetType.getObjectType().isInstance(source)) {
return source;
@@ -375,7 +377,7 @@ public class GenericConversionService implements ConfigurableConversionService {
@Override
public String toString() {
return this.typeInfo + " : " + this.converter;
return (this.typeInfo + " : " + this.converter);
}
}
@@ -425,7 +427,7 @@ public class GenericConversionService implements ConfigurableConversionService {
@Override
public String toString() {
return this.typeInfo + " : " + this.converterFactory;
return (this.typeInfo + " : " + this.converterFactory);
}
}
@@ -453,20 +455,20 @@ public class GenericConversionService implements ConfigurableConversionService {
return false;
}
ConverterCacheKey otherKey = (ConverterCacheKey) other;
return ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType) &&
ObjectUtils.nullSafeEquals(this.targetType, otherKey.targetType);
return (ObjectUtils.nullSafeEquals(this.sourceType, otherKey.sourceType) &&
ObjectUtils.nullSafeEquals(this.targetType, otherKey.targetType));
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.sourceType) * 29 +
ObjectUtils.nullSafeHashCode(this.targetType);
return (ObjectUtils.nullSafeHashCode(this.sourceType) * 29 +
ObjectUtils.nullSafeHashCode(this.targetType));
}
@Override
public String toString() {
return "ConverterCacheKey [sourceType = " + this.sourceType +
", targetType = " + this.targetType + "]";
return ("ConverterCacheKey [sourceType = " + this.sourceType +
", targetType = " + this.targetType + "]");
}
}
@@ -544,9 +546,9 @@ public class GenericConversionService implements ConfigurableConversionService {
return converter;
}
}
// Check ConditionalGenericConverter that match all types
// Check ConditionalConverters for a dynamic match
for (GenericConverter globalConverter : this.globalConverters) {
if (((ConditionalConverter)globalConverter).matches(sourceType, targetType)) {
if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
return globalConverter;
}
}
@@ -563,6 +565,7 @@ public class GenericConversionService implements ConfigurableConversionService {
Set<Class<?>> visited = new HashSet<Class<?>>(20);
addToClassHierarchy(0, ClassUtils.resolvePrimitiveIfNecessary(type), false, hierarchy, visited);
boolean array = type.isArray();
int i = 0;
while (i < hierarchy.size()) {
Class<?> candidate = hierarchy.get(i);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ import org.springframework.lang.UsesJava8;
* of Optional when known.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 4.1
*/
@UsesJava8
@@ -64,12 +65,15 @@ final class ObjectToOptionalConverter implements ConditionalGenericConverter {
if (source == null) {
return Optional.empty();
}
if (targetType.getResolvableType() == null) {
else if (source instanceof Optional) {
return source;
}
else if (targetType.getResolvableType() == null) {
return Optional.of(source);
}
else {
Object target = this.conversionService.convert(source, sourceType, new GenericTypeDescriptor(targetType));
return Optional.of(target);
return Optional.ofNullable(target);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,69 +27,73 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Holder that combines a {@link org.springframework.core.io.Resource}
* with a specific encoding to be used for reading from the resource.
* Holder that combines a {@link Resource} descriptor with a specific encoding
* or {@code Charset} to be used for reading from the resource.
*
* <p>Used as argument for operations that support to read content with
* a specific encoding (usually through a {@code java.io.Reader}).
* <p>Used as an argument for operations that support reading content with
* a specific encoding, typically via a {@code java.io.Reader}.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 1.2.6
* @see java.io.Reader
* @see java.nio.charset.Charset
*/
public class EncodedResource {
private final Resource resource;
private String encoding;
private final String encoding;
private Charset charset;
private final Charset charset;
/**
* Create a new EncodedResource for the given Resource,
* not specifying a specific encoding.
* @param resource the Resource to hold
* Create a new {@code EncodedResource} for the given {@code Resource},
* not specifying an explicit encoding or {@code Charset}.
* @param resource the {@code Resource} to hold; never {@code null}
*/
public EncodedResource(Resource resource) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this(resource, null, null);
}
/**
* Create a new EncodedResource for the given Resource,
* using the specified encoding.
* @param resource the Resource to hold
* Create a new {@code EncodedResource} for the given {@code Resource},
* using the specified {@code encoding}.
* @param resource the {@code Resource} to hold; never {@code null}
* @param encoding the encoding to use for reading from the resource
*/
public EncodedResource(Resource resource, String encoding) {
this(resource, encoding, null);
}
/**
* Create a new {@code EncodedResource} for the given {@code Resource},
* using the specified {@code Charset}.
* @param resource the {@code Resource} to hold; never {@code null}
* @param charset the {@code Charset} to use for reading from the resource
*/
public EncodedResource(Resource resource, Charset charset) {
this(resource, null, charset);
}
private EncodedResource(Resource resource, String encoding, Charset charset) {
super();
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.encoding = encoding;
}
/**
* Create a new EncodedResource for the given Resource,
* using the specified encoding.
* @param resource the Resource to hold
* @param charset the charset to use for reading from the resource
*/
public EncodedResource(Resource resource, Charset charset) {
Assert.notNull(resource, "Resource must not be null");
this.resource = resource;
this.charset = charset;
}
/**
* Return the Resource held.
* Return the {@code Resource} held by this {@code EncodedResource}.
*/
public final Resource getResource() {
return this.resource;
}
/**
* Return the encoding to use for reading from the resource,
* Return the encoding to use for reading from the {@linkplain #getResource() resource},
* or {@code null} if none specified.
*/
public final String getEncoding() {
@@ -97,17 +101,17 @@ public class EncodedResource {
}
/**
* Return the charset to use for reading from the resource,
* Return the {@code Charset} to use for reading from the {@linkplain #getResource() resource},
* or {@code null} if none specified.
*/
public final Charset getCharset() {
return this.charset;
}
/**
* Determine whether a {@link Reader} is required as opposed to an {@link InputStream},
* i.e. whether an encoding or a charset has been specified.
* i.e. whether an {@linkplain #getEncoding() encoding} or a {@link #getCharset() Charset}
* has been specified.
* @see #getReader()
* @see #getInputStream()
*/
@@ -116,10 +120,12 @@ public class EncodedResource {
}
/**
* Open a {@code java.io.Reader} for the specified resource,
* using the specified encoding (if any).
* Open a {@code java.io.Reader} for the specified resource, using the specified
* {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding}
* (if any).
* @throws IOException if opening the Reader failed
* @see #requiresReader()
* @see #getInputStream()
*/
public Reader getReader() throws IOException {
if (this.charset != null) {
@@ -134,10 +140,11 @@ public class EncodedResource {
}
/**
* Open an {@code java.io.InputStream} for the specified resource,
* typically assuming that there is no specific encoding to use.
* Open a {@code java.io.InputStream} for the specified resource, ignoring any
* specified {@link #getCharset() Charset} or {@linkplain #getEncoding() encoding}.
* @throws IOException if opening the InputStream failed
* @see #requiresReader()
* @see #getReader()
*/
public InputStream getInputStream() throws IOException {
return this.resource.getInputStream();
@@ -150,9 +157,10 @@ public class EncodedResource {
return true;
}
if (obj instanceof EncodedResource) {
EncodedResource otherRes = (EncodedResource) obj;
return (this.resource.equals(otherRes.resource) &&
ObjectUtils.nullSafeEquals(this.encoding, otherRes.encoding));
EncodedResource that = (EncodedResource) obj;
return (this.resource.equals(that.resource) &&
ObjectUtils.nullSafeEquals(this.charset, that.charset) &&
ObjectUtils.nullSafeEquals(this.encoding, that.encoding));
}
return false;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,10 @@ import java.util.Random;
import java.util.UUID;
/**
* A variation of {@link UUID#randomUUID()} that uses {@link SecureRandom} only for the
* initial seed and {@link Random} thereafter. This provides better performance in
* exchange for less securely random id's.
* An {@link IdGenerator} that uses {@link SecureRandom} for the initial seed and
* {@link Random} thereafter, instead of calling {@link UUID#randomUUID()} every
* time as {@link org.springframework.util.JdkIdGenerator JdkIdGenerator} does.
* This provides a better balance between securely random ids and performance.
*
* @author Rossen Stoyanchev
* @author Rob Winch
@@ -43,8 +44,8 @@ public class AlternativeJdkIdGenerator implements IdGenerator {
}
@Override
public UUID generateId() {
byte[] randomBytes = new byte[16];
this.random.nextBytes(randomBytes);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -41,7 +41,7 @@ import java.util.Map;
* Assert.notNull(clazz, "The class must not be null");
* Assert.isTrue(i > 0, "The value must be greater than zero");</pre>
*
* Mainly for internal use within the framework; consider Jakarta's Commons Lang
* Mainly for internal use within the framework; consider Apache's Commons Lang
* >= 2.0 for a more comprehensive suite of assertion utilities.
*
* @author Keith Donald
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -335,9 +335,10 @@ public abstract class CollectionUtils {
}
/**
* Adapt a {@code Map<K, List<V>>} to an {@code MultiValueMap<K,V>}.
* @param map the map
* Adapt a {@code Map<K, List<V>>} to an {@code MultiValueMap<K, V>}.
* @param map the original map
* @return the multi-value map
* @since 3.1
*/
public static <K, V> MultiValueMap<K, V> toMultiValueMap(Map<K, List<V>> map) {
return new MultiValueMapAdapter<K, V>(map);
@@ -348,8 +349,9 @@ public abstract class CollectionUtils {
* Return an unmodifiable view of the specified multi-value map.
* @param map the map for which an unmodifiable view is to be returned.
* @return an unmodifiable view of the specified multi-value map.
* @since 3.1
*/
public static <K,V> MultiValueMap<K,V> unmodifiableMultiValueMap(MultiValueMap<? extends K, ? extends V> map) {
public static <K, V> MultiValueMap<K, V> unmodifiableMultiValueMap(MultiValueMap<? extends K, ? extends V> map) {
Assert.notNull(map, "'map' must not be null");
Map<K, List<V>> result = new LinkedHashMap<K, List<V>>(map.size());
for (Map.Entry<? extends K, ? extends List<? extends V>> entry : map.entrySet()) {
@@ -366,7 +368,7 @@ public abstract class CollectionUtils {
*/
private static class EnumerationIterator<E> implements Iterator<E> {
private Enumeration<E> enumeration;
private final Enumeration<E> enumeration;
public EnumerationIterator(Enumeration<E> enumeration) {
this.enumeration = enumeration;
@@ -476,8 +478,8 @@ public abstract class CollectionUtils {
}
@Override
public void putAll(Map<? extends K, ? extends List<V>> m) {
this.map.putAll(m);
public void putAll(Map<? extends K, ? extends List<V>> map) {
this.map.putAll(map);
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,10 +51,10 @@ import java.util.concurrent.locks.ReentrantLock;
* <p>If not explicitly specified, this implementation will use
* {@linkplain SoftReference soft entry references}.
*
* @param <K> The key type
* @param <V> The value type
* @author Phillip Webb
* @since 3.2
* @param <K> the key type
* @param <V> the value type
*/
public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
@@ -0,0 +1,34 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.util;
import java.util.UUID;
/**
* An {@link IdGenerator} that calls {@link java.util.UUID#randomUUID()}.
*
* @author Rossen Stoyanchev
* @since 4.1.5
*/
public class JdkIdGenerator implements IdGenerator {
@Override
public UUID generateId() {
return UUID.randomUUID();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@ import java.util.Set;
/**
* Miscellaneous utility methods for number conversion and parsing.
* Mainly for internal use within the framework; consider Jakarta's
* Mainly for internal use within the framework; consider Apache's
* Commons Lang for a more comprehensive suite of string utilities.
*
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ public abstract class ReflectionUtils {
private static final String CGLIB_RENAMED_METHOD_PREFIX = "CGLIB$";
/**
* Cache for {@link Class#getDeclaredMethods()}, allowing for fast resolution.
* Cache for {@link Class#getDeclaredMethods()}, allowing for fast iteration.
*/
private static final Map<Class<?>, Method[]> declaredMethodsCache =
new ConcurrentReferenceHashMap<Class<?>, Method[]>(256);
@@ -440,8 +440,8 @@ public abstract class ReflectionUtils {
* @see java.lang.reflect.Method#setAccessible
*/
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) &&
!method.isAccessible()) {
if ((!Modifier.isPublic(method.getModifiers()) ||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {
method.setAccessible(true);
}
}
@@ -455,8 +455,8 @@ public abstract class ReflectionUtils {
* @see java.lang.reflect.Constructor#setAccessible
*/
public static void makeAccessible(Constructor<?> ctor) {
if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) &&
!ctor.isAccessible()) {
if ((!Modifier.isPublic(ctor.getModifiers()) ||
!Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) && !ctor.isAccessible()) {
ctor.setAccessible(true);
}
}
@@ -466,11 +466,11 @@ public abstract class ReflectionUtils {
* class and superclasses.
* <p>The same named method occurring on subclass and superclass will appear
* twice, unless excluded by a {@link MethodFilter}.
* @param clazz class to start looking at
* @param clazz the class to introspect
* @param mc the callback to invoke for each method
* @see #doWithMethods(Class, MethodCallback, MethodFilter)
*/
public static void doWithMethods(Class<?> clazz, MethodCallback mc) throws IllegalArgumentException {
public static void doWithMethods(Class<?> clazz, MethodCallback mc) {
doWithMethods(clazz, mc, null);
}
@@ -479,13 +479,11 @@ public abstract class ReflectionUtils {
* class and superclasses (or given interface and super-interfaces).
* <p>The same named method occurring on subclass and superclass will appear
* twice, unless excluded by the specified {@link MethodFilter}.
* @param clazz class to start looking at
* @param clazz the class to introspect
* @param mc the callback to invoke for each method
* @param mf the filter that determines the methods to apply the callback to
*/
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf)
throws IllegalArgumentException {
public static void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf) {
// Keep backing up the inheritance hierarchy.
Method[] methods = getDeclaredMethods(clazz);
for (Method method : methods) {
@@ -496,7 +494,7 @@ public abstract class ReflectionUtils {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Shouldn't be illegal to access method '" + method.getName() + "': " + ex);
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
if (clazz.getSuperclass() != null) {
@@ -510,10 +508,11 @@ public abstract class ReflectionUtils {
}
/**
* Get all declared methods on the leaf class and all superclasses. Leaf
* class methods are included first.
* Get all declared methods on the leaf class and all superclasses.
* Leaf class methods are included first.
* @param leafClass the class to introspect
*/
public static Method[] getAllDeclaredMethods(Class<?> leafClass) throws IllegalArgumentException {
public static Method[] getAllDeclaredMethods(Class<?> leafClass) {
final List<Method> methods = new ArrayList<Method>(32);
doWithMethods(leafClass, new MethodCallback() {
@Override
@@ -525,11 +524,12 @@ public abstract class ReflectionUtils {
}
/**
* Get the unique set of declared methods on the leaf class and all superclasses. Leaf
* class methods are included first and while traversing the superclass hierarchy any methods found
* with signatures matching a method already included are filtered out.
* Get the unique set of declared methods on the leaf class and all superclasses.
* Leaf class methods are included first and while traversing the superclass hierarchy
* any methods found with signatures matching a method already included are filtered out.
* @param leafClass the class to introspect
*/
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass) throws IllegalArgumentException {
public static Method[] getUniqueDeclaredMethods(Class<?> leafClass) {
final List<Method> methods = new ArrayList<Method>(32);
doWithMethods(leafClass, new MethodCallback() {
@Override
@@ -562,7 +562,7 @@ public abstract class ReflectionUtils {
}
/**
* This method retrieves {@link Class#getDeclaredMethods()} from a local cache
* This variant retrieves {@link Class#getDeclaredMethods()} from a local cache
* in order to avoid the JVM's SecurityManager check and defensive array copying.
*/
private static Method[] getDeclaredMethods(Class<?> clazz) {
@@ -580,7 +580,7 @@ public abstract class ReflectionUtils {
* @param clazz the target class to analyze
* @param fc the callback to invoke for each field
*/
public static void doWithFields(Class<?> clazz, FieldCallback fc) throws IllegalArgumentException {
public static void doWithFields(Class<?> clazz, FieldCallback fc) {
doWithFields(clazz, fc, null);
}
@@ -591,15 +591,12 @@ public abstract class ReflectionUtils {
* @param fc the callback to invoke for each field
* @param ff the filter that determines the fields to apply the callback to
*/
public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff)
throws IllegalArgumentException {
public static void doWithFields(Class<?> clazz, FieldCallback fc, FieldFilter ff) {
// Keep backing up the inheritance hierarchy.
Class<?> targetClass = clazz;
do {
Field[] fields = targetClass.getDeclaredFields();
for (Field field : fields) {
// Skip static and final fields.
if (ff != null && !ff.matches(field)) {
continue;
}
@@ -607,7 +604,7 @@ public abstract class ReflectionUtils {
fc.doWith(field);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Shouldn't be illegal to access field '" + field.getName() + "': " + ex);
throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
}
}
targetClass = targetClass.getSuperclass();
@@ -619,9 +616,8 @@ public abstract class ReflectionUtils {
* Given the source object and the destination, which must be the same class
* or a subclass, copy all fields, including inherited fields. Designed to
* work on objects with public no-arg constructors.
* @throws IllegalArgumentException if the arguments are incompatible
*/
public static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException {
public static void shallowCopyFieldState(final Object src, final Object dest) {
if (src == null) {
throw new IllegalArgumentException("Source for field copy cannot be null");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,7 @@ public class ResizableByteArrayOutputStream extends ByteArrayOutputStream {
/**
* Create a new <code>ResizableByteArrayOutputStream</code>
* with the default initial capacity of 128 bytes.
* with the default initial capacity of 256 bytes.
*/
public ResizableByteArrayOutputStream() {
super(DEFAULT_INITIAL_CAPACITY);
@@ -0,0 +1,44 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.util;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
/**
* A simple {@link IdGenerator} that starts at 1 and increments by 1 with each call.
*
* @author Rossen Stoyanchev
* @since 4.1.5
*/
public class SimpleIdGenerator implements IdGenerator {
private final AtomicLong mostSigBits = new AtomicLong(0);
private final AtomicLong leastSigBits = new AtomicLong(0);
@Override
public UUID generateId() {
long leastSigBits = this.leastSigBits.incrementAndGet();
if (leastSigBits == 0) {
this.mostSigBits.incrementAndGet();
}
return new UUID(this.mostSigBits.get(), leastSigBits);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ import java.util.TreeSet;
* Miscellaneous {@link String} utility methods.
*
* <p>Mainly for internal use within the framework; consider
* <a href="http://jakarta.apache.org/commons/lang/">Jakarta's Commons Lang</a>
* <a href="http://jakarta.apache.org/commons/lang/">Apache's Commons Lang</a>
* for a more comprehensive suite of String utilities.
*
* <p>This class delivers some simple functionality that should really
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,8 +32,8 @@ import org.springframework.util.Assert;
*
* @author Phillip Webb
* @since 3.2
* @param <T> the type of objects being compared
* @see CompoundComparator
* @param <T> the type of objects being compared
*/
public class InstanceComparator<T> implements Comparator<T> {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,10 +25,10 @@ import java.util.concurrent.ExecutionException;
* and {@link ListenableFutureCallback#onSuccess(Object)} call {@link #adapt(Object)}
* on the adaptee's result.
*
* @param <T> the type of this {@code Future}
* @param <S> the type of the adaptee's {@code Future}
* @author Arjen Poutsma
* @since 4.0
* @param <T> the type of this {@code Future}
* @param <S> the type of the adaptee's {@code Future}
*/
public abstract class ListenableFutureAdapter<T, S> extends FutureAdapter<T, S> implements ListenableFuture<T> {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@ public class ByteBufferConverterTests {
private GenericConversionService conversionService;
@Before
public void setup() {
this.conversionService = new GenericConversionService();
@@ -43,6 +44,7 @@ public class ByteBufferConverterTests {
this.conversionService.addConverter(new OtherTypeToByteArrayConverter());
}
@Test
public void byteArrayToByteBuffer() throws Exception {
byte[] bytes = new byte[] { 1, 2, 3 };
@@ -78,6 +80,7 @@ public class ByteBufferConverterTests {
assertThat(bytes, equalTo(convert.array()));
}
private static class OtherType {
private byte[] bytes;
@@ -88,8 +91,8 @@ public class ByteBufferConverterTests {
}
private static class ByteArrayToOtherTypeConverter implements
Converter<byte[], OtherType> {
private static class ByteArrayToOtherTypeConverter implements Converter<byte[], OtherType> {
@Override
public OtherType convert(byte[] source) {
@@ -97,8 +100,8 @@ public class ByteBufferConverterTests {
}
}
private static class OtherTypeToByteArrayConverter implements
Converter<OtherType, byte[]> {
private static class OtherTypeToByteArrayConverter implements Converter<OtherType, byte[]> {
@Override
public byte[] convert(OtherType source) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -69,7 +69,7 @@ public class DefaultConversionTests {
assertEquals(null, conversionService.convert("", Character.class));
}
@Test(expected=ConversionFailedException.class)
@Test(expected = ConversionFailedException.class)
public void testStringToCharacterInvalidString() {
conversionService.convert("invalid", Character.class);
}
@@ -106,7 +106,7 @@ public class DefaultConversionTests {
assertEquals(null, conversionService.convert("", Boolean.class));
}
@Test(expected=ConversionFailedException.class)
@Test(expected = ConversionFailedException.class)
public void testStringToBooleanInvalidString() {
conversionService.convert("invalid", Boolean.class);
}
@@ -265,36 +265,11 @@ public class DefaultConversionTests {
assertEquals(Long.valueOf(1), conversionService.convert(Integer.valueOf(1), Long.class));
}
@Test(expected=ConversionFailedException.class)
@Test(expected = ConversionFailedException.class)
public void testNumberToNumberNotSupportedNumber() {
conversionService.convert(Integer.valueOf(1), CustomNumber.class);
}
@SuppressWarnings("serial")
public static class CustomNumber extends Number {
@Override
public double doubleValue() {
return 0;
}
@Override
public float floatValue() {
return 0;
}
@Override
public int intValue() {
return 0;
}
@Override
public long longValue() {
return 0;
}
}
@Test
public void testNumberToCharacter() {
assertEquals(Character.valueOf('A'), conversionService.convert(Integer.valueOf(65), Character.class));
@@ -798,7 +773,7 @@ public class DefaultConversionTests {
TypeDescriptor descriptor = new TypeDescriptor(parameter);
Object actual = conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class), descriptor);
assertEquals(Optional.class, actual.getClass());
assertEquals(Arrays.asList(1,2,3), ((Optional<List<Integer>>) actual).get());
assertEquals(Arrays.asList(1, 2, 3), ((Optional<List<Integer>>) actual).get());
}
@Test
@@ -807,6 +782,38 @@ public class DefaultConversionTests {
assertSame(Optional.empty(), conversionService.convert(null, Optional.class));
}
@Test
public void convertExistingOptional() {
assertSame(Optional.empty(), conversionService.convert(Optional.empty(), TypeDescriptor.valueOf(Object.class),
TypeDescriptor.valueOf(Optional.class)));
assertSame(Optional.empty(), conversionService.convert(Optional.empty(), Optional.class));
}
@SuppressWarnings("serial")
public static class CustomNumber extends Number {
@Override
public double doubleValue() {
return 0;
}
@Override
public float floatValue() {
return 0;
}
@Override
public int intValue() {
return 0;
}
@Override
public long longValue() {
return 0;
}
}
public static class TestEntity {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -113,17 +113,17 @@ public class GenericConversionServiceTests {
assertEquals(null, conversionService.convert(null, Integer.class));
}
@Test(expected=ConversionFailedException.class)
@Test(expected = ConversionFailedException.class)
public void convertNullSourcePrimitiveTarget() {
assertEquals(null, conversionService.convert(null, int.class));
}
@Test(expected=ConversionFailedException.class)
@Test(expected = ConversionFailedException.class)
public void convertNullSourcePrimitiveTargetTypeDescriptor() {
conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(int.class));
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void convertNotNullSourceNullSourceTypeDescriptor() {
conversionService.convert("3", null, TypeDescriptor.valueOf(int.class));
}
@@ -177,18 +177,18 @@ public class GenericConversionServiceTests {
assertNull(conversionService.convert(null, Integer.class));
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void convertNullTargetClass() {
assertNull(conversionService.convert("3", (Class<?>) null));
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void convertNullTypeDescriptor() {
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
}
@Test(expected=IllegalArgumentException.class)
@Test(expected = IllegalArgumentException.class)
public void convertWrongSourceTypeDescriptor() {
conversionService.convert("3", TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Long.class));
}
@@ -218,8 +218,7 @@ public class GenericConversionServiceTests {
}
// SPR-8718
@Test(expected=ConverterNotFoundException.class)
@Test(expected = ConverterNotFoundException.class)
public void convertSuperTarget() {
conversionService.addConverter(new ColorConverter());
conversionService.convert("#000000", SystemColor.class);
@@ -295,7 +294,7 @@ public class GenericConversionServiceTests {
@Test
public void testInterfaceToString() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new MyBaseInterfaceConverter());
conversionService.addConverter(new MyBaseInterfaceToStringConverter());
conversionService.addConverter(new ObjectToStringConverter());
Object converted = conversionService.convert(new MyInterfaceImplementer(), String.class);
assertEquals("RESULT", converted);
@@ -304,7 +303,7 @@ public class GenericConversionServiceTests {
@Test
public void testInterfaceArrayToStringArray() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new MyBaseInterfaceConverter());
conversionService.addConverter(new MyBaseInterfaceToStringConverter());
conversionService.addConverter(new ArrayToArrayConverter(conversionService));
String[] converted = conversionService.convert(new MyInterface[] {new MyInterfaceImplementer()}, String[].class);
assertEquals("RESULT", converted[0]);
@@ -313,7 +312,7 @@ public class GenericConversionServiceTests {
@Test
public void testObjectArrayToStringArray() {
GenericConversionService conversionService = new GenericConversionService();
conversionService.addConverter(new MyBaseInterfaceConverter());
conversionService.addConverter(new MyBaseInterfaceToStringConverter());
conversionService.addConverter(new ArrayToArrayConverter(conversionService));
String[] converted = conversionService.convert(new MyInterfaceImplementer[] {new MyInterfaceImplementer()}, String[].class);
assertEquals("RESULT", converted[0]);
@@ -813,7 +812,7 @@ public class GenericConversionServiceTests {
}
private static class MyBaseInterfaceConverter implements Converter<MyBaseInterface, String> {
private static class MyBaseInterfaceToStringConverter implements Converter<MyBaseInterface, String> {
@Override
public String convert(MyBaseInterface source) {
@@ -0,0 +1,83 @@
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.io.support;
import java.nio.charset.Charset;
import org.junit.Test;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.core.io.Resource;
import static org.junit.Assert.*;
/**
* Unit tests for {@link EncodedResource}.
*
* @author Sam Brannen
* @since 3.2.14
*/
public class EncodedResourceTests {
private static final String UTF8 = "UTF-8";
private static final String UTF16 = "UTF-16";
private static final Charset UTF8_CS = Charset.forName(UTF8);
private static final Charset UTF16_CS = Charset.forName(UTF16);
private final Resource resource = new DescriptiveResource("test");
@Test
public void equalsWithNullOtherObject() {
assertFalse(new EncodedResource(resource).equals(null));
}
@Test
public void equalsWithSameEncoding() {
EncodedResource er1 = new EncodedResource(resource, UTF8);
EncodedResource er2 = new EncodedResource(resource, UTF8);
assertEquals(er1, er2);
}
@Test
public void equalsWithDifferentEncoding() {
EncodedResource er1 = new EncodedResource(resource, UTF8);
EncodedResource er2 = new EncodedResource(resource, UTF16);
assertNotEquals(er1, er2);
}
@Test
public void equalsWithSameCharset() {
EncodedResource er1 = new EncodedResource(resource, UTF8_CS);
EncodedResource er2 = new EncodedResource(resource, UTF8_CS);
assertEquals(er1, er2);
}
@Test
public void equalsWithDifferentCharset() {
EncodedResource er1 = new EncodedResource(resource, UTF8_CS);
EncodedResource er2 = new EncodedResource(resource, UTF16_CS);
assertNotEquals(er1, er2);
}
@Test
public void equalsWithEncodingAndCharset() {
EncodedResource er1 = new EncodedResource(resource, UTF8);
EncodedResource er2 = new EncodedResource(resource, UTF8_CS);
assertNotEquals(er1, er2);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ import static java.lang.String.*;
*/
public enum TestGroup {
/**
* Tests that take a considerable amount of time to run. Any test lasting longer than
* 500ms should be considered a candidate in order to avoid making the overall test
@@ -68,6 +67,7 @@ public enum TestGroup {
*/
CUSTOM_COMPILATION;
/**
* Parse the specified comma separated string of groups.
* @param value the comma separated string of groups
@@ -102,4 +102,5 @@ public enum TestGroup {
}
return groups;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,8 +66,8 @@ public class ReflectionUtilsTests {
@Test
public void setField() {
final TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField();
final Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class);
TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField();
Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class);
ReflectionUtils.makeAccessible(field);
@@ -79,13 +79,6 @@ public class ReflectionUtilsTests {
assertNull(testBean.getName());
}
@Test(expected = IllegalStateException.class)
public void setFieldIllegal() {
final TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField();
final Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class);
ReflectionUtils.setField(field, testBean, "FooBar");
}
@Test
public void invokeMethod() throws Exception {
String rob = "Rob Harrop";
@@ -94,65 +87,50 @@ public class ReflectionUtilsTests {
bean.setName(rob);
Method getName = TestObject.class.getMethod("getName", (Class[]) null);
Method setName = TestObject.class.getMethod("setName", new Class[] { String.class });
Method setName = TestObject.class.getMethod("setName", String.class);
Object name = ReflectionUtils.invokeMethod(getName, bean);
assertEquals("Incorrect name returned", rob, name);
String juergen = "Juergen Hoeller";
ReflectionUtils.invokeMethod(setName, bean, new Object[] { juergen });
ReflectionUtils.invokeMethod(setName, bean, juergen);
assertEquals("Incorrect name set", juergen, bean.getName());
}
@Test
public void declaresException() throws Exception {
Method remoteExMethod = A.class.getDeclaredMethod("foo", new Class[] { Integer.class });
Method remoteExMethod = A.class.getDeclaredMethod("foo", Integer.class);
assertTrue(ReflectionUtils.declaresException(remoteExMethod, RemoteException.class));
assertTrue(ReflectionUtils.declaresException(remoteExMethod, ConnectException.class));
assertFalse(ReflectionUtils.declaresException(remoteExMethod, NoSuchMethodException.class));
assertFalse(ReflectionUtils.declaresException(remoteExMethod, Exception.class));
Method illegalExMethod = B.class.getDeclaredMethod("bar", new Class[] { String.class });
Method illegalExMethod = B.class.getDeclaredMethod("bar", String.class);
assertTrue(ReflectionUtils.declaresException(illegalExMethod, IllegalArgumentException.class));
assertTrue(ReflectionUtils.declaresException(illegalExMethod, NumberFormatException.class));
assertFalse(ReflectionUtils.declaresException(illegalExMethod, IllegalStateException.class));
assertFalse(ReflectionUtils.declaresException(illegalExMethod, Exception.class));
}
@Test
@Test(expected = IllegalArgumentException.class)
public void copySrcToDestinationOfIncorrectClass() {
TestObject src = new TestObject();
String dest = new String();
try {
ReflectionUtils.shallowCopyFieldState(src, dest);
fail();
} catch (IllegalArgumentException ex) {
// Ok
}
ReflectionUtils.shallowCopyFieldState(src, dest);
}
@Test
@Test(expected = IllegalArgumentException.class)
public void rejectsNullSrc() {
TestObject src = null;
String dest = new String();
try {
ReflectionUtils.shallowCopyFieldState(src, dest);
fail();
} catch (IllegalArgumentException ex) {
// Ok
}
ReflectionUtils.shallowCopyFieldState(src, dest);
}
@Test
@Test(expected = IllegalArgumentException.class)
public void rejectsNullDest() {
TestObject src = new TestObject();
String dest = null;
try {
ReflectionUtils.shallowCopyFieldState(src, dest);
fail();
} catch (IllegalArgumentException ex) {
// Ok
}
ReflectionUtils.shallowCopyFieldState(src, dest);
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -27,15 +29,20 @@ import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
/**
* Implements the matches operator. Matches takes two operands. The first is a string and
* the second is a java regex. It will return true when getValue() is called if the first
* operand matches the regex.
* Implements the matches operator. Matches takes two operands:
* The first is a String and the second is a Java regex.
* It will return {@code true} when {@link #getValue} is called
* if the first operand matches the regex.
*
* @author Andy Clement
* @author Juergen Hoeller
* @since 3.0
*/
public class OperatorMatches extends Operator {
private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<String, Pattern>();
public OperatorMatches(int pos, SpelNodeImpl... operands) {
super("matches", pos, operands);
}
@@ -66,8 +73,14 @@ public class OperatorMatches extends Operator {
}
try {
Pattern pattern = Pattern.compile((String) right);
Matcher matcher = pattern.matcher((String) left);
String leftString = (String) left;
String rightString = (String) right;
Pattern pattern = this.patternCache.get(rightString);
if (pattern == null) {
pattern = Pattern.compile(rightString);
this.patternCache.putIfAbsent(rightString, pattern);
}
Matcher matcher = pattern.matcher(leftString);
return BooleanTypedValue.forValue(matcher.matches());
}
catch (PatternSyntaxException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,13 +40,14 @@ import org.springframework.util.MethodInvoker;
public class ReflectionHelper {
/**
* Compare argument arrays and return information about whether they match. A supplied
* type converter and conversionAllowed flag allow for matches to take into account
* that a type may be transformed into a different type by the converter.
* @param expectedArgTypes the array of types the method/constructor is expecting
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation
* Compare argument arrays and return information about whether they match.
* A supplied type converter and conversionAllowed flag allow for matches to take
* into account that a type may be transformed into a different type by the converter.
* @param expectedArgTypes the types the method/constructor is expecting
* @param suppliedArgTypes the types that are being supplied at the point of invocation
* @param typeConverter a registered type converter
* @return a MatchInfo object indicating what kind of match it was or null if it was not a match
* @return a MatchInfo object indicating what kind of match it was,
* or {@code null} if it was not a match
*/
static ArgumentsMatchInfo compareArguments(
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) {
@@ -90,7 +91,7 @@ public class ReflectionHelper {
int result = 0;
for (int i = 0; i < paramTypes.size(); i++) {
TypeDescriptor paramType = paramTypes.get(i);
TypeDescriptor argType = argTypes.get(i);
TypeDescriptor argType = (i < argTypes.size() ? argTypes.get(i) : null);
if (argType == null) {
if (paramType.isPrimitive()) {
return Integer.MAX_VALUE;
@@ -127,13 +128,15 @@ public class ReflectionHelper {
}
/**
* Compare argument arrays and return information about whether they match. A supplied type converter and
* conversionAllowed flag allow for matches to take into account that a type may be transformed into a different
* type by the converter. This variant of compareArguments also allows for a varargs match.
* @param expectedArgTypes the array of types the method/constructor is expecting
* @param suppliedArgTypes the array of types that are being supplied at the point of invocation
* Compare argument arrays and return information about whether they match.
* A supplied type converter and conversionAllowed flag allow for matches to
* take into account that a type may be transformed into a different type by the
* converter. This variant of compareArguments also allows for a varargs match.
* @param expectedArgTypes the types the method/constructor is expecting
* @param suppliedArgTypes the types that are being supplied at the point of invocation
* @param typeConverter a registered type converter
* @return a MatchInfo object indicating what kind of match it was or null if it was not a match
* @return a MatchInfo object indicating what kind of match it was,
* or {@code null} if it was not a match
*/
static ArgumentsMatchInfo compareArgumentsVarargs(
List<TypeDescriptor> expectedArgTypes, List<TypeDescriptor> suppliedArgTypes, TypeConverter typeConverter) {
@@ -246,12 +249,14 @@ public class ReflectionHelper {
* @param converter the type converter to use for attempting conversions
* @param arguments the actual arguments that need conversion
* @param methodOrCtor the target Method or Constructor
* @param varargsPosition the known position of the varargs argument, if any (null if not varargs)
* @return true if some kind of conversion occurred on an argument
* @param varargsPosition the known position of the varargs argument, if any
* ({@code null} if not varargs)
* @return {@code true} if some kind of conversion occurred on an argument
* @throws EvaluationException if a problem occurs during conversion
*/
static boolean convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor,
Integer varargsPosition) throws EvaluationException {
boolean conversionOccurred = false;
if (varargsPosition == null) {
for (int i = 0; i < arguments.length; i++) {
@@ -320,9 +325,9 @@ public class ReflectionHelper {
/**
* Package up the arguments so that they correctly match what is expected in parameterTypes.
* For example, if parameterTypes is (int, String[]) because the second parameter was declared String...
* then if arguments is [1,"a","b"] then it must be repackaged as [1,new String[]{"a","b"}] in order to
* match the expected parameterTypes.
* For example, if parameterTypes is {@code (int, String[])} because the second parameter
* was declared {@code String...}, then if arguments is {@code [1,"a","b"]} then it must be
* repackaged as {@code [1,new String[]{"a","b"}]} in order to match the expected types.
* @param requiredParameterTypes the types of the parameters for the invocation
* @param args the arguments to be setup ready for the invocation
* @return a repackaged array of arguments where any varargs setup has been done
@@ -374,10 +379,11 @@ public class ReflectionHelper {
/**
* An instance of ArgumentsMatchInfo describes what kind of match was achieved between two sets of arguments -
* the set that a method/constructor is expecting and the set that are being supplied at the point of invocation.
* If the kind indicates that conversion is required for some of the arguments then the arguments that require
* conversion are listed in the argsRequiringConversion array.
* An instance of ArgumentsMatchInfo describes what kind of match was achieved
* between two sets of arguments - the set that a method/constructor is expecting
* and the set that are being supplied at the point of invocation. If the kind
* indicates that conversion is required for some of the arguments then the arguments
* that require conversion are listed in the argsRequiringConversion array.
*/
static class ArgumentsMatchInfo {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,13 +66,14 @@ public class ReflectiveMethodResolver implements MethodResolver {
}
/**
* This constructors allows the ReflectiveMethodResolver to be configured such that it will
* use a distance computation to check which is the better of two close matches (when there
* are multiple matches). Using the distance computation is intended to ensure matches
* are more closely representative of what a Java compiler would do when taking into
* account boxing/unboxing and whether the method candidates are declared to handle a
* supertype of the type (of the argument) being passed in.
* @param useDistance true if distance computation should be used when calculating matches
* This constructor allows the ReflectiveMethodResolver to be configured such that it
* will use a distance computation to check which is the better of two close matches
* (when there are multiple matches). Using the distance computation is intended to
* ensure matches are more closely representative of what a Java compiler would do
* when taking into account boxing/unboxing and whether the method candidates are
* declared to handle a supertype of the type (of the argument) being passed in.
* @param useDistance {@code true} if distance computation should be used when
* calculating matches; {@code false} otherwise
*/
public ReflectiveMethodResolver(boolean useDistance) {
this.useDistance = useDistance;
@@ -175,17 +176,17 @@ public class ReflectiveMethodResolver implements MethodResolver {
return new ReflectiveMethodExecutor(method);
}
else if (matchInfo.isCloseMatch()) {
if (!this.useDistance) {
// Take this as a close match if there isn't one already
if (closeMatch == null) {
if (this.useDistance) {
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
if (closeMatch == null || matchDistance < closeMatchDistance) {
// This is a better match...
closeMatch = method;
closeMatchDistance = matchDistance;
}
}
else {
int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes);
if (matchDistance < closeMatchDistance) {
// This is a better match...
closeMatchDistance = matchDistance;
// Take this as a close match if there isn't one already
if (closeMatch == null) {
closeMatch = method;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,196 +35,146 @@ import static org.junit.Assert.*;
*/
public abstract class AbstractExpressionTests {
private final static boolean DEBUG = false;
private static final boolean DEBUG = false;
protected static final boolean SHOULD_BE_WRITABLE = true;
protected static final boolean SHOULD_NOT_BE_WRITABLE = false;
protected final static boolean SHOULD_BE_WRITABLE = true;
protected final static boolean SHOULD_NOT_BE_WRITABLE = false;
protected final ExpressionParser parser = new SpelExpressionParser();
protected final StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
/**
* Evaluate an expression and check that the actual result matches the expectedValue and the class of the result
* matches the expectedClassOfResult.
* @param expression The expression to evaluate
* Evaluate an expression and check that the actual result matches the
* expectedValue and the class of the result matches the expectedClassOfResult.
* @param expression the expression to evaluate
* @param expectedValue the expected result for evaluating the expression
* @param expectedResultType the expected class of the evaluation result
*/
protected void evaluate(String expression, Object expectedValue, Class<?> expectedResultType) {
try {
Expression expr = parser.parseExpression(expression);
if (expr == null) {
fail("Parser returned null for expression");
public void evaluate(String expression, Object expectedValue, Class<?> expectedResultType) {
Expression expr = parser.parseExpression(expression);
if (expr == null) {
fail("Parser returned null for expression");
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
}
Object value = expr.getValue(eContext);
// Check the return value
if (value == null) {
if (expectedValue == null) {
return; // no point doing other checks
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
}
// Class<?> expressionType = expr.getValueType();
// assertEquals("Type of the expression is not as expected. Should be '" +
// expectedResultType + "' but is '"
// + expressionType + "'", expectedResultType, expressionType);
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, null);
}
Object value = expr.getValue(eContext);
Class<?> resultType = value.getClass();
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType +
"' but result was of type '" + resultType + "'", expectedResultType, resultType);
// Check the return value
if (value == null) {
if (expectedValue == null) {
return; // no point doing other checks
}
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
null);
}
Class<?> resultType = value.getClass();
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType
+ "' but result was of type '" + resultType + "'", expectedResultType, resultType);
// .equals/* isAssignableFrom */(resultType), truers);
// TODO isAssignableFrom would allow some room for compatibility
// in the above expression...
if (expectedValue instanceof String) {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
if (expectedValue instanceof String) {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
AbstractExpressionTests.stringValueOf(value));
}
else {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
}
}
catch (EvaluationException ee) {
ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage());
}
catch (ParseException pe) {
pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage());
else {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
}
}
protected void evaluateAndAskForReturnType(String expression, Object expectedValue, Class<?> expectedResultType) {
try {
Expression expr = parser.parseExpression(expression);
if (expr == null) {
fail("Parser returned null for expression");
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
}
// Class<?> expressionType = expr.getValueType();
// assertEquals("Type of the expression is not as expected. Should be '" +
// expectedResultType + "' but is '"
// + expressionType + "'", expectedResultType, expressionType);
public void evaluateAndAskForReturnType(String expression, Object expectedValue, Class<?> expectedResultType) {
Expression expr = parser.parseExpression(expression);
if (expr == null) {
fail("Parser returned null for expression");
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
}
Object value = expr.getValue(eContext, expectedResultType);
if (value == null) {
if (expectedValue == null)
return; // no point doing other checks
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
null);
Object value = expr.getValue(eContext, expectedResultType);
if (value == null) {
if (expectedValue == null) {
return; // no point doing other checks
}
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, null);
}
Class<?> resultType = value.getClass();
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType
+ "' but result was of type '" + resultType + "'", expectedResultType, resultType);
// .equals/* isAssignableFrom */(resultType), truers);
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
// isAssignableFrom would allow some room for compatibility
// in the above expression...
}
catch (EvaluationException ee) {
SpelEvaluationException ex = (SpelEvaluationException) ee;
ex.printStackTrace();
fail("Unexpected EvaluationException: " + ex.getMessage());
}
catch (ParseException pe) {
fail("Unexpected ParseException: " + pe.getMessage());
}
Class<?> resultType = value.getClass();
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType +
"' but result was of type '" + resultType + "'", expectedResultType, resultType);
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
}
/**
* Evaluate an expression and check that the actual result matches the expectedValue and the class of the result
* matches the expectedClassOfResult. This method can also check if the expression is writable (for example, it is a
* variable or property reference).
*
* @param expression The expression to evaluate
* Evaluate an expression and check that the actual result matches the
* expectedValue and the class of the result matches the expectedClassOfResult.
* This method can also check if the expression is writable (for example,
* it is a variable or property reference).
* @param expression the expression to evaluate
* @param expectedValue the expected result for evaluating the expression
* @param expectedClassOfResult the expected class of the evaluation result
* @param shouldBeWritable should the parsed expression be writable?
*/
protected void evaluate(String expression, Object expectedValue, Class<?> expectedClassOfResult,
boolean shouldBeWritable) {
try {
Expression e = parser.parseExpression(expression);
if (e == null) {
fail("Parser returned null for expression");
public void evaluate(String expression, Object expectedValue, Class<?> expectedClassOfResult, boolean shouldBeWritable) {
Expression expr = parser.parseExpression(expression);
if (expr == null) {
fail("Parser returned null for expression");
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
}
Object value = expr.getValue(eContext);
if (value == null) {
if (expectedValue == null) {
return; // no point doing other checks
}
if (DEBUG) {
SpelUtilities.printAbstractSyntaxTree(System.out, e);
}
Object value = e.getValue(eContext);
if (value == null) {
if (expectedValue == null)
return; // no point doing other
// checks
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
null);
}
Class<? extends Object> resultType = value.getClass();
if (expectedValue instanceof String) {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, null);
}
Class<? extends Object> resultType = value.getClass();
if (expectedValue instanceof String) {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
AbstractExpressionTests.stringValueOf(value));
}
else {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
}
// assertEquals("Did not get expected value for expression '" + expression +
// "'.", expectedValue, stringValueOf(value));
assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult
+ "' but result was of type '" + resultType + "'",
expectedClassOfResult.equals/* isAssignableFrom */(resultType), true);
// TODO isAssignableFrom would allow some room for compatibility
// in the above expression...
}
else {
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
}
assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult +
"' but result was of type '" + resultType + "'", expectedClassOfResult.equals(resultType), true);
boolean isWritable = e.isWritable(eContext);
if (isWritable != shouldBeWritable) {
if (shouldBeWritable)
fail("Expected the expression to be writable but it is not");
else
fail("Expected the expression to be readonly but it is not");
}
}
catch (EvaluationException ee) {
ee.printStackTrace();
fail("Unexpected Exception: " + ee.getMessage());
}
catch (ParseException pe) {
pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage());
boolean isWritable = expr.isWritable(eContext);
if (isWritable != shouldBeWritable) {
if (shouldBeWritable)
fail("Expected the expression to be writable but it is not");
else
fail("Expected the expression to be readonly but it is not");
}
}
/**
* Evaluate the specified expression and ensure the expected message comes out. The message may have inserts and
* they will be checked if otherProperties is specified. The first entry in otherProperties should always be the
* position.
* @param expression The expression to evaluate
* @param expectedMessage The expected message
* @param otherProperties The expected inserts within the message
* Evaluate the specified expression and ensure the expected message comes out.
* The message may have inserts and they will be checked if otherProperties is specified.
* The first entry in otherProperties should always be the position.
* @param expression the expression to evaluate
* @param expectedMessage the expected message
* @param otherProperties the expected inserts within the message
*/
protected void evaluateAndCheckError(String expression, SpelMessage expectedMessage, Object... otherProperties) {
evaluateAndCheckError(expression, null, expectedMessage, otherProperties);
}
/**
* Evaluate the specified expression and ensure the expected message comes out. The message may have inserts and
* they will be checked if otherProperties is specified. The first entry in otherProperties should always be the
* position.
* @param expression The expression to evaluate
* @param expectedReturnType Ask the expression return value to be of this type if possible (null indicates don't
* ask for conversion)
* @param expectedMessage The expected message
* @param otherProperties The expected inserts within the message
* Evaluate the specified expression and ensure the expected message comes out.
* The message may have inserts and they will be checked if otherProperties is specified.
* The first entry in otherProperties should always be the position.
* @param expression the expression to evaluate
* @param expectedReturnType ask the expression return value to be of this type if possible
* ({@code null} indicates don't ask for conversion)
* @param expectedMessage the expected message
* @param otherProperties the expected inserts within the message
*/
protected void evaluateAndCheckError(String expression, Class<?> expectedReturnType, SpelMessage expectedMessage,
Object... otherProperties) {
@@ -234,19 +184,16 @@ public abstract class AbstractExpressionTests {
fail("Parser returned null for expression");
}
if (expectedReturnType != null) {
@SuppressWarnings("unused")
Object value = expr.getValue(eContext, expectedReturnType);
expr.getValue(eContext, expectedReturnType);
}
else {
@SuppressWarnings("unused")
Object value = expr.getValue(eContext);
expr.getValue(eContext);
}
fail("Should have failed with message " + expectedMessage);
}
catch (EvaluationException ee) {
SpelEvaluationException ex = (SpelEvaluationException) ee;
if (ex.getMessageCode() != expectedMessage) {
ex.printStackTrace();
assertEquals("Failed to get expected message", expectedMessage, ex.getMessageCode());
}
if (otherProperties != null && otherProperties.length != 0) {
@@ -260,47 +207,39 @@ public abstract class AbstractExpressionTests {
inserts = new Object[0];
}
if (inserts.length < otherProperties.length - 1) {
ex.printStackTrace();
fail("Cannot check " + (otherProperties.length - 1)
+ " properties of the exception, it only has " + inserts.length + " inserts");
fail("Cannot check " + (otherProperties.length - 1) +
" properties of the exception, it only has " + inserts.length + " inserts");
}
for (int i = 1; i < otherProperties.length; i++) {
if (otherProperties[i] == null) {
if (inserts[i - 1] != null) {
ex.printStackTrace();
fail("Insert does not match, expected 'null' but insert value was '" + inserts[i - 1]
+ "'");
fail("Insert does not match, expected 'null' but insert value was '" +
inserts[i - 1] + "'");
}
}
else if (inserts[i - 1] == null) {
if (otherProperties[i] != null) {
ex.printStackTrace();
fail("Insert does not match, expected '" + otherProperties[i]
+ "' but insert value was 'null'");
fail("Insert does not match, expected '" + otherProperties[i] +
"' but insert value was 'null'");
}
}
else if (!inserts[i - 1].equals(otherProperties[i])) {
ex.printStackTrace();
fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '"
+ inserts[i - 1] + "'");
fail("Insert does not match, expected '" + otherProperties[i] +
"' but insert value was '" + inserts[i - 1] + "'");
}
}
}
}
}
catch (ParseException pe) {
pe.printStackTrace();
fail("Unexpected Exception: " + pe.getMessage());
}
}
/**
* Parse the specified expression and ensure the expected message comes out. The message may have inserts and they
* will be checked if otherProperties is specified. The first entry in otherProperties should always be the
* position.
* @param expression The expression to evaluate
* @param expectedMessage The expected message
* @param otherProperties The expected inserts within the message
* Parse the specified expression and ensure the expected message comes out.
* The message may have inserts and they will be checked if otherProperties is specified.
* The first entry in otherProperties should always be the position.
* @param expression the expression to evaluate
* @param expectedMessage the expected message
* @param otherProperties the expected inserts within the message
*/
protected void parseAndCheckError(String expression, SpelMessage expectedMessage, Object... otherProperties) {
try {
@@ -309,21 +248,8 @@ public abstract class AbstractExpressionTests {
fail("Parsing should have failed!");
}
catch (ParseException pe) {
// pe.printStackTrace();
// Throwable t = pe.getCause();
// if (t == null) {
// fail("ParseException caught with no defined cause");
// }
// if (!(t instanceof SpelEvaluationException)) {
// t.printStackTrace();
// fail("Cause of parse exception is not a SpelException");
// }
// SpelEvaluationException ex = (SpelEvaluationException) t;
// pe.printStackTrace();
SpelParseException ex = (SpelParseException) pe;
SpelParseException ex = (SpelParseException)pe;
if (ex.getMessageCode() != expectedMessage) {
// System.out.println(ex.getMessage());
ex.printStackTrace();
assertEquals("Failed to get expected message", expectedMessage, ex.getMessageCode());
}
if (otherProperties != null && otherProperties.length != 0) {
@@ -337,15 +263,13 @@ public abstract class AbstractExpressionTests {
inserts = new Object[0];
}
if (inserts.length < otherProperties.length - 1) {
ex.printStackTrace();
fail("Cannot check " + (otherProperties.length - 1)
+ " properties of the exception, it only has " + inserts.length + " inserts");
fail("Cannot check " + (otherProperties.length - 1) +
" properties of the exception, it only has " + inserts.length + " inserts");
}
for (int i = 1; i < otherProperties.length; i++) {
if (!inserts[i - 1].equals(otherProperties[i])) {
ex.printStackTrace();
fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '"
+ inserts[i - 1] + "'");
fail("Insert does not match, expected '" + otherProperties[i] +
"' but insert value was '" + inserts[i - 1] + "'");
}
}
}
@@ -353,13 +277,13 @@ public abstract class AbstractExpressionTests {
}
}
protected static String stringValueOf(Object value) {
return stringValueOf(value, false);
}
/**
* Produce a nice string representation of the input object.
*
* @param value object to be formatted
* @return a nice string
*/
@@ -395,8 +319,8 @@ public abstract class AbstractExpressionTests {
sb.append("}");
}
else {
throw new RuntimeException("Please implement support for type " + primitiveType.getName()
+ " in ExpressionTestCase.stringValueOf()");
throw new RuntimeException("Please implement support for type " + primitiveType.getName() +
" in ExpressionTestCase.stringValueOf()");
}
}
else if (value.getClass().getComponentType().isArray()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,17 +54,6 @@ public class MethodInvocationTests extends AbstractExpressionTests {
evaluate("getPlaceOfBirth().getCity()", "SmilJan", String.class);
}
// public void testBuiltInProcessors() {
// evaluate("new int[]{1,2,3,4}.count()", 4, Integer.class);
// evaluate("new int[]{4,3,2,1}.sort()[3]", 4, Integer.class);
// evaluate("new int[]{4,3,2,1}.average()", 2, Integer.class);
// evaluate("new int[]{4,3,2,1}.max()", 4, Integer.class);
// evaluate("new int[]{4,3,2,1}.min()", 1, Integer.class);
// evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class);
// evaluate("{1,2,3,null}.nonnull().count()", 3, Integer.class);
// evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class);
// }
@Test
public void testStringClass() {
evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class);
@@ -107,7 +96,7 @@ public class MethodInvocationTests extends AbstractExpressionTests {
// Normal exit
StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
eContext.setVariable("bar",3);
eContext.setVariable("bar", 3);
Object o = expr.getValue(eContext);
assertEquals(o, 3);
assertEquals(1, parser.parseExpression("counter").getValue(eContext));
@@ -115,46 +104,44 @@ public class MethodInvocationTests extends AbstractExpressionTests {
// Now the expression has cached that throwException(int) is the right thing to call
// Let's change 'bar' to be a PlaceOfBirth which indicates the cached reference is
// out of date.
eContext.setVariable("bar",new PlaceOfBirth("London"));
eContext.setVariable("bar", new PlaceOfBirth("London"));
o = expr.getValue(eContext);
assertEquals("London", o);
// That confirms the logic to mark the cached reference stale and retry is working
// Now let's cause the method to exit via exception and ensure it doesn't cause
// a retry.
// Now let's cause the method to exit via exception and ensure it doesn't cause a retry.
// First, switch back to throwException(int)
eContext.setVariable("bar",3);
eContext.setVariable("bar", 3);
o = expr.getValue(eContext);
assertEquals(3, o);
assertEquals(2, parser.parseExpression("counter").getValue(eContext));
// Now cause it to throw an exception:
eContext.setVariable("bar",1);
eContext.setVariable("bar", 1);
try {
o = expr.getValue(eContext);
fail();
} catch (Exception e) {
if (e instanceof SpelEvaluationException) {
e.printStackTrace();
fail("Should not be a SpelEvaluationException");
}
catch (Exception ex) {
if (ex instanceof SpelEvaluationException) {
fail("Should not be a SpelEvaluationException: " + ex);
}
// normal
}
// If counter is 4 then the method got called twice!
assertEquals(3, parser.parseExpression("counter").getValue(eContext));
eContext.setVariable("bar",4);
eContext.setVariable("bar", 4);
try {
o = expr.getValue(eContext);
fail();
} catch (Exception e) {
}
catch (Exception ex) {
// 4 means it will throw a checked exception - this will be wrapped
if (!(e instanceof ExpressionInvocationTargetException)) {
e.printStackTrace();
fail("Should have been wrapped");
if (!(ex instanceof ExpressionInvocationTargetException)) {
fail("Should have been wrapped: " + ex);
}
// normal
}
@@ -176,14 +163,14 @@ public class MethodInvocationTests extends AbstractExpressionTests {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expr = parser.parseExpression("throwException(#bar)");
eContext.setVariable("bar",2);
eContext.setVariable("bar", 2);
try {
expr.getValue(eContext);
fail();
} catch (Exception e) {
if (e instanceof SpelEvaluationException) {
e.printStackTrace();
fail("Should not be a SpelEvaluationException");
}
catch (Exception ex) {
if (ex instanceof SpelEvaluationException) {
fail("Should not be a SpelEvaluationException: " + ex);
}
// normal
}
@@ -200,18 +187,16 @@ public class MethodInvocationTests extends AbstractExpressionTests {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expr = parser.parseExpression("throwException(#bar)");
eContext.setVariable("bar",4);
eContext.setVariable("bar", 4);
try {
expr.getValue(eContext);
fail();
} catch (ExpressionInvocationTargetException e) {
Throwable t = e.getCause();
assertEquals(
"org.springframework.expression.spel.testresources.Inventor$TestException",
t.getClass().getName());
return;
}
fail("Should not be a SpelEvaluationException");
catch (ExpressionInvocationTargetException ex) {
Throwable cause = ex.getCause();
assertEquals("org.springframework.expression.spel.testresources.Inventor$TestException",
cause.getClass().getName());
}
}
@Test
@@ -224,7 +209,7 @@ public class MethodInvocationTests extends AbstractExpressionTests {
// Filter will be called but not do anything, so first doit() will be invoked
SpelExpression expr = (SpelExpression) parser.parseExpression("doit(1)");
String result = expr.getValue(context,String.class);
String result = expr.getValue(context, String.class);
assertEquals("1", result);
assertTrue(filter.filterCalled);
@@ -232,15 +217,15 @@ public class MethodInvocationTests extends AbstractExpressionTests {
filter.removeIfNotAnnotated = true;
filter.filterCalled = false;
expr = (SpelExpression) parser.parseExpression("doit(1)");
result = expr.getValue(context,String.class);
result = expr.getValue(context, String.class);
assertEquals("double 1.0", result);
assertTrue(filter.filterCalled);
// check not called for other types
filter.filterCalled=false;
filter.filterCalled = false;
context.setRootObject(new String("abc"));
expr = (SpelExpression) parser.parseExpression("charAt(0)");
result = expr.getValue(context,String.class);
result = expr.getValue(context, String.class);
assertEquals("a", result);
assertFalse(filter.filterCalled);
@@ -249,64 +234,11 @@ public class MethodInvocationTests extends AbstractExpressionTests {
context.registerMethodFilter(TestObject.class,null);//clear filter
context.setRootObject(new TestObject());
expr = (SpelExpression) parser.parseExpression("doit(1)");
result = expr.getValue(context,String.class);
result = expr.getValue(context, String.class);
assertEquals("1", result);
assertFalse(filter.filterCalled);
}
// Simple filter
static class LocalFilter implements MethodFilter {
public boolean removeIfNotAnnotated = false;
public boolean filterCalled = false;
private boolean isAnnotated(Method m) {
Annotation[] annos = m.getAnnotations();
if (annos==null) {
return false;
}
for (Annotation anno: annos) {
String s = anno.annotationType().getName();
if (s.endsWith("Anno")) {
return true;
}
}
return false;
}
@Override
public List<Method> filter(List<Method> methods) {
filterCalled = true;
List<Method> forRemoval = new ArrayList<Method>();
for (Method m: methods) {
if (removeIfNotAnnotated && !isAnnotated(m)) {
forRemoval.add(m);
}
}
for (Method m: forRemoval) {
methods.remove(m);
}
return methods;
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Anno {}
class TestObject {
public int doit(int i) {
return i;
}
@Anno
public String doit(double d) {
return "double "+d;
}
}
@Test
public void testAddingMethodResolvers() {
StandardEvaluationContext ctx = new StandardEvaluationContext();
@@ -329,17 +261,6 @@ public class MethodInvocationTests extends AbstractExpressionTests {
assertEquals(2, ctx.getMethodResolvers().size());
}
static class DummyMethodResolver implements MethodResolver {
@Override
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException {
throw new UnsupportedOperationException("Auto-generated method stub");
}
}
@Test
public void testVarargsInvocation01() {
// Calling 'public int aVarargsMethod(String... strings)'
@@ -383,8 +304,7 @@ public class MethodInvocationTests extends AbstractExpressionTests {
StandardEvaluationContext context = new StandardEvaluationContext(bytes);
context.setBeanResolver(new BeanResolver() {
@Override
public Object resolve(EvaluationContext context, String beanName)
throws AccessException {
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
if ("service".equals(beanName)) {
return service;
}
@@ -396,10 +316,78 @@ public class MethodInvocationTests extends AbstractExpressionTests {
assertSame(bytes, outBytes);
}
// Simple filter
static class LocalFilter implements MethodFilter {
public boolean removeIfNotAnnotated = false;
public boolean filterCalled = false;
private boolean isAnnotated(Method method) {
Annotation[] anns = method.getAnnotations();
if (anns == null) {
return false;
}
for (Annotation ann : anns) {
String name = ann.annotationType().getName();
if (name.endsWith("Anno")) {
return true;
}
}
return false;
}
@Override
public List<Method> filter(List<Method> methods) {
filterCalled = true;
List<Method> forRemoval = new ArrayList<Method>();
for (Method method: methods) {
if (removeIfNotAnnotated && !isAnnotated(method)) {
forRemoval.add(method);
}
}
for (Method method: forRemoval) {
methods.remove(method);
}
return methods;
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Anno {
}
class TestObject {
public int doit(int i) {
return i;
}
@Anno
public String doit(double d) {
return "double "+d;
}
}
static class DummyMethodResolver implements MethodResolver {
@Override
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException {
throw new UnsupportedOperationException();
}
}
public static class BytesService {
public byte[] handleBytes(byte[] bytes) {
return bytes;
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1895,6 +1895,15 @@ public class SpelReproTests extends AbstractExpressionTests {
assertTrue(((List) value).isEmpty());
}
@Test
public void SPR12803() throws Exception {
StandardEvaluationContext sec = new StandardEvaluationContext();
sec.setVariable("iterable", Collections.emptyList());
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("T(org.springframework.expression.spel.SpelReproTests.GuavaLists).newArrayList(#iterable)");
assertTrue(expression.getValue(sec) instanceof ArrayList);
}
private static enum ABC { A, B, C }
@@ -2180,4 +2189,16 @@ public class SpelReproTests extends AbstractExpressionTests {
}
}
public static class GuavaLists {
public static <T> List<T> newArrayList(Iterable<T> iterable) {
return new ArrayList<T>();
}
public static <T> List<T> newArrayList(Object... elements) {
throw new UnsupportedOperationException();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testresources.Inventor;
import org.springframework.expression.spel.testresources.PlaceOfBirth;
///CLOVER:OFF
/**
* Builds an evaluation context for test expressions. Features of the test evaluation context are:
* Builds an evaluation context for test expressions.
* Features of the test evaluation context are:
* <ul>
* <li>The root context object is an Inventor instance {@link Inventor}
* </ul>
@@ -45,21 +45,19 @@ public class TestScenarioCreator {
*/
private static void populateFunctions(StandardEvaluationContext testContext) {
try {
testContext.registerFunction("isEven", TestScenarioCreator.class.getDeclaredMethod("isEven",
new Class[] { Integer.TYPE }));
testContext.registerFunction("reverseInt", TestScenarioCreator.class.getDeclaredMethod("reverseInt",
new Class[] { Integer.TYPE, Integer.TYPE, Integer.TYPE }));
testContext.registerFunction("reverseString", TestScenarioCreator.class.getDeclaredMethod("reverseString",
new Class[] { String.class }));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge", TestScenarioCreator.class
.getDeclaredMethod("varargsFunctionReverseStringsAndMerge", new Class[] { String[].class }));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge2", TestScenarioCreator.class
.getDeclaredMethod("varargsFunctionReverseStringsAndMerge2", new Class[] { Integer.TYPE,
String[].class }));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
testContext.registerFunction("isEven",
TestScenarioCreator.class.getDeclaredMethod("isEven", Integer.TYPE));
testContext.registerFunction("reverseInt",
TestScenarioCreator.class.getDeclaredMethod("reverseInt", Integer.TYPE, Integer.TYPE, Integer.TYPE));
testContext.registerFunction("reverseString",
TestScenarioCreator.class.getDeclaredMethod("reverseString", String.class));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge",
TestScenarioCreator.class.getDeclaredMethod("varargsFunctionReverseStringsAndMerge", String[].class));
testContext.registerFunction("varargsFunctionReverseStringsAndMerge2",
TestScenarioCreator.class.getDeclaredMethod("varargsFunctionReverseStringsAndMerge2", Integer.TYPE, String[].class));
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
@@ -72,9 +70,8 @@ public class TestScenarioCreator {
}
/**
* Create the root context object, an Inventor instance. Non-qualified property and method references will be
* resolved against this context object.
*
* Create the root context object, an Inventor instance. Non-qualified property
* and method references will be resolved against this context object.
* @param testContext the evaluation context in which to set the root object
*/
private static void setupRootContextObject(StandardEvaluationContext testContext) {
@@ -88,12 +85,14 @@ public class TestScenarioCreator {
testContext.setRootObject(tesla);
}
// These methods are registered in the test context and therefore accessible through function calls
// in test expressions
public static String isEven(int i) {
if ((i % 2) == 0)
if ((i % 2) == 0) {
return "y";
}
return "n";
}
@@ -129,4 +128,5 @@ public class TestScenarioCreator {
}
return sb.toString();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,7 +83,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* <p>This transaction manager can be used as a replacement for the
* {@link org.springframework.transaction.jta.JtaTransactionManager} in the single
* resource case, as it does not require a container that supports JTA, typically
* in combination with a locally defined JDBC DataSource (e.g. a Jakarta Commons
* in combination with a locally defined JDBC DataSource (e.g. an Apache Commons
* DBCP connection pool). Switching between this local strategy and a JTA
* environment is just a matter of configuration!
*
@@ -126,8 +126,8 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
/**
* Set the JDBC DataSource that this instance should manage transactions for.
* <p>This will typically be a locally defined DataSource, for example a
* Jakarta Commons DBCP connection pool. Alternatively, you can also drive
* <p>This will typically be a locally defined DataSource, for example an
* Apache Commons DBCP connection pool. Alternatively, you can also drive
* transactions for a non-XA J2EE DataSource fetched from JNDI. For an XA
* DataSource, use JtaTransactionManager.
* <p>The DataSource specified here should be the target DataSource to manage
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ import org.springframework.util.ClassUtils;
* bean definition to a local DataSource (which is simpler and thus recommended).
*
* <p>If you need a "real" connection pool outside of a J2EE container, consider
* <a href="http://jakarta.apache.org/commons/dbcp">Apache's Jakarta Commons DBCP</a>
* <a href="http://commons.apache.org/proper/commons-dbcp">Apache Commons DBCP</a>
* or <a href="http://sourceforge.net/projects/c3p0">C3P0</a>.
* Commons DBCP's BasicDataSource and C3P0's ComboPooledDataSource are full
* connection pool beans, supporting the same basic properties as this class
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,8 @@ import org.springframework.util.Assert;
/**
* Simple implementation of the standard JDBC {@link javax.sql.DataSource} interface,
* configuring a plain old JDBC {@link java.sql.Driver} via bean properties, and returning
* a new {@link java.sql.Connection} from every {@code getConnection} call.
* configuring a plain old JDBC {@link java.sql.Driver} via bean properties, and
* returning a new {@link java.sql.Connection} from every {@code getConnection} call.
*
* <p><b>NOTE: This class is not an actual connection pool; it does not actually
* pool Connections.</b> It just serves as simple replacement for a full-blown
@@ -40,7 +40,7 @@ import org.springframework.util.Assert;
* for seamless switching to and from a local DataSource bean like this class.
*
* <p>If you need a "real" connection pool outside of a J2EE container, consider
* <a href="http://jakarta.apache.org/commons/dbcp">Apache's Jakarta Commons DBCP</a>
* <a href="http://commons.apache.org/proper/commons-dbcp">Apache Commons DBCP</a>
* or <a href="http://sourceforge.net/projects/c3p0">C3P0</a>.
* Commons DBCP's BasicDataSource and C3P0's ComboPooledDataSource are full
* connection pool beans, supporting the same basic properties as this class
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,14 +31,14 @@ public class ScriptStatementFailedException extends ScriptException {
/**
* Construct a new {@code ScriptStatementFailedException}.
* @param statement the actual SQL statement that failed
* @param lineNumber the line number in the SQL script
* @param stmt the actual SQL statement that failed
* @param stmtNumber the statement number in the SQL script (i.e.,
* the nth statement present in the resource)
* @param resource the resource from which the SQL statement was read
* @param cause the underlying cause of the failure
*/
public ScriptStatementFailedException(String statement, int lineNumber, EncodedResource resource, Throwable cause) {
super("Failed to execute SQL script statement at line " + lineNumber + " of resource " + resource + ": "
+ statement, cause);
public ScriptStatementFailedException(String stmt, int stmtNumber, EncodedResource resource, Throwable cause) {
super("Failed to execute SQL script statement #" + stmtNumber + " of resource " + resource + ": " + stmt, cause);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,8 +48,6 @@ import org.springframework.util.StringUtils;
*/
public abstract class ScriptUtils {
private static final Log logger = LogFactory.getLog(ScriptUtils.class);
/**
* Default statement separator within SQL scripts: {@code ";"}.
*/
@@ -89,12 +87,8 @@ public abstract class ScriptUtils {
public static final String DEFAULT_BLOCK_COMMENT_END_DELIMITER = "*/";
/**
* Prevent instantiation of this utility class.
*/
private ScriptUtils() {
/* no-op */
}
private static final Log logger = LogFactory.getLog(ScriptUtils.class);
/**
* Split an SQL script into separate statements delimited by the provided
@@ -140,7 +134,7 @@ public abstract class ScriptUtils {
*/
public static void splitSqlScript(String script, String separator, List<String> statements) throws ScriptException {
splitSqlScript(null, script, separator, DEFAULT_COMMENT_PREFIX, DEFAULT_BLOCK_COMMENT_START_DELIMITER,
DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements);
DEFAULT_BLOCK_COMMENT_END_DELIMITER, statements);
}
/**
@@ -276,6 +270,7 @@ public abstract class ScriptUtils {
*/
private static String readScript(EncodedResource resource, String commentPrefix, String separator)
throws IOException {
LineNumberReader lnr = new LineNumberReader(resource.getReader());
try {
return readScript(lnr, commentPrefix, separator);
@@ -302,6 +297,7 @@ public abstract class ScriptUtils {
*/
public static String readScript(LineNumberReader lineNumberReader, String commentPrefix, String separator)
throws IOException {
String currentStatement = lineNumberReader.readLine();
StringBuilder scriptBuilder = new StringBuilder();
while (currentStatement != null) {
@@ -431,9 +427,8 @@ public abstract class ScriptUtils {
if (logger.isInfoEnabled()) {
logger.info("Executing SQL script from " + resource);
}
long startTime = System.currentTimeMillis();
List<String> statements = new LinkedList<String>();
String script;
try {
script = readScript(resource, commentPrefix, separator);
@@ -449,13 +444,15 @@ public abstract class ScriptUtils {
separator = FALLBACK_STATEMENT_SEPARATOR;
}
List<String> statements = new LinkedList<String>();
splitSqlScript(resource, script, separator, commentPrefix, blockCommentStartDelimiter,
blockCommentEndDelimiter, statements);
int lineNumber = 0;
blockCommentEndDelimiter, statements);
int stmtNumber = 0;
Statement stmt = connection.createStatement();
try {
for (String statement : statements) {
lineNumber++;
stmtNumber++;
try {
stmt.execute(statement);
int rowsAffected = stmt.getUpdateCount();
@@ -467,12 +464,12 @@ public abstract class ScriptUtils {
boolean dropStatement = StringUtils.startsWithIgnoreCase(statement.trim(), "drop");
if (continueOnError || (dropStatement && ignoreFailedDrops)) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to execute SQL script statement at line " + lineNumber
+ " of resource " + resource + ": " + statement, ex);
logger.debug("Failed to execute SQL script statement #" + stmtNumber +
" of resource " + resource + ": " + statement, ex);
}
}
else {
throw new ScriptStatementFailedException(statement, lineNumber, resource, ex);
throw new ScriptStatementFailedException(statement, stmtNumber, resource, ex);
}
}
}
@@ -495,7 +492,6 @@ public abstract class ScriptUtils {
if (ex instanceof ScriptException) {
throw (ScriptException) ex;
}
throw new UncategorizedScriptException(
"Failed to execute database script from resource [" + resource + "]", ex);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import org.springframework.util.ReflectionUtils;
/**
* Implementation of the {@link NativeJdbcExtractor} interface for the
* Jakarta Commons DBCP connection pool, version 1.1 or higher.
* Apache Commons DBCP connection pool, version 1.1 or higher.
*
* <p>Returns the underlying native Connection, Statement, etc to application
* code instead of DBCP's wrapper implementations. The returned JDBC classes
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,7 +42,7 @@ import java.sql.Statement;
*
* <p>When working with a simple connection pool that wraps Connections but not
* Statements, a {@link SimpleNativeJdbcExtractor} is often sufficient. However,
* some pools (like Jakarta's Commons DBCP) wrap <i>all</i> JDBC objects that they
* some pools (like Apache's Commons DBCP) wrap <i>all</i> JDBC objects that they
* return: Therefore, you need to use a specific {@code NativeJdbcExtractor}
* (like {@link CommonsDbcpNativeJdbcExtractor}) with them.
*

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