Compare commits

...

86 Commits

Author SHA1 Message Date
Spring Buildmaster 44ae54f252 Release version 4.0.4 2014-04-30 15:40:58 -07:00
Juergen Hoeller 8f175046c8 spring-orm-hibernate4 requires aopalliance dependency now (after propdeps upgrade) 2014-04-30 23:19:07 +02:00
Juergen Hoeller c1dbd9f150 Upgraded to propdeps plugin 0.0.6
(cherry picked from commit a842b93)
2014-04-30 22:58:56 +02:00
Juergen Hoeller 42a35ef3be AnnotationMetadataReadingVisitor passes metaAnnotationMap into getMergedAnnotationAttributes algorithm, for finding out about applicable overrides
Issue: SPR-11649
(cherry picked from commit 842a8a8)
2014-04-30 22:57:09 +02:00
Rossen Stoyanchev 21fd68150a Log ignored CONNECT messages at error level
Issue: SPR-11673
2014-04-30 11:12:32 -04:00
Rossen Stoyanchev d20259be1d Log STOMP ERROR frames at error level
Issue: SPR-11673
2014-04-30 11:01:18 -04:00
Rossen Stoyanchev 6ca921021c Update log level
Issue: SPR-11673
2014-04-30 10:28:27 -04:00
Rossen Stoyanchev eab9d24c31 Fix Javadoc typo 2014-04-30 10:07:51 -04:00
Juergen Hoeller 15749c2a9d Upgraded to Gradle 1.12 and updated several dependencies to latest maintenance releases
(cherry picked from commit e84f61b)
2014-04-30 14:32:12 +02:00
Juergen Hoeller 93b0f0b126 JRubyScriptUtils defensively handles null Nodes in findClassNode (fails against JRuby 1.7.12 otherwise)
Issue: SPR-11747
(cherry picked from commit adb616b)
2014-04-30 14:32:07 +02:00
Juergen Hoeller 27b2ed1614 Spring Framework build uses Reactor 1.1 GA now, getting rid of last remaining pre-GA dependency 2014-04-30 11:41:57 +02:00
Rossen Stoyanchev 790d62bcb1 Simplify and improve STOMP broker relay int tests 2014-04-29 23:01:40 -04:00
Rossen Stoyanchev 563476f57c Split destination cache into access vs update
Issue: SPR-11657
2014-04-29 22:16:49 -04:00
Rossen Stoyanchev 79de45b805 Add cache limit to DefaultSessionRegistry and polish
Issue: SPR-11657
2014-04-29 18:17:40 -04:00
Sebastien Deleuze 63a868dafb Fix DefaultSubscriptionRegistry when using pattern destinations
DestinationCache is now used for both plain and pattern
destinations. It stores internally the subscriptions map for each
cached destination. Subscriptions are initially created when there
is no cache for the requested destination, and are updated when
subscriptions change.

Issue: SPR-11657
2014-04-29 18:17:30 -04:00
Juergen Hoeller 1afdd9bd75 Polishing
(cherry picked from commit 02aca9c)
2014-04-30 00:10:58 +02:00
Juergen Hoeller d0c839f0eb Polishing 2014-04-29 16:21:06 +02:00
Juergen Hoeller 744727b8aa AbstractAdvisingBeanPostProcessor uses target class check for existing proxy but checks against actual exposed object otherwise (catching introductions)
Issue: SPR-11725
(cherry picked from commit a0658c5)
2014-04-29 16:01:44 +02:00
Rossen Stoyanchev 9fbb7394e2 Polish STOMP documentation 2014-04-28 22:35:51 -04:00
Sebastien Deleuze 80cb0c4e5b Include more guidance about DispatcherServlet context
Also update <mvc:annotation-driven /> comment in XSD.

Issue: SPR-11703
2014-04-28 22:10:52 -04:00
Rossen Stoyanchev 5c4804f4a4 Document STOMP-related ApplicationContext events
Issue: SPR-11672
2014-04-28 21:59:09 -04:00
Juergen Hoeller a679f3e7a3 Polishing
(cherry picked from commit be5f2a8)
2014-04-28 23:52:23 +02:00
Juergen Hoeller bd5b3749c5 Revised @PropertySource parsing for consistent PropertySource naming, avoiding accidental overriding by name
Issue: SPR-11637
(cherry picked from commit ab24dda)
2014-04-28 23:47:33 +02:00
Juergen Hoeller 89398b0811 AspectJExpressionPointcut defensively handles fallback expression parsing
Issue: SPR-9335
(cherry picked from commit ce4912b)
2014-04-28 23:47:25 +02:00
Juergen Hoeller a87c9b8c5c Test for base package specified as config location
Issue: SPR-11647
(cherry picked from commit 8e6e6c2)
2014-04-28 23:47:14 +02:00
Juergen Hoeller d0f9853769 Test for overriding singleton @Bean method with scoped proxy in configuration subclass
Issue: SPR-10744
(cherry picked from commit 299776f)
2014-04-28 23:46:51 +02:00
Juergen Hoeller bed739ce92 GenericBeanDefinition's toString() takes parent definition into account
Issue: SPR-9671
(cherry picked from commit 0ef29b2)
2014-04-28 23:46:40 +02:00
Rossen Stoyanchev cb712afa97 Improve handling of disconnects in STOMP broker relay
This is a backport of:
https://github.com/spring-projects/spring-framework/commit/990f5bb720ac172fa659a59339df06065d31c0bf

Issue: SPR-11655
2014-04-28 10:08:00 -04:00
Juergen Hoeller c97c246940 Polishing 2014-04-28 00:29:04 +02:00
Juergen Hoeller 4196e6c96f AbstractMarshaller avoids SAXSource workaround when processExternalEntities=true
Issue: SPR-11737
(cherry picked from commit 93d13cf)
2014-04-28 00:27:04 +02:00
Juergen Hoeller 59cef3ce81 General defensiveness about the bootstrap ClassLoader (i.e. null ClassLoader)
Issue: SPR-11721
2014-04-28 00:26:18 +02:00
Juergen Hoeller c8ea80d7ed Configuration class processing explicitly skips java.* classes since we'll never find @Bean annotations there anyway
Issue: SPR-11718
(cherry picked from commit 470e9c8)
2014-04-28 00:17:19 +02:00
Juergen Hoeller 656fc52ff9 @Bean processing explicitly ignores bridge methods (for method overrides with return type narrowing on JDK 8)
Issue: SPR-11718
(cherry picked from commit dc93406)
2014-04-28 00:16:38 +02:00
Rossen Stoyanchev a4d6f8473e Upgrade to reactor 1.1 RC1 2014-04-25 12:32:36 -04:00
Rossen Stoyanchev 443fb8e4ee Fix issue with subscribe destination
The original fix for SPR-11423:
https://github.com/spring-projects/spring-framework/commit/32e5f57e647022d9ea82c03670936bf31f8467de

was insufficient when using an external broker since the original
destination header has to be in the "native headers" map (i.e. with
STOMP headers) in order to be included in messages broadcast by
the broker.
2014-04-25 12:17:08 -04:00
Juergen Hoeller 95b1cb7173 AspectJ 1.8 final used in build, plus TestNG preparations for optional -target 1.8 usage
Issue: SPR-11212
Issue: SPR-11699
2014-04-24 11:09:39 +02:00
Juergen Hoeller 51fb485181 Polishing
(cherry picked from commit 9353332)
2014-04-24 10:32:38 +02:00
Juergen Hoeller f16e6c4105 General defensiveness about the bootstrap ClassLoader (i.e. null ClassLoader)
Issue: SPR-11721
(cherry picked from commit c05ab3e)
2014-04-24 10:31:48 +02:00
Juergen Hoeller 4dbc0c296c Polishing
(cherry picked from commit ec7d80b)
2014-04-24 10:31:39 +02:00
Juergen Hoeller d71d38bfaf ServletServerHttpResponse specifically checks for Servlet 3.0's HttpServletResponse.getHeader(String) method
Issue: SPR-11712
(cherry picked from commit 21f9ca0)
2014-04-24 10:31:29 +02:00
Juergen Hoeller eb28259371 SpringProperties falls back to ClassLoader.getSystemResource when loaded in bootstrap ClassLoader
Issue: SPR-11721
(cherry picked from commit 9cb5f48)
2014-04-24 10:31:20 +02:00
Juergen Hoeller 7ae6a60f43 checkNotModified leniently handles IE-10-style If-Modified-Since values and silently proceeds if header value cannot be parsed at all
Issue: SPR-11727
(cherry picked from commit 794e859)
2014-04-24 10:30:49 +02:00
Juergen Hoeller d3c9a31e9a DispatcherServlet skips multipart resolution if error page exception attribute indicates MultipartException as root cause
Issue: SPR-11716
(cherry picked from commit 5b47816)
2014-04-24 10:30:12 +02:00
Juergen Hoeller 5aa126600f Final patches from ASM 5.0.2 release
Issue: SPR-11212
(cherry picked from commit fb66567)
2014-04-24 10:29:50 +02:00
Juergen Hoeller 2f15f72fcc ShallowEtagHeaderFilter writes body early on sendError/sendRedirect and interprets setContentLength/setBufferSize as a hint for capacity increase
Issue: SPR-11705
Issue: SPR-11717
(cherry picked from commit 3f392e3)
2014-04-24 10:28:42 +02:00
Juergen Hoeller d5aacdefd9 Polishing
(cherry picked from commit 700c3b2)
2014-04-24 10:27:43 +02:00
Juergen Hoeller e379e77b96 considerInterfaces should work without considerInherited as well
Issue: SPR-11719
(cherry picked from commit 5ab7076)
2014-04-24 10:27:15 +02:00
Juergen Hoeller 9c45755890 AnnotationTypeFilter prevents ASM-based loading of java.* interfaces as well
Issue: SPR-11719
(cherry picked from commit 945335d)
2014-04-24 10:26:42 +02:00
Juergen Hoeller 5962fc2590 EQ/NE do not fail in case of a Comparable mismatch and apply a specific CharSequence equality check
Issue: SPR-11708
(cherry picked from commit 66bae99)
2014-04-24 10:26:08 +02:00
Rossen Stoyanchev 1b59b4eb26 Add Reactor 11 support
This change adds support for Reactor 1.1 in spring-messaging in
addition to Reactor 1.0.1 -- whichever is present on the classpath is
used.

Note also the module name change:
reactor-tcp:1.0.1 -> reactor-net:1.1.0

Issue: SPR-11636
2014-04-23 23:35:49 -04:00
HejiaHo f6b89c2ca9 Fix ConcurrentReferenceHashMap max constraints
Update calculateShift to respect the maximum upper bound as well as the
minimum value.

Issue: SPR-11720

(cherry picked from commit 16410cad)
2014-04-22 15:03:23 +01:00
Sam Brannen 82c32db5a1 Don't mutate annotation metadata when merging attrs
Prior to this commit, invoking the getMergedAnnotationAttributes()
method in AnnotationReadingVisitorUtils resulted in mutation of the
internal state of the ASM-based annotation metadata supplied to the
method.

This commit fixes this issue by making a copy of the original
AnnotationAttributes for the target annotation before merging attribute
values from the meta-annotation hierarchy.

This commit also introduces a slight performance improvement by
avoiding duplicate processing of the attributes of the target
annotation.

Issue: SPR-11710
(cherry picked from commit e1720d89fc)
2014-04-21 12:50:27 -04:00
Juergen Hoeller 52f580149f Polishing 2014-04-17 22:42:33 +02:00
Juergen Hoeller 271fe4f554 Polishing
(cherry picked from commit 48c977a)
2014-04-17 22:14:31 +02:00
Juergen Hoeller 02e8198283 MessageConversionException offers constructor without cause argument now, plus related polishing
Issue: SPR-11653
(cherry picked from commit 2888775)
2014-04-17 22:14:01 +02:00
Juergen Hoeller 090ab4bb6d XStreamMarshaller supports custom NameCoder strategy
Issue: SPR-11702
(cherry picked from commit f5cce14)
2014-04-17 21:39:34 +02:00
Juergen Hoeller 18ef1d4f76 WebSocket intro correctly points to annotations section
Issue: SPR-11667
(cherry picked from commit 53162e7)
2014-04-17 21:39:02 +02:00
Juergen Hoeller d9cb44527c Backported tests for package-visible methods with CGLIB proxies
Issue: SPR-11618
(cherry picked from commit 90309ab)
2014-04-17 21:38:01 +02:00
Juergen Hoeller 8e44521ec4 Latest ASM patches (fix for bug 317151 from ASM HEAD; ASM's 1.8 bytecode processing needs to be lenient with CGLIB 3.1)
Issue: SPR-11212
(cherry picked from commit 637ad20)
2014-04-17 21:34:57 +02:00
Juergen Hoeller d28c6d8bdb Consistent documentation for both 'close' and 'shutdown' as inferred destroy methods
Issue: SPR-11680
(cherry picked from commit 14f9dbf)
2014-04-17 21:32:09 +02:00
Juergen Hoeller c9432ce499 JDBC 3.0 related javadoc overhaul
Issue: SPR-11600
(cherry picked from commit 3fef358)
2014-04-17 21:31:45 +02:00
Stephane Nicoll 2d8e0c8f87 Fix expression cache
Prior to this commit, only the java.lang.reflect.Method was used to
identify an annotated method. As a result, if different annotations
were placed on different methods (method overriding, interface
implementation) only the first one (cached) was used.

LazyParamAwareEvaluationContext was affected by the exact
same problem and has been also fixed.

Issue: SPR-11692
(cherry picked from commit df34bab)
2014-04-15 09:29:56 +02:00
Sam Brannen 03ae8eeb95 Make EOF_STATEMENT_SEPARATOR XML friendly
Changed the value of ScriptUtils.EOF_STATEMENT_SEPARATOR from
"<<< END OF SCRIPT >>>" to "^^^ END OF SCRIPT ^^^" so that the angle
brackets do not have to be escaped in XML configuration files.

Issue: SPR-11687
(cherry picked from commit 1753f5d1ca)
2014-04-11 18:27:59 +02:00
Sam Brannen 9230b38aea Support EOF as statement separator in SQL scripts
Prior to Spring Framework 4.0.3, it was possible to supply a bogus
statement separator (i.e., a separator string that does not exist in
the configured SQL scripts) to ResourceDatabasePopulator with the side
effect that the entire contents of a script file would be interpreted
as a single SQL statement.

This undocumented feature was never intentional; however, some
developers came to rely on it. Unfortunately, changes made in
conjunction with SPR-9531 and SPR-11560 caused such scenarios to no
longer work.

This commit introduces first-class support for executing scripts which
contain a single statement that spans multiple lines but is not
followed by an explicit statement separator.

Specifically, ScriptUtils.EOF_STATEMENT_SEPARATOR may now be specified
as a 'virtual' statement separator to denote that a script contains a
single statement and no actual separator.

Issue: SPR-11687
(cherry picked from commit cc0ae3a881)
2014-04-11 18:25:06 +02:00
Sam Brannen d5ce30f360 Deprecate custom/default CtxLdr class name in TCF
Once the new bootstrap strategy for the TestContext framework (TCF) is
introduced in Spring Framework 4.1, a TestContextBootstrapper will
assume full responsibility for determining what ContextLoader to use as
the default. Consequently, the previous support for supplying the class
name for a custom, default ContextLoader will no longer be applicable.

This commit therefore officially deprecates support for custom, default
ContextLoader class names via the following mechanisms:

 - The TestContextManager(Class, String) constructor

 - The getDefaultContextLoaderClassName(Class) method in
   SpringJUnit4ClassRunner

Issue: SPR-11682
2014-04-10 17:54:14 +02:00
Sam Brannen 428aee5b72 Deprecate getDefTELClasses in TestContextMgr
Since a dedicated bootstrap strategy will be introduced for the
TestContext framework in Spring Framework 4.1, this commit officially
deprecates TestContextManager.getDefaultTestExecutionListenerClasses()
as a forewarning to developers or frameworks that may be using this
obscure feature.

Issue: SPR-11679
2014-04-09 22:20:43 +02:00
Juergen Hoeller f7a17added AbstractMarshaller uses general exception message in extracted buildDocument() method
Issue: SPR-11635
2014-04-09 20:54:41 +02:00
Juergen Hoeller 196f629a20 JBoss "vfszip" resources need to be treated as jar URLs
Issue: SPR-11676
(cherry picked from commit be6b54f)
2014-04-09 20:51:23 +02:00
Juergen Hoeller 7135e729e2 Dropped JCache RC repo (now unused); minor dependency upgrades
Issue: SPR-11640
(cherry picked from commit 9e1631d)
2014-04-09 19:00:44 +02:00
Juergen Hoeller 21874627d2 Polishing
Issue: SPR-11637
(cherry picked from commit 0041e24)
2014-04-09 19:00:23 +02:00
Juergen Hoeller 3ab88b857b AbstractMarshaller pre-implements getDefaultEncoding() method
Issue: SPR-11635
(cherry picked from commit d4b0ae9)
2014-04-09 19:00:08 +02:00
Juergen Hoeller 294545d07a XStreamMarshaller lazily creates fallback XppDriver
Issue: SPR-11635
(cherry picked from commit 8f28a93)
2014-04-09 18:59:47 +02:00
Juergen Hoeller 38cd79047a SelectTag correctly detects multiple="true" again
Issue: SPR-11678
(cherry picked from commit 8d8766d)
2014-04-09 18:59:37 +02:00
Stephane Nicoll 8a779c32d5 Update to JCache 1.0.0 final
Issue: SPR-11640
(cherry picked from commit 0bdece7)
2014-04-08 15:20:57 +02:00
Sam Brannen 7ba31dee45 Use unconstrained quotes in reference manual
Prior to this commit, there were numerous places in the reference
manual, where we see output similar to the following:

    BeanDefinition`s with the `ApplicationContext

This commit addresses this issue by using unconstrained quotes
(e.g., ++XYZ++s) instead of backticks (e.g., `XYZ`s) when the formatted
text is immediately followed by an "s".

This commit also corrects a few typos and corrects natural English
pluralization of Java code elements in the reference manual where
appropriate -- for example, "@Controllers" becomes "@Controller classes,
etc.

Issue: SPR-11650
(cherry picked from commit 0eba1f818f)
2014-04-04 22:05:43 +02:00
Brian Clozel 1c45d7573c Fix @SubscribeMapping MESSAGE response destination
Prior to this commit, @SubscribeMapping mapped methods (backed with
@SendTo* annotations, or not) would send MESSAGEs with the wrong
destination. Instead of using the original SUBSCRIBE destination, it
would use the lookup path computed from the configured prefixes in the
application.

This commit fixes this issue - now @SubscribeMapping MESSAGEs use the
original SUBSCRIBE destination.

Issue: SPR-11648
2014-04-04 12:45:19 +02:00
Juergen Hoeller f014bbb5cf Revised ByteArrayOutputStream handling in MarshallingView and co
Issue: SPR-11646
(cherry picked from commit 8006696)
2014-04-02 21:29:37 +02:00
Juergen Hoeller d1030b798d ResourceHttpRequestHandler explicitly closes a Resource's InputStream
Issue: SPR-11644
(cherry picked from commit 3a96f16)
2014-04-02 21:29:05 +02:00
Juergen Hoeller d628025f13 Polishing
Issue: SPR-11262
2014-04-02 21:28:42 +02:00
Rossen Stoyanchev 30ea1a3475 Fix issue with default executor for message channels
This change ensures correct default settings for message channel's
created through the websocket message-broker XML namespace even
when the channels are customized for other reasons -- e.g. to add
a channel interceptor.

Issue: SPR-11623
2014-04-01 14:16:10 -04:00
Rossen Stoyanchev 7b014eaa55 Improve access to WebSocketSession fields
Ensure the Standard- and the JettyWebSocketSession can return the
Principal and accepted WebSocket sub-protocol even after the
session is closed.

Issue: SPR-11621
2014-04-01 14:16:10 -04:00
Rossen Stoyanchev e21c47d4ce Optimize performance in StompEncoder/Decoder escaping
Issue: SPR-11643
2014-04-01 14:16:10 -04:00
Rossen Stoyanchev 632ae6a4df Improve shutdown responsiveness of SubProtocolWSH
Proactively notify all active WebSocket sessions when a shutdown is
progress. Sessions then can ignore further attempts to send messages
and also stop stop trying to flush messages right away.
2014-04-01 14:16:10 -04:00
Sam Brannen 989f6194b6 Support classes AND locations in @ContextConfiguration
Prior to this commit, the Spring TestContext Framework did not support
the declaration of both 'locations' and 'classes' within
@ContextConfiguration at the same time.

This commit addresses this in the following manner:

 - ContextConfigurationAttributes no longer throws an
   IllegalArgumentException if both 'locations' and 'classes' are
   supplied to its constructor.

 - Concrete SmartContextLoader implementations now validate the
   supplied MergedContextConfiguration before attempting to load the
   ApplicationContext. See validateMergedContextConfiguration().

 - Introduced tests for hybrid context loaders like the one used in
   Spring Boot. See HybridContextLoaderTests.

 - Updated the Testing chapter of the reference manual so that it no
   longer states that locations and classes cannot be used
   simultaneously, mentioning Spring Boot as well.

 - The Javadoc for @ContextConfiguration has been updated accordingly.

 - Added hasLocations(), hasClasses(), and hasResources() convenience
   methods to MergedContextConfiguration.

Issue: SPR-11634
(cherry picked from commit 1f017c4acb)
2014-04-01 19:54:04 +02:00
Sam Brannen 17bf5b991f Update Javadoc for supported JBoss VFS version
(cherry picked from commit 34eb4dba3a)
2014-03-30 16:02:27 +02:00
Sam Brannen cd9d7cfe4f Reinject Servlet mocks between TestNG test methods
Prior to this commit, if multiple test methods were executed in a
subclass of AbstractTestNGSpringContextTests annotated with
@WebAppConfiguration, then injected Servlet API mocks would only
reference the mocks created for the first test method. Subsequent test
methods could therefore never reference the current mocks, and there
was a discrepancy between the state of the injected mocks and the mock
set in the RequestContextHolder.

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

Issue: SPR-11626
(cherry picked from commit c38600762d)
2014-03-29 21:46:58 +01:00
205 changed files with 5082 additions and 2187 deletions
+38 -35
View File
@@ -3,7 +3,7 @@ buildscript {
maven { url "http://repo.springsource.org/plugins-release" }
}
dependencies {
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.5")
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.6")
classpath("org.asciidoctor:asciidoctor-gradle-plugin:0.7.0")
classpath("org.springframework.build.gradle:docbook-reference-plugin:0.2.8")
}
@@ -16,18 +16,19 @@ configure(allprojects) { project ->
ext.aspectjVersion = "1.7.4"
ext.groovyVersion = "1.8.9"
ext.hibernate3Version = "3.6.10.Final"
ext.hibernate4Version = "4.2.11.Final"
ext.hibernate4Version = "4.2.12.Final"
ext.hibValVersion = "4.3.1.Final"
ext.hsqldbVersion = "2.3.2"
ext.jackson1Version = "1.9.13"
ext.jackson2Version = "2.3.1"
ext.jackson2Version = "2.3.3"
ext.jasperReportsVersion = "5.5.1"
ext.jettyVersion = "9.1.3.v20140225"
ext.jettyVersion = "9.1.4.v20140401"
ext.jodaVersion = "2.3"
ext.junitVersion = "4.11"
ext.slf4jVersion = "1.7.6"
ext.slf4jVersion = "1.7.7"
ext.tiles2Version = "2.2.2"
ext.tiles3Version = "3.0.3"
ext.tomcatVersion = "8.0.5"
ext.xstreamVersion = "1.4.7"
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
@@ -71,14 +72,12 @@ configure(allprojects) { project ->
include(["**/*Tests.class", "**/*Test.class"])
// Since we set scanForTestClasses to false, we need to filter out inner
// classes with the "$" pattern; otherwise, using -Dtest.single=MyTests to
// run MyTests by itself will fail if MyTests contains any inner classes.
// run MyTests by itself will fail if MyTests contains any inner classes.
exclude(["**/Abstract*.class", '**/*$*'])
}
repositories {
maven { url "http://repo.spring.io/libs-release" }
maven { url "http://repo.spring.io/milestone" } // for AspectJ 1.8.0.M1
maven { url "https://oss.sonatype.org/content/repositories/releases" } // javax.cache
}
dependencies {
@@ -93,7 +92,7 @@ configure(allprojects) { project ->
ext.javadocLinks = [
"http://docs.oracle.com/javase/7/docs/api/",
"http://docs.oracle.com/javaee/6/api/",
"http://docs.oracle.com/javaee/7/api/",
"http://docs.oracle.com/cd/E13222_01/wls/docs90/javadocs/", // CommonJ
"http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.javadoc.doc/web/apidocs/",
"http://glassfish.java.net/nonav/docs/v3/api/",
@@ -376,7 +375,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.10")
optional("org.jruby:jruby:1.7.12")
testCompile("javax.inject:javax.inject-tck:1")
testCompile("commons-dbcp:commons-dbcp:1.4")
testCompile("org.slf4j:slf4j-api:${slf4jVersion}")
@@ -397,7 +396,8 @@ project("spring-messaging") {
compile(project(":spring-beans"))
compile(project(":spring-core"))
compile(project(":spring-context"))
optional("org.projectreactor:reactor-core:1.0.1.RELEASE")
optional("org.projectreactor:reactor-core:1.1.0.RELEASE")
optional("org.projectreactor:reactor-net:1.1.0.RELEASE")
optional("org.projectreactor:reactor-tcp:1.0.1.RELEASE")
optional("org.eclipse.jetty.websocket:websocket-server:${jettyVersion}") {
exclude group: "javax.servlet", module: "javax.servlet-api"
@@ -417,9 +417,9 @@ project("spring-messaging") {
testCompile("org.eclipse.jetty:jetty-webapp:${jettyVersion}") {
exclude group: "javax.servlet", module: "javax.servlet-api"
}
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
testCompile("commons-dbcp:commons-dbcp:1.4")
testCompile("log4j:log4j:1.2.17")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
@@ -458,8 +458,9 @@ project("spring-oxm") {
dependencies {
compile(project(":spring-beans"))
compile(project(":spring-core"))
optional("org.codehaus.castor:castor-xml:1.3.2") {
optional("org.codehaus.castor:castor-xml:1.3.3") {
exclude group: 'stax', module: 'stax-api'
exclude group: "org.springframework", module: "spring-context"
}
optional("org.apache.xmlbeans:xmlbeans:2.6.0") {
exclude group: 'stax', module: 'stax-api'
@@ -509,11 +510,11 @@ project("spring-jdbc") {
compile(project(":spring-tx"))
optional(project(":spring-context")) // for JndiDataSourceLookup
optional("javax.transaction:javax.transaction-api:1.2")
optional("c3p0:c3p0:0.9.1.2")
optional("com.mchange:c3p0:0.9.2.1")
optional("org.hsqldb:hsqldb:${hsqldbVersion}")
optional("com.h2database:h2:1.0.71")
optional("org.apache.derby:derby:10.10.1.1")
optional("org.apache.derby:derbyclient:10.10.1.1")
optional("com.h2database:h2:1.3.176")
optional("org.apache.derby:derby:10.10.2.0")
optional("org.apache.derby:derbyclient:10.10.2.0")
}
}
@@ -527,8 +528,8 @@ project("spring-context-support") {
optional(project(":spring-jdbc")) // for Quartz support
optional(project(":spring-tx")) // for Quartz support
optional("javax.mail:mail:1.4.7")
optional("javax.cache:cache-api:1.0.0-RC1")
optional("com.google.guava:guava:16.0.1")
optional("javax.cache:cache-api:1.0.0")
optional("com.google.guava:guava:17.0")
optional("net.sf.ehcache:ehcache-core:2.6.5")
optional("org.quartz-scheduler:quartz:1.8.6") {
exclude group: "org.slf4j", module: "slf4j-log4j12"
@@ -538,7 +539,7 @@ project("spring-context-support") {
optional("org.freemarker:freemarker:2.3.20")
optional("com.lowagie:itext:2.1.7")
optional("net.sf.jasperreports:jasperreports:$jasperReportsVersion")
testCompile("org.apache.poi:poi:3.9")
testCompile("org.apache.poi:poi:3.10-FINAL")
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}")
@@ -599,7 +600,7 @@ project("spring-websocket") {
optional(project(":spring-webmvc"))
optional("javax.servlet:javax.servlet-api:3.1.0")
optional("javax.websocket:javax.websocket-api:1.0")
optional("org.apache.tomcat:tomcat-websocket:8.0.3") {
optional("org.apache.tomcat:tomcat-websocket:${tomcatVersion}") {
exclude group: "org.apache.tomcat", module: "tomcat-websocket-api"
exclude group: "org.apache.tomcat", module: "tomcat-servlet-api"
}
@@ -612,20 +613,20 @@ project("spring-websocket") {
exclude group: "javax.servlet", module: "javax.servlet"
}
optional("org.eclipse.jetty.websocket:websocket-client:${jettyVersion}")
optional("io.undertow:undertow-core:1.0.0.Final")
optional("io.undertow:undertow-servlet:1.0.0.Final") {
optional("io.undertow:undertow-core:1.0.1.Final")
optional("io.undertow:undertow-servlet:1.0.1.Final") {
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_3.1_spec"
exclude group: "org.jboss.spec.javax.annotation", module: "jboss-annotations-api_1.2_spec"
}
optional("io.undertow:undertow-websockets-jsr:1.0.0.Final") {
optional("io.undertow:undertow-websockets-jsr:1.0.1.Final") {
exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.0_spec"
}
optional("com.fasterxml.jackson.core:jackson-databind:${jackson2Version}")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0.3")
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:8.0.3")
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0.3")
testCompile("org.projectreactor:reactor-core:1.0.1.RELEASE")
testCompile("org.projectreactor:reactor-tcp:1.0.1.RELEASE")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}")
testCompile("org.projectreactor:reactor-core:1.1.0.RELEASE")
testCompile("org.projectreactor:reactor-net:1.1.0.RELEASE")
testCompile("log4j:log4j:1.2.17")
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
}
@@ -682,6 +683,7 @@ project("spring-orm-hibernate4") {
optional("org.hibernate:hibernate-core:${hibernate4Version}")
optional("org.hibernate:hibernate-entitymanager:${hibernate4Version}")
optional("javax.servlet:javax.servlet-api:3.0.1")
optional("aopalliance:aopalliance:1.0")
}
}
@@ -701,7 +703,7 @@ project("spring-webmvc") {
optional("javax.servlet.jsp:jsp-api:2.2")
optional("javax.servlet:jstl:1.2")
optional("net.sourceforge.jexcelapi:jxl:2.6.12")
optional("org.apache.poi:poi:3.9")
optional("org.apache.poi:poi:3.10-FINAL")
optional("org.apache.velocity:velocity:1.7")
optional("velocity-tools:velocity-tools-view:1.4")
optional("org.freemarker:freemarker:2.3.20")
@@ -863,6 +865,7 @@ project("spring-test") {
task testNG(type: Test) {
useTestNG()
scanForTestClasses = false
include(["**/testng/**/*Tests.class", "**/testng/**/*Test.class"])
// Show STD_OUT & STD_ERR of the test JVM(s) on the console:
// testLogging.showStandardStreams = true
@@ -889,8 +892,8 @@ project("spring-aspects") {
dependencies {
aspects(project(":spring-orm"))
ajc("org.aspectj:aspectjtools:1.8.0.RC2") // needed for ajc on JDK 8 only
rt("org.aspectj:aspectjrt:1.8.0.RC2") // needed for ajc on JDK 8 only
ajc("org.aspectj:aspectjtools:1.8.0") // needed for ajc on JDK 8 only
rt("org.aspectj:aspectjrt:1.8.0") // needed for ajc on JDK 8 only
compile("org.aspectj:aspectjweaver:${aspectjVersion}") // exposing regular AspectJ version to users
provided("org.eclipse.persistence:javax.persistence:2.0.0")
optional(project(":spring-aop")) // for @Async support
@@ -1175,7 +1178,7 @@ configure(rootProject) {
task wrapper(type: Wrapper) {
description = "Generates gradlew[.bat] scripts"
gradleVersion = "1.11"
gradleVersion = "1.12"
doLast() {
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
+1 -1
View File
@@ -1 +1 @@
version=4.0.4.BUILD-SNAPSHOT
version=4.0.4.RELEASE
Binary file not shown.
+2 -2
View File
@@ -1,6 +1,6 @@
#Wed Feb 12 23:28:21 CET 2014
#Wed Apr 30 13:06:57 CEST 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
@@ -29,7 +29,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.weaver.BCException;
import org.aspectj.weaver.patterns.NamePattern;
import org.aspectj.weaver.reflect.ReflectionWorld;
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ContextBasedMatcher;
@@ -108,6 +107,8 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
private BeanFactory beanFactory;
private transient ClassLoader pointcutClassLoader;
private transient PointcutExpression pointcutExpression;
private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<Method, ShadowMatch>(32);
@@ -185,20 +186,13 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
throw new IllegalStateException("Must set property 'expression' before attempting to match");
}
if (this.pointcutExpression == null) {
this.pointcutExpression = buildPointcutExpression();
this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
ClassUtils.getDefaultClassLoader());
this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
}
}
/**
* Build the underlying AspectJ pointcut expression.
*/
private PointcutExpression buildPointcutExpression() {
ClassLoader cl = (this.beanFactory instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
ClassUtils.getDefaultClassLoader());
return buildPointcutExpression(cl);
}
/**
* Build the underlying AspectJ pointcut expression.
*/
@@ -252,23 +246,22 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
public boolean matches(Class<?> targetClass) {
checkReadyToMatch();
try {
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
catch (ReflectionWorldException rwe) {
logger.debug("PointcutExpression matching rejected target class", rwe);
try {
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
return getFallbackPointcutExpression(targetClass).couldMatchJoinPointsInType(targetClass);
return this.pointcutExpression.couldMatchJoinPointsInType(targetClass);
}
catch (BCException bce) {
logger.debug("Fallback PointcutExpression matching rejected target class", bce);
return false;
catch (ReflectionWorldException ex) {
logger.debug("PointcutExpression matching rejected target class - trying fallback expression", ex);
// Actually this is still a "maybe" - treat the pointcut as dynamic if we don't know enough yet
PointcutExpression fallbackExpression = getFallbackPointcutExpression(targetClass);
if (fallbackExpression != null) {
return fallbackExpression.couldMatchJoinPointsInType(targetClass);
}
}
}
catch (BCException ex) {
logger.debug("PointcutExpression matching rejected target class", ex);
return false;
}
return false;
}
@Override
@@ -365,12 +358,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
/**
* Get a new pointcut expression based on a target class's loader, rather
* than the default.
* Get a new pointcut expression based on a target class's loader rather than the default.
*/
private PointcutExpression getFallbackPointcutExpression(Class<?> targetClass) {
ClassLoader classLoader = targetClass.getClassLoader();
return (classLoader != null ? buildPointcutExpression(classLoader) : this.pointcutExpression);
try {
ClassLoader classLoader = targetClass.getClassLoader();
if (classLoader != null && classLoader != this.pointcutClassLoader) {
return buildPointcutExpression(classLoader);
}
}
catch (Throwable ex) {
logger.debug("Failed to create fallback PointcutExpression", ex);
}
return null;
}
private RuntimeTestWalker getRuntimeTestWalker(ShadowMatch shadowMatch) {
@@ -396,46 +396,51 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
if (shadowMatch == null) {
synchronized (this.shadowMatchCache) {
// Not found - now check again with full lock...
PointcutExpression fallbackExpression = null;
Method methodToMatch = targetMethod;
PointcutExpression fallbackPointcutExpression = null;
shadowMatch = this.shadowMatchCache.get(methodToMatch);
shadowMatch = this.shadowMatchCache.get(targetMethod);
if (shadowMatch == null) {
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(targetMethod);
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorld.ReflectionWorldException ex) {
catch (ReflectionWorldException ex) {
// Failed to introspect target method, probably because it has been loaded
// in a special ClassLoader. Let's try the original method instead...
// in a special ClassLoader. Let's try the declaring ClassLoader instead...
try {
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorld.ReflectionWorldException ex2) {
if (targetMethod == originalMethod) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
if (fallbackExpression != null) {
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
}
else {
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(originalMethod);
}
catch (ReflectionWorld.ReflectionWorldException ex3) {
// Could neither introspect the target class nor the proxy class ->
// let's simply consider this method as non-matching.
methodToMatch = originalMethod;
fallbackPointcutExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
try {
shadowMatch = fallbackPointcutExpression.matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorld.ReflectionWorldException ex4) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
}
}
catch (ReflectionWorldException ex2) {
fallbackExpression = null;
}
}
if (shadowMatch == null && targetMethod != originalMethod) {
methodToMatch = originalMethod;
try {
shadowMatch = this.pointcutExpression.matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorldException ex3) {
// Could neither introspect the target class nor the proxy class ->
// let's try the original method's declaring class before we give up...
try {
fallbackExpression = getFallbackPointcutExpression(methodToMatch.getDeclaringClass());
if (fallbackExpression != null) {
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
}
}
catch (ReflectionWorldException ex4) {
fallbackExpression = null;
}
}
}
if (shadowMatch.maybeMatches() && fallbackPointcutExpression != null) {
if (shadowMatch == null) {
shadowMatch = new ShadowMatchImpl(org.aspectj.util.FuzzyBoolean.NO, null, null, null);
}
else if (shadowMatch.maybeMatches() && fallbackExpression != null) {
shadowMatch = new DefensiveShadowMatch(shadowMatch,
fallbackPointcutExpression.matchesMethodExecution(methodToMatch));
fallbackExpression.matchesMethodExecution(methodToMatch));
}
this.shadowMatchCache.put(targetMethod, shadowMatch);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,9 +91,11 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (isEligible(bean, beanName)) {
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
@@ -102,32 +104,47 @@ public abstract class AbstractAdvisingBeanPostProcessor extends ProxyConfig
}
return bean;
}
else {
ProxyFactory proxyFactory = new ProxyFactory(bean);
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
}
else {
// No async proxy needed.
return bean;
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = new ProxyFactory(bean);
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
proxyFactory.addAdvisor(this.advisor);
return proxyFactory.getProxy(this.beanClassLoader);
}
// No async proxy needed.
return bean;
}
/**
* Check whether the given bean is eligible for advising with this
* post-processor's {@link Advisor}.
* <p>Implements caching of {@code canApply} results per bean target class.
* <p>Delegates to {@link #isEligible(Class)} for target class checking.
* Can be overridden e.g. to specifically exclude certain beans by name.
* <p>Note: Only called for regular bean instances but not for existing
* proxy instances which implement {@link Advised} and allow for adding
* the local {@link Advisor} to the existing proxy's {@link Advisor} chain.
* For the latter, {@link #isEligible(Class)} is being called directly,
* with the actual target class behind the existing proxy (as determined
* by {@link AopUtils#getTargetClass(Object)}).
* @param bean the bean instance
* @param beanName the name of the bean
* @see AopUtils#getTargetClass(Object)
* @see AopUtils#canApply(Advisor, Class)
* @see #isEligible(Class)
*/
protected boolean isEligible(Object bean, String beanName) {
Class<?> targetClass = AopUtils.getTargetClass(bean);
return isEligible(bean.getClass());
}
/**
* Check whether the given class is eligible for advising with this
* post-processor's {@link Advisor}.
* <p>Implements caching of {@code canApply} results per bean target class.
* @param targetClass the class to check against
* @see AopUtils#canApply(Advisor, Class)
*/
protected boolean isEligible(Class<?> targetClass) {
Boolean eligible = this.eligibleBeans.get(targetClass);
if (eligible != null) {
return eligible;
@@ -261,7 +261,7 @@ class CglibAopProxy implements AopProxy, Serializable {
if (!Object.class.equals(method.getDeclaringClass()) && !Modifier.isStatic(method.getModifiers()) &&
Modifier.isFinal(method.getModifiers())) {
logger.warn("Unable to proxy method [" + method + "] because it is final: " +
"All calls to this method via a proxy will be routed directly to the proxy.");
"All calls to this method via a proxy will NOT be routed to the target instance.");
}
}
}
@@ -604,7 +604,7 @@ class CglibAopProxy implements AopProxy, Serializable {
*/
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private AdvisedSupport advised;
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
@@ -622,8 +622,8 @@ class CglibAopProxy implements AopProxy, Serializable {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool.
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
@@ -689,13 +689,13 @@ class CglibAopProxy implements AopProxy, Serializable {
private final MethodProxy methodProxy;
private boolean protectedMethod;
private final boolean publicMethod;
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
this.methodProxy = methodProxy;
this.protectedMethod = Modifier.isProtected(method.getModifiers());
this.publicMethod = Modifier.isPublic(method.getModifiers());
}
/**
@@ -704,11 +704,11 @@ class CglibAopProxy implements AopProxy, Serializable {
*/
@Override
protected Object invokeJoinpoint() throws Throwable {
if (this.protectedMethod) {
return super.invokeJoinpoint();
if (this.publicMethod) {
return this.methodProxy.invoke(this.target, this.arguments);
}
else {
return this.methodProxy.invoke(this.target, this.arguments);
return super.invokeJoinpoint();
}
}
}
@@ -829,8 +829,8 @@ class CglibAopProxy implements AopProxy, Serializable {
// of the target type. If so we know it never needs to have return type
// massage and can use a dispatcher.
// If the proxy is being exposed, then must use the interceptor the
// correct one is already configured. If the target is not static cannot
// use a Dispatcher because the target can not then be released.
// correct one is already configured. If the target is not static, then
// cannot use a dispatcher because the target cannot be released.
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ package org.springframework.aop.framework;
import org.aopalliance.intercept.Interceptor;
import org.springframework.aop.TargetSource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
@@ -47,9 +46,8 @@ public class ProxyFactory extends ProxyCreatorSupport {
* @param target the target object to be proxied
*/
public ProxyFactory(Object target) {
Assert.notNull(target, "Target object must not be null");
setInterfaces(ClassUtils.getAllInterfaces(target));
setTarget(target);
setInterfaces(ClassUtils.getAllInterfaces(target));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -289,15 +289,15 @@ class TypeConverterDelegate {
if (index > - 1) {
String enumType = trimmedValue.substring(0, index);
String fieldName = trimmedValue.substring(index + 1);
ClassLoader loader = this.targetObject.getClass().getClassLoader();
ClassLoader cl = this.targetObject.getClass().getClassLoader();
try {
Class<?> enumValueType = loader.loadClass(enumType);
Class<?> enumValueType = ClassUtils.forName(enumType, cl);
Field enumField = enumValueType.getField(fieldName);
convertedValue = enumField.get(null);
}
catch (ClassNotFoundException ex) {
if(logger.isTraceEnabled()) {
logger.trace("Enum class [" + enumType + "] cannot be loaded from [" + loader + "]", ex);
logger.trace("Enum class [" + enumType + "] cannot be loaded", ex);
}
}
catch (Throwable ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -135,9 +135,9 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
ClassLoader cl = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,9 +66,9 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
@SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() {
this.qualifierTypes.add(Qualifier.class);
ClassLoader cl = QualifierAnnotationAutowireCandidateResolver.class.getClassLoader();
try {
this.qualifierTypes.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Qualifier"));
this.qualifierTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Qualifier", QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
@@ -38,8 +38,8 @@ import org.springframework.util.StringUtils;
/**
* Base class for concrete, full-fledged
* {@link org.springframework.beans.factory.config.BeanDefinition} classes,
* factoring out common properties of {@link RootBeanDefinition} and
* {@link ChildBeanDefinition}.
* factoring out common properties of {@link GenericBeanDefinition},
* {@link RootBeanDefinition} and {@link ChildBeanDefinition}.
*
* <p>The autowire constants match the ones defined in the
* {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory}
@@ -123,11 +123,14 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
public static final int DEPENDENCY_CHECK_ALL = 3;
/**
* Constant that indicates the container should attempt to infer the {@link
* #setDestroyMethodName destroy method name} for a bean as opposed to explicit
* specification of a method name. The value {@value} is specifically designed to
* include characters otherwise illegal in a method name, ensuring no possibility of
* collisions with legitimately named methods having the same name.
* Constant that indicates the container should attempt to infer the
* {@link #setDestroyMethodName destroy method name} for a bean as opposed to
* explicit specification of a method name. The value {@value} is specifically
* designed to include characters otherwise illegal in a method name, ensuring
* no possibility of collisions with legitimately named methods having the same
* name.
* <p>Currently, the method names detected during destroy method inference
* are "close" and "shutdown", if present on the specific bean class.
*/
public static final String INFER_METHOD = "(inferred)";
@@ -105,9 +105,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
private static Class<?> javaxInjectProviderClass = null;
static {
ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
try {
javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
javaxInjectProviderClass =
ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - Provider interface simply not supported then.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -69,7 +69,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
static {
try {
closeableInterface = DisposableBeanAdapter.class.getClassLoader().loadClass("java.lang.AutoCloseable");
closeableInterface = ClassUtils.forName("java.lang.AutoCloseable",
DisposableBeanAdapter.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
closeableInterface = Closeable.class;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,7 +89,12 @@ public class GenericBeanDefinition extends AbstractBeanDefinition {
@Override
public String toString() {
return "Generic bean: " + super.toString();
StringBuilder sb = new StringBuilder("Generic bean");
if (this.parentName != null) {
sb.append(" with parent '").append(this.parentName).append("'");
}
sb.append(": ").append(super.toString());
return sb.toString();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -261,7 +262,7 @@ public class CronTriggerFactoryBean implements FactoryBean<CronTrigger>, BeanNam
Class<?> cronTriggerClass;
Method jobKeyMethod;
try {
cronTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.CronTriggerImpl");
cronTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.CronTriggerImpl", getClass().getClassLoader());
jobKeyMethod = JobDetail.class.getMethod("getKey");
}
catch (ClassNotFoundException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;
/**
* A Spring {@link FactoryBean} for creating a Quartz {@link org.quartz.JobDetail}
@@ -210,7 +211,7 @@ public class JobDetailFactoryBean
Class<?> jobDetailClass;
try {
jobDetailClass = getClass().getClassLoader().loadClass("org.quartz.impl.JobDetailImpl");
jobDetailClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl", getClass().getClassLoader());
}
catch (ClassNotFoundException ex) {
jobDetailClass = JobDetail.class;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@ public class LocalTaskExecutorThreadPool implements ThreadPool {
@Override
public int blockForAvailableThreads() {
// The present implementation always returns 1, making Quartz (1.6)
// The present implementation always returns 1, making Quartz
// always schedule any tasks that it feels like scheduling.
// This could be made smarter for specific TaskExecutors,
// for example calling {@code getMaximumPoolSize() - getActiveCount()}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,14 +87,15 @@ public class MethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethod
static {
try {
jobDetailImplClass = Class.forName("org.quartz.impl.JobDetailImpl");
jobDetailImplClass = ClassUtils.forName("org.quartz.impl.JobDetailImpl",
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
jobDetailImplClass = null;
}
try {
Class<?> jobExecutionContextClass =
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
Class<?> jobExecutionContextClass = ClassUtils.forName("org.quartz.JobExecutionContext",
MethodInvokingJobDetailFactoryBean.class.getClassLoader());
setResultMethod = jobExecutionContextClass.getMethod("setResult", Object.class);
}
catch (Exception ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import org.quartz.SchedulerException;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -77,7 +78,7 @@ public abstract class QuartzJobBean implements Job {
static {
try {
Class<?> jobExecutionContextClass =
QuartzJobBean.class.getClassLoader().loadClass("org.quartz.JobExecutionContext");
ClassUtils.forName("org.quartz.JobExecutionContext", QuartzJobBean.class.getClassLoader());
getSchedulerMethod = jobExecutionContextClass.getMethod("getScheduler");
getMergedJobDataMapMethod = jobExecutionContextClass.getMethod("getMergedJobDataMap");
}
@@ -43,6 +43,7 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -68,8 +69,8 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
static {
// Quartz 2.0 job/trigger key available?
try {
jobKeyClass = Class.forName("org.quartz.JobKey");
triggerKeyClass = Class.forName("org.quartz.TriggerKey");
jobKeyClass = ClassUtils.forName("org.quartz.JobKey", SchedulerAccessor.class.getClassLoader());
triggerKeyClass = ClassUtils.forName("org.quartz.TriggerKey", SchedulerAccessor.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
jobKeyClass = null;
@@ -151,8 +152,6 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* in combination with the Trigger.
* @see #setTriggers
* @see org.quartz.JobDetail
* @see JobDetailBean
* @see JobDetailAwareTrigger
*/
public void setJobDetails(JobDetail... jobDetails) {
// Use modifiable ArrayList here, to allow for further adding of
@@ -180,15 +179,11 @@ public abstract class SchedulerAccessor implements ResourceLoaderAware {
* "jobDetails" property of this FactoryBean.
* @see #setJobDetails
* @see org.quartz.JobDetail
* @see JobDetailAwareTrigger
* @see CronTriggerBean
* @see SimpleTriggerBean
*/
public void setTriggers(Trigger... triggers) {
this.triggers = Arrays.asList(triggers);
}
/**
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
/**
@@ -245,14 +246,14 @@ public class SimpleTriggerFactoryBean implements FactoryBean<SimpleTrigger>, Bea
sti.setRepeatCount(this.repeatCount);
sti.setPriority(this.priority);
sti.setMisfireInstruction(this.misfireInstruction);
cti.setDescription(this.description);
sti.setDescription(this.description);
this.simpleTrigger = sti;
*/
Class<?> simpleTriggerClass;
Method jobKeyMethod;
try {
simpleTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.SimpleTriggerImpl");
simpleTriggerClass = ClassUtils.forName("org.quartz.impl.triggers.SimpleTriggerImpl", getClass().getClassLoader());
jobKeyMethod = JobDetail.class.getMethod("getKey");
}
catch (ClassNotFoundException ex) {
@@ -372,6 +372,8 @@ public abstract class CacheAspectSupport implements InitializingBean {
private final Collection<? extends Cache> caches;
private final MethodCacheKey methodCacheKey;
public CacheOperationContext(CacheOperation operation, Method method,
Object[] args, Object target, Class<?> targetClass) {
this.operation = operation;
@@ -380,6 +382,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
this.target = target;
this.targetClass = targetClass;
this.caches = CacheAspectSupport.this.getCaches(operation);
this.methodCacheKey = new MethodCacheKey(method, targetClass);
}
private Object[] extractArgs(Method method, Object[] args) {
@@ -396,7 +399,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
protected boolean isConditionPassing(Object result) {
if (StringUtils.hasText(this.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.condition(this.operation.getCondition(), this.method, evaluationContext);
return evaluator.condition(this.operation.getCondition(), this.methodCacheKey, evaluationContext);
}
return true;
}
@@ -411,7 +414,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
if (StringUtils.hasText(unless)) {
EvaluationContext evaluationContext = createEvaluationContext(value);
return !evaluator.unless(unless, this.method, evaluationContext);
return !evaluator.unless(unless, this.methodCacheKey, evaluationContext);
}
return true;
}
@@ -423,7 +426,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
protected Object generateKey(Object result) {
if (StringUtils.hasText(this.operation.getKey())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.key(this.operation.getKey(), this.method, evaluationContext);
return evaluator.key(this.operation.getKey(), this.methodCacheKey, evaluationContext);
}
return keyGenerator.generate(this.target, this.method, this.args);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,16 +27,19 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.ObjectUtils;
/**
* Utility class handling the SpEL expression parsing.
* Meant to be used as a reusable, thread-safe component.
*
* <p>Performs internal caching for performance reasons.
* <p>Performs internal caching for performance reasons
* using {@link MethodCacheKey}.
*
* @author Costin Leau
* @author Phillip Webb
* @author Sam Brannen
* @author Stephane Nicoll
* @since 3.1
*/
class ExpressionEvaluator {
@@ -49,13 +52,16 @@ class ExpressionEvaluator {
// shared param discoverer since it caches data internally
private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
private final Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<ExpressionKey, Expression> keyCache
= new ConcurrentHashMap<ExpressionKey, Expression>(64);
private final Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<ExpressionKey, Expression> conditionCache
= new ConcurrentHashMap<ExpressionKey, Expression>(64);
private final Map<String, Expression> unlessCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<ExpressionKey, Expression> unlessCache
= new ConcurrentHashMap<ExpressionKey, Expression>(64);
private final Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>(64);
private final Map<MethodCacheKey, Method> targetMethodCache = new ConcurrentHashMap<MethodCacheKey, Method>(64);
/**
@@ -93,22 +99,22 @@ class ExpressionEvaluator {
return evaluationContext;
}
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
return getExpression(this.keyCache, keyExpression, method).getValue(evalContext);
public Object key(String keyExpression, MethodCacheKey methodKey, EvaluationContext evalContext) {
return getExpression(this.keyCache, keyExpression, methodKey).getValue(evalContext);
}
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
return getExpression(this.conditionCache, conditionExpression, method).getValue(
public boolean condition(String conditionExpression, MethodCacheKey methodKey, EvaluationContext evalContext) {
return getExpression(this.conditionCache, conditionExpression, methodKey).getValue(
evalContext, boolean.class);
}
public boolean unless(String unlessExpression, Method method, EvaluationContext evalContext) {
return getExpression(this.unlessCache, unlessExpression, method).getValue(
public boolean unless(String unlessExpression, MethodCacheKey methodKey, EvaluationContext evalContext) {
return getExpression(this.unlessCache, unlessExpression, methodKey).getValue(
evalContext, boolean.class);
}
private Expression getExpression(Map<String, Expression> cache, String expression, Method method) {
String key = toString(method, expression);
private Expression getExpression(Map<ExpressionKey, Expression> cache, String expression, MethodCacheKey methodKey) {
ExpressionKey key = createKey(methodKey, expression);
Expression rtn = cache.get(key);
if (rtn == null) {
rtn = this.parser.parseExpression(expression);
@@ -117,13 +123,37 @@ class ExpressionEvaluator {
return rtn;
}
private String toString(Method method, String expression) {
StringBuilder sb = new StringBuilder();
sb.append(method.getDeclaringClass().getName());
sb.append("#");
sb.append(method.toString());
sb.append("#");
sb.append(expression);
return sb.toString();
private ExpressionKey createKey(MethodCacheKey methodCacheKey, String expression) {
return new ExpressionKey(methodCacheKey, expression);
}
private static class ExpressionKey {
private final MethodCacheKey methodCacheKey;
private final String expression;
private ExpressionKey(MethodCacheKey methodCacheKey, String expression) {
this.methodCacheKey = methodCacheKey;
this.expression = expression;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ExpressionKey)) {
return false;
}
ExpressionKey otherKey = (ExpressionKey) other;
return (this.methodCacheKey.equals(otherKey.methodCacheKey)
&& ObjectUtils.nullSafeEquals(this.expression, otherKey.expression));
}
@Override
public int hashCode() {
return this.methodCacheKey.hashCode() * 29 + (this.expression != null ? this.expression.hashCode() : 0);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ import org.springframework.util.ObjectUtils;
* (rather then a dedicated 'closure'-like class for deferred execution).
*
* @author Costin Leau
* @author Stephane Nicoll
* @since 3.1
*/
class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
@@ -45,13 +46,13 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
private final Class<?> targetClass;
private final Map<String, Method> methodCache;
private final Map<MethodCacheKey, Method> methodCache;
private boolean paramLoaded = false;
LazyParamAwareEvaluationContext(Object rootObject, ParameterNameDiscoverer paramDiscoverer, Method method,
Object[] args, Class<?> targetClass, Map<String, Method> methodCache) {
Object[] args, Class<?> targetClass, Map<MethodCacheKey, Method> methodCache) {
super(rootObject);
this.paramDiscoverer = paramDiscoverer;
@@ -85,7 +86,7 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
return;
}
String methodKey = toString(this.method);
MethodCacheKey methodKey = new MethodCacheKey(this.method, this.targetClass);
Method targetMethod = this.methodCache.get(methodKey);
if (targetMethod == null) {
targetMethod = AopUtils.getMostSpecificMethod(this.method, this.targetClass);
@@ -110,11 +111,4 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
}
}
private String toString(Method m) {
StringBuilder sb = new StringBuilder();
sb.append(m.getDeclaringClass().getName());
sb.append("#");
sb.append(m.toString());
return sb.toString();
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cache.interceptor;
import java.lang.reflect.Method;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Represent a method on a particular {@link Class} and is suitable as a key.
* <p>Mainly for internal use within the framework.
*
* @author Costin Leau
* @author Stephane Nicoll
* @since 4.0.4
*/
public final class MethodCacheKey {
private final Method method;
private final Class<?> targetClass;
public MethodCacheKey(Method method, Class<?> targetClass) {
Assert.notNull(method, "method must be set.");
this.method = method;
this.targetClass = targetClass;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof MethodCacheKey)) {
return false;
}
MethodCacheKey otherKey = (MethodCacheKey) other;
return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(this.targetClass,
otherKey.targetClass));
}
@Override
public int hashCode() {
return this.method.hashCode() * 29 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -226,8 +226,8 @@ public class AnnotationConfigUtils {
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
ClassLoader cl = AnnotationConfigUtils.class.getClassLoader();
def.setBeanClass(cl.loadClass(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME));
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -197,25 +197,26 @@ public @interface Bean {
/**
* The optional name of a method to call on the bean instance during initialization.
* Not commonly used, given that the method may be called programmatically directly
* within the body of a Bean-annotated method. Default value is {@code ""}, indicating
* that no init method should be called.
* within the body of a Bean-annotated method.
* <p>The default value is {@code ""}, indicating no init method to be called.
*/
String initMethod() default "";
/**
* The optional name of a method to call on the bean instance upon closing the
* application context, for example a {@code close()} method on a JDBC {@code
* DataSource} implementation, or a Hibernate {@code SessionFactory} object.
* application context, for example a {@code close()} method on a JDBC
* {@code DataSource} implementation, or a Hibernate {@code SessionFactory} object.
* The method must have no arguments but may throw any exception.
* <p>As a convenience to the user, the container will attempt to infer a destroy
* method against an object returned from the {@code @Bean} method. For example, given a
* {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource}, the
* container will notice the {@code close()} method available on that object and
* method against an object returned from the {@code @Bean} method. For example, given
* an {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource},
* the container will notice the {@code close()} method available on that object and
* automatically register it as the {@code destroyMethod}. This 'destroy method
* inference' is currently limited to detecting only public, no-arg methods named
* 'close'. The method may be declared at any level of the inheritance hierarchy and
* will be detected regardless of the return type of the {@code @Bean} method (i.e.,
* detection occurs reflectively against the bean instance itself at creation time).
* 'close' or 'shutdown'. The method may be declared at any level of the inheritance
* hierarchy and will be detected regardless of the return type of the {@code @Bean}
* method (i.e., detection occurs reflectively against the bean instance itself at
* creation time).
* <p>To disable destroy method inference for a particular {@code @Bean}, specify an
* empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
* {@link org.springframework.beans.factory.DisposableBean} and the
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -238,7 +238,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) cl.loadClass("javax.annotation.ManagedBean")), false));
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
@@ -246,7 +246,7 @@ public class ClassPathScanningCandidateComponentProvider implements EnvironmentC
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) cl.loadClass("javax.inject.Named")), false));
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -142,10 +142,10 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
private static Class<? extends Annotation> ejbRefClass = null;
static {
ClassLoader cl = CommonAnnotationBeanPostProcessor.class.getClassLoader();
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.xml.ws.WebServiceRef");
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
ClassUtils.forName("javax.xml.ws.WebServiceRef", CommonAnnotationBeanPostProcessor.class.getClassLoader());
webServiceRefClass = clazz;
}
catch (ClassNotFoundException ex) {
@@ -153,7 +153,8 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
try {
@SuppressWarnings("unchecked")
Class<? extends Annotation> clazz = (Class<? extends Annotation>) cl.loadClass("javax.ejb.EJB");
Class<? extends Annotation> clazz = (Class<? extends Annotation>)
ClassUtils.forName("javax.ejb.EJB", CommonAnnotationBeanPostProcessor.class.getClassLoader());
ejbRefClass = clazz;
}
catch (ClassNotFoundException ex) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -258,7 +258,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
@SuppressWarnings("unchecked")
private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) {
Object result = null;
Object result;
try {
result = classLoader.loadClass(className).newInstance();
}
@@ -268,7 +268,7 @@ public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
}
catch (Exception ex) {
throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" +
strategyType.getName() + "]. A zero-argument constructor is required", ex);
strategyType.getName() + "]: a zero-argument constructor is required", ex);
}
if (!strategyType.isAssignableFrom(result.getClass())) {
@@ -116,7 +116,8 @@ class ConfigurationClassParser {
private final Map<String, ConfigurationClass> knownSuperclasses = new HashMap<String, ConfigurationClass>();
private final MultiValueMap<String, PropertySource<?>> propertySources = new LinkedMultiValueMap<String, PropertySource<?>>();
private final MultiValueMap<String, ResourcePropertySource> propertySources =
new LinkedMultiValueMap<String, ResourcePropertySource>();
private final ImportStack importStack = new ImportStack();
@@ -267,7 +268,7 @@ class ConfigurationClassParser {
// process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!this.knownSuperclasses.containsKey(superclass)) {
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// superclass found, return its annotation metadata and recurse
try {
@@ -305,23 +306,15 @@ class ConfigurationClassParser {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
int locationCount = locations.length;
if (locationCount == 0) {
if (locations.length == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (String location : locations) {
try {
Resource resource = this.resourceLoader.getResource(
this.environment.resolveRequiredPlaceholders(location));
if (!StringUtils.hasText(name) || this.propertySources.containsKey(name)) {
// We need to ensure unique names when the property source will
// ultimately end up in a composite
ResourcePropertySource ps = new ResourcePropertySource(resource);
this.propertySources.add((StringUtils.hasText(name) ? name : ps.getName()), ps);
}
else {
this.propertySources.add(name, new ResourcePropertySource(name, resource));
}
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
Resource resource = this.resourceLoader.getResource(resolvedLocation);
ResourcePropertySource ps = new ResourcePropertySource(resource);
this.propertySources.add((StringUtils.hasText(name) ? name : ps.getName()), ps);
}
catch (IllegalArgumentException ex) {
// from resolveRequiredPlaceholders
@@ -484,15 +477,15 @@ class ConfigurationClassParser {
public List<PropertySource<?>> getPropertySources() {
List<PropertySource<?>> propertySources = new LinkedList<PropertySource<?>>();
for (Map.Entry<String, List<PropertySource<?>>> entry : this.propertySources.entrySet()) {
for (Map.Entry<String, List<ResourcePropertySource>> entry : this.propertySources.entrySet()) {
propertySources.add(0, collatePropertySources(entry.getKey(), entry.getValue()));
}
return propertySources;
}
private PropertySource<?> collatePropertySources(String name, List<PropertySource<?>> propertySources) {
private PropertySource<?> collatePropertySources(String name, List<ResourcePropertySource> propertySources) {
if (propertySources.size() == 1) {
return propertySources.get(0);
return propertySources.get(0).withName(name);
}
CompositePropertySource result = new CompositePropertySource(name);
for (int i = propertySources.size() - 1; i >= 0; i--) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -307,7 +307,7 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
"Reason: Environment must implement ConfigurableEnvironment");
}
else {
MutablePropertySources envPropertySources = ((ConfigurableEnvironment)this.environment).getPropertySources();
MutablePropertySources envPropertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();
for (PropertySource<?> propertySource : parsedPropertySources) {
envPropertySources.addLast(propertySource);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Advisor that activates asynchronous method execution through the {@link Async}
@@ -73,9 +74,9 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
public AsyncAnnotationAdvisor(Executor executor) {
Set<Class<? extends Annotation>> asyncAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>(2);
asyncAnnotationTypes.add(Async.class);
ClassLoader cl = AsyncAnnotationAdvisor.class.getClassLoader();
try {
asyncAnnotationTypes.add((Class<? extends Annotation>) cl.loadClass("javax.ejb.Asynchronous"));
asyncAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.ejb.Asynchronous", AsyncAnnotationAdvisor.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// If EJB 3.1 API not present, simply ignore.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@ import java.util.List;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyException;
import org.jruby.RubyNil;
import org.jruby.ast.ClassNode;
import org.jruby.ast.Colon2Node;
@@ -116,10 +115,12 @@ public abstract class JRubyScriptUtils {
/**
* Find the first {@link ClassNode} under the supplied {@link Node}.
* @return the found {@code ClassNode}, or {@code null}
* if no {@link ClassNode} is found
* @return the corresponding {@code ClassNode}, or {@code null} if none found
*/
private static ClassNode findClassNode(Node node) {
if (node == null) {
return null;
}
if (node instanceof ClassNode) {
return (ClassNode) node;
}
@@ -229,9 +230,6 @@ public abstract class JRubyScriptUtils {
/**
* Exception thrown in response to a JRuby {@link RaiseException}
* being thrown from a JRuby method invocation.
* <p>Introduced because the {@code RaiseException} class does not
* have useful {@link Object#toString()}, {@link Throwable#getMessage()},
* and {@link Throwable#printStackTrace} implementations.
*/
@SuppressWarnings("serial")
public static class JRubyExecutionException extends NestedRuntimeException {
@@ -242,12 +240,7 @@ public abstract class JRubyScriptUtils {
* @param ex the cause (must not be {@code null})
*/
public JRubyExecutionException(RaiseException ex) {
super(buildMessage(ex), ex);
}
private static String buildMessage(RaiseException ex) {
RubyException rubyEx = ex.getException();
return (rubyEx != null && rubyEx.message != null) ? rubyEx.message.toString() : "Unexpected JRuby error";
super(ex.getMessage(), ex);
}
}
@@ -102,6 +102,7 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
@Test
public void testProtectedMethodInvocation() {
ProtectedMethodTestBean bean = new ProtectedMethodTestBean();
bean.value = "foo";
mockTargetSource.setTarget(bean);
AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
@@ -109,8 +110,47 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
as.addAdvice(new NopInterceptor());
AopProxy aop = new CglibAopProxy(as);
Object proxy = aop.getProxy();
ProtectedMethodTestBean proxy = (ProtectedMethodTestBean) aop.getProxy();
assertTrue(AopUtils.isCglibProxy(proxy));
assertEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
assertEquals("foo", proxy.getString());
}
@Test
public void testPackageMethodInvocation() {
PackageMethodTestBean bean = new PackageMethodTestBean();
bean.value = "foo";
mockTargetSource.setTarget(bean);
AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
AopProxy aop = new CglibAopProxy(as);
PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy();
assertTrue(AopUtils.isCglibProxy(proxy));
assertEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
assertEquals("foo", proxy.getString());
}
@Test
public void testPackageMethodInvocationWithDifferentClassLoader() {
ClassLoader child = new ClassLoader(getClass().getClassLoader()) {
};
PackageMethodTestBean bean = new PackageMethodTestBean();
bean.value = "foo";
mockTargetSource.setTarget(bean);
AdvisedSupport as = new AdvisedSupport(new Class<?>[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
AopProxy aop = new CglibAopProxy(as);
PackageMethodTestBean proxy = (PackageMethodTestBean) aop.getProxy(child);
assertTrue(AopUtils.isCglibProxy(proxy));
assertNotEquals(proxy.getClass().getClassLoader(), bean.getClass().getClassLoader());
assertNull(proxy.getString()); // we're stuck in the proxy instance
}
@Test
@@ -410,9 +450,40 @@ public final class CglibProxyTests extends AbstractAopProxyTests implements Seri
}
public static class HasFinalMethod {
public static class NoArgCtorTestBean {
public final void foo() {
private boolean called = false;
public NoArgCtorTestBean(String x, int y) {
called = true;
}
public boolean wasCalled() {
return called;
}
public void reset() {
called = false;
}
}
public static class ProtectedMethodTestBean {
public String value;
protected String getString() {
return this.value;
}
}
public static class PackageMethodTestBean {
public String value;
String getString() {
return this.value;
}
}
}
@@ -436,32 +507,6 @@ class CglibTestBean {
}
class NoArgCtorTestBean {
private boolean called = false;
public NoArgCtorTestBean(String x, int y) {
called = true;
}
public boolean wasCalled() {
return called;
}
public void reset() {
called = false;
}
}
class ProtectedMethodTestBean {
protected String getString() {
return "foo";
}
}
class UnsupportedInterceptor implements MethodInterceptor {
@Override
@@ -0,0 +1,118 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cache.config;
import org.junit.Test;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* @author Stephane Nicoll
*/
public class ExpressionCachingIntegrationTests {
@SuppressWarnings("unchecked")
@Test // SPR-11692
public void expressionIsCacheBasedOnActualMethod() {
ConfigurableApplicationContext context =
new AnnotationConfigApplicationContext(SharedConfig.class, Spr11692Config.class);
BaseDao<User> userDao = (BaseDao<User>) context.getBean("userDao");
BaseDao<Order> orderDao = (BaseDao<Order>) context.getBean("orderDao");
userDao.persist(new User("1"));
orderDao.persist(new Order("2"));
context.close();
}
@Configuration
static class Spr11692Config {
@Bean
public BaseDao<User> userDao() {
return new UserDaoImpl();
}
@Bean
public BaseDao<Order> orderDao() {
return new OrderDaoImpl();
}
}
private static interface BaseDao<T> {
T persist(T t);
}
private static class UserDaoImpl implements BaseDao<User> {
@Override
@CachePut(value = "users", key = "#user.id")
public User persist(User user) {
return user;
}
}
private static class OrderDaoImpl implements BaseDao<Order> {
@Override
@CachePut(value = "orders", key = "#order.id")
public Order persist(Order order) {
return order;
}
}
private static class User {
private final String id;
private User(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
private static class Order {
private final String id;
private Order(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
@Configuration
@EnableCaching
static class SharedConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import static org.junit.Assert.*;
* @author Costin Leau
* @author Phillip Webb
* @author Sam Brannen
* @author Stephane Nicoll
*/
public class ExpressionEvaluatorTests {
@@ -82,8 +83,10 @@ public class ExpressionEvaluatorTests {
Iterator<CacheOperation> it = ops.iterator();
Object keyA = eval.key(it.next().getKey(), method, evalCtx);
Object keyB = eval.key(it.next().getKey(), method, evalCtx);
MethodCacheKey key = new MethodCacheKey(method, AnnotatedClass.class);
Object keyA = eval.key(it.next().getKey(), key, evalCtx);
Object keyB = eval.key(it.next().getKey(), key, evalCtx);
assertEquals(args[0], keyA);
assertEquals(args[1], keyB);
@@ -23,6 +23,7 @@ import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
@@ -55,6 +56,39 @@ public class BeanMethodPolymorphismTests {
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
}
@Test
public void beanMethodOverridingOnASM() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBeanDefinition("config", new RootBeanDefinition(OverridingConfig.class.getName()));
ctx.setAllowBeanDefinitionOverriding(false);
ctx.refresh();
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
}
@Test
public void beanMethodOverridingWithNarrowedReturnType() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(NarrowedOverridingConfig.class);
ctx.setAllowBeanDefinitionOverriding(false);
ctx.refresh();
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
}
@Test
public void beanMethodOverridingWithNarrowedReturnTypeOnASM() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBeanDefinition("config", new RootBeanDefinition(NarrowedOverridingConfig.class.getName()));
ctx.setAllowBeanDefinitionOverriding(false);
ctx.refresh();
assertFalse(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
assertEquals("overridden", ctx.getBean("testBean", TestBean.class).toString());
assertTrue(ctx.getDefaultListableBeanFactory().containsSingleton("testBean"));
}
@Test
public void beanMethodOverloadingWithoutInheritance() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -173,6 +207,26 @@ public class BeanMethodPolymorphismTests {
}
static class ExtendedTestBean extends TestBean {
}
@Configuration
static class NarrowedOverridingConfig extends BaseConfig {
@Bean @Lazy
@Override
public ExtendedTestBean testBean() {
return new ExtendedTestBean() {
@Override
public String toString() {
return "overridden";
}
};
}
}
@Configuration
static class ConfigWithOverloading {
@@ -23,6 +23,7 @@ import java.lang.annotation.Target;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.FactoryBean;
@@ -86,8 +87,7 @@ public class ConfigurationClassPostProcessorTests {
*/
@Test
public void alreadyLoadedConfigurationClasses() {
beanFactory.registerBeanDefinition("unloadedConfig", new RootBeanDefinition(UnloadedConfig.class.getName(),
null, null));
beanFactory.registerBeanDefinition("unloadedConfig", new RootBeanDefinition(UnloadedConfig.class.getName()));
beanFactory.registerBeanDefinition("loadedConfig", new RootBeanDefinition(LoadedConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -126,56 +126,56 @@ public class ConfigurationClassPostProcessorTests {
@Test
public void postProcessorWorksWithComposedConfigurationWithAttributeOverridesUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverridesClass.class);
ComposedConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedConfigurationWithAttributeOverridesUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedConfigurationWithAttributeOverridesClass.class.getName());
ComposedConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedComposedConfigurationWithAttributeOverridesClass.class);
ComposedComposedConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithComposedComposedConfigurationWithAttributeOverridesUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
ComposedComposedConfigurationWithAttributeOverridesClass.class.getName());
ComposedComposedConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
MetaComponentScanConfigurationWithAttributeOverridesClass.class);
MetaComponentScanConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
MetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
MetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingReflection() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class);
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class);
assertSupportForComposedAnnotation(beanDefinition);
}
@Test
public void postProcessorWorksWithMetaComponentScanConfigurationWithAttributeOverridesSubclassUsingAsm() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
SubMetaComponentScanConfigurationWithAttributeOverridesClass.class.getName());
assertSupportForComposedAnnotation(beanDefinition);
}
@@ -208,8 +208,8 @@ public class ConfigurationClassPostProcessorTests {
public void postProcessorDoesNotOverrideRegularBeanDefinitionsEvenWithScopedProxy() {
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
rbd.setResource(new DescriptiveResource("XML or something"));
BeanDefinitionHolder proxied = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(rbd, "bar"),
beanFactory, true);
BeanDefinitionHolder proxied = ScopedProxyUtils.createScopedProxy(
new BeanDefinitionHolder(rbd, "bar"), beanFactory, true);
beanFactory.registerBeanDefinition("bar", proxied.getBeanDefinition());
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
@@ -296,8 +296,7 @@ public class ConfigurationClassPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(RepositoryInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
beanFactory.registerBeanDefinition("annotatedBean", bd);
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(
ScopedProxyRepositoryConfiguration.class));
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ScopedProxyRepositoryConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.freezeConfiguration();
@@ -332,8 +331,7 @@ public class ConfigurationClassPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFactoryBeanInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
beanFactory.registerBeanDefinition("annotatedBean", bd);
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(
RepositoryFactoryBeanConfiguration.class));
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryFactoryBeanConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();
@@ -374,8 +372,7 @@ public class ConfigurationClassPostProcessorTests {
@Test
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(
WildcardWithGenericExtendsConfiguration.class));
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
@@ -574,7 +571,6 @@ public class ConfigurationClassPostProcessorTests {
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Repository<String> stringRepo() {
return new Repository<String>() {
@Override
public String toString() {
return "Repository<String>";
@@ -586,7 +582,6 @@ public class ConfigurationClassPostProcessorTests {
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Repository<Integer> integerRepo() {
return new Repository<Integer>() {
@Override
public String toString() {
return "Repository<Integer>";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -123,6 +123,7 @@ public class NestedConfigurationClassTests {
@Configuration
static class L0Config {
@Bean
public TestBean l0Bean() {
return new TestBean("l0");
@@ -135,6 +136,7 @@ public class NestedConfigurationClassTests {
@Configuration
static class L1Config {
@Bean
public TestBean l1Bean() {
return new TestBean("l1");
@@ -147,6 +149,7 @@ public class NestedConfigurationClassTests {
@Configuration
protected static class L2Config {
@Bean
public TestBean l2Bean() {
return new TestBean("l2");
@@ -163,6 +166,7 @@ public class NestedConfigurationClassTests {
@Component
static class L0ConfigLight {
@Bean
public TestBean l0Bean() {
return new TestBean("l0");
@@ -175,6 +179,7 @@ public class NestedConfigurationClassTests {
@Component
static class L1ConfigLight {
@Bean
public TestBean l1Bean() {
return new TestBean("l1");
@@ -187,6 +192,7 @@ public class NestedConfigurationClassTests {
@Component
protected static class L2ConfigLight {
@Bean
public TestBean l2Bean() {
return new TestBean("l2");
@@ -216,6 +222,7 @@ public class NestedConfigurationClassTests {
@Configuration
static class S1Config extends L0Config {
@Override
@Bean
public TestBean overrideBean() {
@@ -124,21 +124,14 @@ public class PropertySourceAnnotationTests {
System.clearProperty("path.to.properties");
}
/**
* Corner bug reported in SPR-9127.
*/
@Test
public void withNameAndMultipleResourceLocations() {
@Test(expected = IllegalArgumentException.class)
public void withEmptyResourceLocations() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConfigWithNameAndMultipleResourceLocations.class);
ctx.register(ConfigWithEmptyResourceLocations.class);
ctx.refresh();
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
}
/**
* SPR-10820
*/
// SPR-10820
@Test
public void orderingWithAndWithoutNameAndMultipleResourceLocations() {
// p2 should 'win' as it was registered last
@@ -148,11 +141,22 @@ public class PropertySourceAnnotationTests {
assertThat(ctxWithName.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
}
@Test(expected=IllegalArgumentException.class)
public void withEmptyResourceLocations() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConfigWithEmptyResourceLocations.class);
ctx.refresh();
@Test
public void withNameAndMultipleResourceLocations() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNameAndMultipleResourceLocations.class);
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
// p2 should 'win' as it was registered last
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
}
@Test
public void withMultipleResourceLocations() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithMultipleResourceLocations.class);
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
// p2 should 'win' as it was registered last
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
}
@Test
@@ -164,6 +168,15 @@ public class PropertySourceAnnotationTests {
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
}
@Test
public void withNamedPropertySources() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithNamedPropertySources.class);
assertThat(ctx.getEnvironment().containsProperty("from.p1"), is(true));
assertThat(ctx.getEnvironment().containsProperty("from.p2"), is(true));
// p2 should 'win' as it was registered last
assertThat(ctx.getEnvironment().getProperty("testbean.name"), equalTo("p2TestBean"));
}
@Test
public void withMissingPropertySource() {
thrown.expect(BeanDefinitionStoreException.class);
@@ -263,8 +276,8 @@ public class PropertySourceAnnotationTests {
@Configuration
@PropertySources({
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p2.properties")
@PropertySource("classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource("classpath:org/springframework/context/annotation/p2.properties"),
})
static class ConfigWithPropertySources {
}
@@ -272,9 +285,18 @@ public class PropertySourceAnnotationTests {
@Configuration
@PropertySources({
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/missing.properties"),
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p2.properties")
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p2.properties"),
})
static class ConfigWithNamedPropertySources {
}
@Configuration
@PropertySources({
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/missing.properties"),
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p2.properties")
})
static class ConfigWithMissingPropertySource {
}
@@ -282,10 +304,10 @@ public class PropertySourceAnnotationTests {
@Configuration
@PropertySources({
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/missing.properties", ignoreResourceNotFound=true),
@PropertySource(name = "psName", value="classpath:${myPath}/missing.properties", ignoreResourceNotFound=true),
@PropertySource(name = "psName", value="classpath:org/springframework/context/annotation/p2.properties")
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p1.properties"),
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/missing.properties", ignoreResourceNotFound=true),
@PropertySource(name = "psName", value = "classpath:${myPath}/missing.properties", ignoreResourceNotFound=true),
@PropertySource(name = "psName", value = "classpath:org/springframework/context/annotation/p2.properties")
})
static class ConfigWithIgnoredPropertySource {
}
@@ -0,0 +1,130 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.configuration;
import org.junit.Test;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* @author Phillip Webb
*/
public class Spr10744Tests {
private static int createCount = 0;
private static int scopeCount = 0;
@Test
public void testSpr10744() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getBeanFactory().registerScope("myTestScope", new MyTestScope());
context.register(MyTestConfiguration.class);
context.refresh();
Foo bean1 = context.getBean("foo", Foo.class);
Foo bean2 = context.getBean("foo", Foo.class);
assertThat(bean1, sameInstance(bean2));
// Should not have invoked constructor for the proxy instance
assertThat(createCount, equalTo(0));
assertThat(scopeCount, equalTo(0));
// Proxy mode should create new scoped object on each method call
bean1.getMessage();
assertThat(createCount, equalTo(1));
assertThat(scopeCount, equalTo(1));
bean1.getMessage();
assertThat(createCount, equalTo(2));
assertThat(scopeCount, equalTo(2));
context.close();
}
private static class MyTestScope implements org.springframework.beans.factory.config.Scope {
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
scopeCount++;
return objectFactory.getObject();
}
@Override
public Object remove(String name) {
return null;
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
@Override
public String getConversationId() {
return null;
}
}
static class Foo {
public Foo() {
createCount++;
}
public String getMessage() {
return "Hello";
}
}
@Configuration
static class MyConfiguration {
@Bean
public Foo foo() {
return new Foo();
}
}
@Configuration
static class MyTestConfiguration extends MyConfiguration {
@Bean
@Scope(value = "myTestScope", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Override
public Foo foo() {
return new Foo();
}
}
}
@@ -18,19 +18,22 @@ package org.springframework.scheduling.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.concurrent.Future;
import org.junit.Before;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import static org.junit.Assert.*;
@@ -46,10 +49,6 @@ public class AsyncExecutionTests {
private static int listenerConstructed = 0;
@Before
public void setUp() {
Assume.group(TestGroup.PERFORMANCE);
}
@Test
public void asyncMethods() throws Exception {
@@ -135,6 +134,46 @@ public class AsyncExecutionTests {
assertEquals("20", future.get());
}
@Test
public void asyncClassWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncClassBean asyncTest = context.getBean("asyncTest", AsyncClassBean.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncClassWithInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBeanWithInterface.class));
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
context.refresh();
RegularInterface asyncTest = context.getBean("asyncTest", RegularInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncClassWithInterfaceAndPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBeanWithInterface.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
RegularInterface asyncTest = context.getBean("asyncTest", RegularInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -149,6 +188,46 @@ public class AsyncExecutionTests {
assertEquals("20", future.get());
}
@Test
public void asyncInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void dynamicAsyncInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncInterfaceBean.class));
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
context.refresh();
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void dynamicAsyncInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncMethodsInInterface() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -164,6 +243,33 @@ public class AsyncExecutionTests {
assertEquals("20", future.get());
}
@Test
public void asyncMethodsInInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodsInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class);
asyncTest.doNothing(5);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void dynamicAsyncMethodsInInterfaceWithPostProcessor() throws Exception {
originalThreadName = Thread.currentThread().getName();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("asyncTest", new RootBeanDefinition(DynamicAsyncMethodsInterfaceBean.class));
context.registerBeanDefinition("asyncProcessor", new RootBeanDefinition(AsyncAnnotationBeanPostProcessor.class));
context.refresh();
AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class);
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertEquals("20", future.get());
}
@Test
public void asyncMethodListener() throws Exception {
originalThreadName = Thread.currentThread().getName();
@@ -304,6 +410,28 @@ public class AsyncExecutionTests {
}
public interface RegularInterface {
void doSomething(int i);
Future<String> returnSomething(int i);
}
@Async
public static class AsyncClassBeanWithInterface implements RegularInterface {
public void doSomething(int i) {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
}
public Future<String> returnSomething(int i) {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
return new AsyncResult<String>(Integer.toString(i));
}
}
@Async
public interface AsyncInterface {
@@ -328,6 +456,44 @@ public class AsyncExecutionTests {
}
public static class DynamicAsyncInterfaceBean implements FactoryBean<AsyncInterface> {
private final AsyncInterface proxy;
public DynamicAsyncInterfaceBean() {
ProxyFactory pf = new ProxyFactory(new HashMap<>());
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
if (Future.class.equals(invocation.getMethod().getReturnType())) {
return new AsyncResult<String>(invocation.getArguments()[0].toString());
}
return null;
}
});
advisor.addInterface(AsyncInterface.class);
pf.addAdvisor(advisor);
this.proxy = (AsyncInterface) pf.getProxy();
}
@Override
public AsyncInterface getObject() {
return this.proxy;
}
@Override
public Class<?> getObjectType() {
return this.proxy.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
}
public interface AsyncMethodsInterface {
void doNothing(int i);
@@ -360,6 +526,44 @@ public class AsyncExecutionTests {
}
public static class DynamicAsyncMethodsInterfaceBean implements FactoryBean<AsyncMethodsInterface> {
private final AsyncMethodsInterface proxy;
public DynamicAsyncMethodsInterfaceBean() {
ProxyFactory pf = new ProxyFactory(new HashMap<>());
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
assertTrue(!Thread.currentThread().getName().equals(originalThreadName));
if (Future.class.equals(invocation.getMethod().getReturnType())) {
return new AsyncResult<String>(invocation.getArguments()[0].toString());
}
return null;
}
});
advisor.addInterface(AsyncMethodsInterface.class);
pf.addAdvisor(advisor);
this.proxy = (AsyncMethodsInterface) pf.getProxy();
}
@Override
public AsyncMethodsInterface getObject() {
return this.proxy;
}
@Override
public Class<?> getObjectType() {
return this.proxy.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
}
public static class AsyncMethodListener implements ApplicationListener<ApplicationEvent> {
@Override
@@ -1,4 +1,3 @@
/*
* Copyright 2002-2012 the original author or authors.
*
@@ -17,19 +16,10 @@
package org.springframework.tests.sample.beans;
import org.springframework.tests.sample.beans.TestBean;
public class Employee extends TestBean {
private String co;
/**
* Constructor for Employee.
*/
public Employee() {
super();
}
public String getCompany() {
return co;
}
@@ -193,9 +193,11 @@ public abstract class ClassVisitor {
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@@ -756,7 +756,7 @@ public class ClassWriter extends ClassVisitor {
if (innerClasses == null) {
innerClasses = new ByteVector();
}
// §4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
// Sec. 4.7.6 of the JVMS states "Every CONSTANT_Class_info entry in the
// constant_pool table which represents a class or interface C that is
// not a package member must have exactly one corresponding entry in the
// classes array". To avoid duplicates we keep track in the intVal field
@@ -116,9 +116,11 @@ public abstract class FieldVisitor {
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@@ -1426,16 +1426,20 @@ final class Frame {
| cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE);
} else {
// if u and t are array types, but not with the same element
// type, merge(u,t)=java/lang/Object
v = OBJECT | cw.addType("java/lang/Object");
// type, merge(u,t) = dim(u) - 1 | java/lang/Object
int vdim = ELEMENT_OF + (u & DIM);
v = vdim | OBJECT | cw.addType("java/lang/Object");
}
} else if ((t & BASE_KIND) == OBJECT || (t & DIM) != 0) {
// if t is any other reference or array type, the merged type
// is Object, or min(dim(u), dim(t)) | java/lang/Object is u
// and t have different array dimensions
int tdim = t & DIM;
int udim = u & DIM;
v = (udim != tdim ? Math.min(tdim, udim) : 0) | OBJECT
// is min(udim, tdim) | java/lang/Object, where udim is the
// array dimension of u, minus 1 if u is an array type with a
// primitive element type (and similarly for tdim).
int tdim = (((t & DIM) == 0 || (t & BASE_KIND) == OBJECT) ? 0
: ELEMENT_OF) + (t & DIM);
int udim = (((u & DIM) == 0 || (u & BASE_KIND) == OBJECT) ? 0
: ELEMENT_OF) + (u & DIM);
v = Math.min(tdim, udim) | OBJECT
| cw.addType("java/lang/Object");
} else {
// if t is any other type, merge(u,t)=TOP
@@ -110,9 +110,11 @@ public abstract class MethodVisitor {
* allowed (see {@link Opcodes}).
*/
public void visitParameter(String name, int access) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (mv != null) {
mv.visitParameter(name, access);
}
@@ -179,9 +181,11 @@ public abstract class MethodVisitor {
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (mv != null) {
return mv.visitTypeAnnotation(typeRef, typePath, desc, visible);
}
@@ -693,9 +697,11 @@ public abstract class MethodVisitor {
*/
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (mv != null) {
return mv.visitInsnAnnotation(typeRef, typePath, desc, visible);
}
@@ -753,9 +759,11 @@ public abstract class MethodVisitor {
*/
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (mv != null) {
return mv.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
}
@@ -824,9 +832,11 @@ public abstract class MethodVisitor {
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
/* SPRING PATCH: REMOVED FOR COMPATIBILITY WITH CGLIB 3.1
if (api < Opcodes.ASM5) {
throw new RuntimeException();
}
*/
if (mv != null) {
return mv.visitLocalVariableAnnotation(typeRef, typePath, start,
end, index, desc, visible);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -103,8 +103,8 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
// We couldn't load the class file, which is not fatal as it
// simply means this method of discovering parameter names won't work.
if (logger.isDebugEnabled()) {
logger.debug("Cannot find '.class' file for class [" + clazz
+ "] - unable to determine constructors/methods parameter names");
logger.debug("Cannot find '.class' file for class [" + clazz +
"] - unable to determine constructor/method parameter names");
}
return NO_DEBUG_INFO_MAP;
}
@@ -117,14 +117,14 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Exception thrown while reading '.class' file for class [" + clazz +
"] - unable to determine constructors/methods parameter names", ex);
"] - unable to determine constructor/method parameter names", ex);
}
}
catch (IllegalArgumentException ex) {
if (logger.isDebugEnabled()) {
logger.debug("ASM ClassReader failed to parse class file [" + clazz +
"], probably due to a new Java class file version that isn't supported yet " +
"- unable to determine constructors/methods parameter names", ex);
"- unable to determine constructor/method parameter names", ex);
}
}
finally {
@@ -148,6 +148,7 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
private static final String STATIC_CLASS_INIT = "<clinit>";
private final Class<?> clazz;
private final Map<Member, String[]> memberMap;
public ParameterNameDiscoveringVisitor(Class<?> clazz, Map<Member, String[]> memberMap) {
@@ -180,12 +181,17 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
private static final String CONSTRUCTOR = "<init>";
private final Class<?> clazz;
private final Map<Member, String[]> memberMap;
private final String name;
private final Type[] args;
private final String[] parameterNames;
private final boolean isStatic;
private String[] parameterNames;
private boolean hasLvtInfo = false;
/*
@@ -194,25 +200,22 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
*/
private final int[] lvtSlotIndex;
public LocalVariableTableVisitor(Class<?> clazz, Map<Member, String[]> map, String name, String desc,
boolean isStatic) {
public LocalVariableTableVisitor(Class<?> clazz, Map<Member, String[]> map, String name, String desc, boolean isStatic) {
super(SpringAsmInfo.ASM_VERSION);
this.clazz = clazz;
this.memberMap = map;
this.name = name;
// determine args
args = Type.getArgumentTypes(desc);
this.parameterNames = new String[args.length];
this.args = Type.getArgumentTypes(desc);
this.parameterNames = new String[this.args.length];
this.isStatic = isStatic;
this.lvtSlotIndex = computeLvtSlotIndices(isStatic, args);
this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args);
}
@Override
public void visitLocalVariable(String name, String description, String signature, Label start, Label end,
int index) {
public void visitLocalVariable(String name, String description, String signature, Label start, Label end, int index) {
this.hasLvtInfo = true;
for (int i = 0; i < lvtSlotIndex.length; i++) {
if (lvtSlotIndex[i] == index) {
for (int i = 0; i < this.lvtSlotIndex.length; i++) {
if (this.lvtSlotIndex[i] == index) {
this.parameterNames[i] = name;
}
}
@@ -225,27 +228,25 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
// which doesn't use any local variables.
// This means that hasLvtInfo could be false for that kind of methods
// even if the class has local variable info.
memberMap.put(resolveMember(), parameterNames);
this.memberMap.put(resolveMember(), this.parameterNames);
}
}
private Member resolveMember() {
ClassLoader loader = clazz.getClassLoader();
Class<?>[] classes = new Class<?>[args.length];
// resolve args
for (int i = 0; i < args.length; i++) {
classes[i] = ClassUtils.resolveClassName(args[i].getClassName(), loader);
ClassLoader loader = this.clazz.getClassLoader();
Class<?>[] argTypes = new Class<?>[this.args.length];
for (int i = 0; i < this.args.length; i++) {
argTypes[i] = ClassUtils.resolveClassName(this.args[i].getClassName(), loader);
}
try {
if (CONSTRUCTOR.equals(name)) {
return clazz.getDeclaredConstructor(classes);
if (CONSTRUCTOR.equals(this.name)) {
return this.clazz.getDeclaredConstructor(argTypes);
}
return clazz.getDeclaredMethod(name, classes);
} catch (NoSuchMethodException ex) {
throw new IllegalStateException("Method [" + name
+ "] was discovered in the .class file but cannot be resolved in the class object", ex);
return this.clazz.getDeclaredMethod(this.name, argTypes);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException("Method [" + this.name +
"] was discovered in the .class file but cannot be resolved in the class object", ex);
}
}
@@ -256,7 +257,8 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
lvtIndex[i] = nextIndex;
if (isWideType(paramTypes[i])) {
nextIndex += 2;
} else {
}
else {
nextIndex++;
}
}
@@ -55,7 +55,8 @@ public abstract class SpringProperties {
static {
try {
ClassLoader cl = SpringProperties.class.getClassLoader();
URL url = cl.getResource(PROPERTIES_RESOURCE_LOCATION);
URL url = (cl != null ? cl.getResource(PROPERTIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResource(PROPERTIES_RESOURCE_LOCATION));
if (url != null) {
logger.info("Found 'spring.properties' file in local classpath");
InputStream is = url.openStream();
@@ -58,7 +58,6 @@ public class AnnotatedElementUtils {
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
return Boolean.TRUE.equals(process(element, annotationType, false, new Processor<Boolean>() {
@Override
public Boolean process(Annotation annotation, int metaDepth) {
if (metaDepth > 0) {
@@ -66,7 +65,6 @@ public class AnnotatedElementUtils {
}
return null;
}
@Override
public void postProcess(Annotation annotation, Boolean result) {
}
@@ -75,12 +73,10 @@ public class AnnotatedElementUtils {
public static boolean isAnnotated(AnnotatedElement element, String annotationType) {
return Boolean.TRUE.equals(process(element, annotationType, false, new Processor<Boolean>() {
@Override
public Boolean process(Annotation annotation, int metaDepth) {
return Boolean.TRUE;
}
@Override
public void postProcess(Annotation annotation, Boolean result) {
}
@@ -95,12 +91,10 @@ public class AnnotatedElementUtils {
final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
return process(element, annotationType, false, new Processor<AnnotationAttributes>() {
@Override
public AnnotationAttributes process(Annotation annotation, int metaDepth) {
return AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap);
}
@Override
public void postProcess(Annotation annotation, AnnotationAttributes result) {
for (String key : result.keySet()) {
@@ -125,7 +119,6 @@ public class AnnotatedElementUtils {
final MultiValueMap<String, Object> attributes = new LinkedMultiValueMap<String, Object>();
process(element, annotationType, false, new Processor<Void>() {
@Override
public Void process(Annotation annotation, int metaDepth) {
if (annotation.annotationType().getName().equals(annotationType)) {
@@ -136,7 +129,6 @@ public class AnnotatedElementUtils {
}
return null;
}
@Override
public void postProcess(Annotation annotation, Void result) {
for (String key : attributes.keySet()) {
@@ -199,8 +191,8 @@ public class AnnotatedElementUtils {
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
if (visited.add(element)) {
Annotation[] annotations = (traverseClassHierarchy ? element.getDeclaredAnnotations()
: element.getAnnotations());
Annotation[] annotations =
(traverseClassHierarchy ? element.getDeclaredAnnotations() : element.getAnnotations());
for (Annotation annotation : annotations) {
if (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0) {
T result = processor.process(annotation, metaDepth);
@@ -228,7 +220,7 @@ public class AnnotatedElementUtils {
if (traverseClassHierarchy && element instanceof Class) {
Class<?> superclass = ((Class<?>) element).getSuperclass();
if (superclass != null && !superclass.equals(Object.class)) {
T result = doProcess(superclass, annotationType, traverseClassHierarchy, processor, visited,
T result = doProcess(superclass, annotationType, true, processor, visited,
metaDepth);
if (result != null) {
return result;
@@ -70,8 +70,8 @@ public abstract class AnnotationUtils {
* Get a single {@link Annotation} of {@code annotationType} from the supplied
* annotation: either the given annotation itself or a meta-annotation thereof.
* @param ann the Annotation to check
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
* @return the matching annotation or {@code null} if not found
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
* @return the matching annotation, or {@code null} if none found
* @since 4.0
*/
@SuppressWarnings("unchecked")
@@ -87,8 +87,8 @@ public abstract class AnnotationUtils {
* Method, Constructor or Field. Meta-annotations will be searched if the annotation
* is not declared locally on the supplied element.
* @param ae the Method, Constructor or Field from which to get the annotation
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
* @return the matching annotation or {@code null} if not found
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
* @return the matching annotation, or {@code null} if none found
* @since 3.1
*/
public static <T extends Annotation> T getAnnotation(AnnotatedElement ae, Class<T> annotationType) {
@@ -119,7 +119,7 @@ public abstract class AnnotationUtils {
* Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method}.
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
* @param method the method to look for annotations on
* @param annotationType the annotation class to look for
* @param annotationType the annotation type to look for
* @return the annotations found
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
*/
@@ -135,16 +135,16 @@ public abstract class AnnotationUtils {
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
* @param method the method to look for annotations on
* @param containerAnnotationType the class of the container that holds the annotations
* @param annotationType the annotation class to look for
* @param annotationType the annotation type to look for
* @return the annotations found
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
* @since 4.0
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
*/
public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method method,
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
return getRepeatableAnnotation((AnnotatedElement) resolvedMethod,
containerAnnotationType, annotationType);
return getRepeatableAnnotation((AnnotatedElement) resolvedMethod, containerAnnotationType, annotationType);
}
/**
@@ -154,13 +154,14 @@ public abstract class AnnotationUtils {
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
* @param annotatedElement the element to look for annotations on
* @param containerAnnotationType the class of the container that holds the annotations
* @param annotationType the annotation class to look for
* @param annotationType the annotation type to look for
* @return the annotations found
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
* @since 4.0
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
*/
public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement,
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
if (annotatedElement.getAnnotations().length == 0) {
return Collections.emptySet();
}
@@ -169,13 +170,13 @@ public abstract class AnnotationUtils {
/**
* Find a single {@link Annotation} of {@code annotationType} from the supplied
* {@link Method}, traversing its super methods (i.e., from super classes and
* {@link Method}, traversing its super methods (i.e., from superclasses and
* interfaces) if no annotation can be found on the given method itself.
* <p>Annotations on methods are not inherited by default, so we need to handle
* this explicitly.
* @param method the method to look for annotations on
* @param annotationType the annotation class to look for
* @return the annotation found, or {@code null} if none found
* @param annotationType the annotation type to look for
* @return the annotation found, or {@code null} if none
*/
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
A annotation = getAnnotation(method, annotationType);
@@ -274,10 +275,8 @@ public abstract class AnnotationUtils {
* @param visited the set of annotations that have already been visited
* @return the annotation if found, or {@code null} if not found
*/
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType,
Set<Annotation> visited) {
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
Assert.notNull(clazz, "Class must not be null");
if (isAnnotationDeclaredLocally(annotationType, clazz)) {
return clazz.getAnnotation(annotationType);
}
@@ -289,8 +288,7 @@ public abstract class AnnotationUtils {
}
for (Annotation ann : clazz.getDeclaredAnnotations()) {
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
A annotation = findAnnotation(ann.annotationType(), annotationType,
visited);
A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
if (annotation != null) {
return annotation;
}
@@ -313,8 +311,8 @@ public abstract class AnnotationUtils {
* <p>The standard {@link Class} API does not provide a mechanism for determining which class
* in an inheritance hierarchy actually declares an {@link Annotation}, so we need to handle
* this explicitly.
* @param annotationType the annotation class to look for, both locally and as a meta-annotation
* @param clazz the class on which to check for the annotation, or {@code null}
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
* @param clazz the class on which to check for the annotation (may be {@code null})
* @return the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
* which declares an annotation for the specified {@code annotationType}, or {@code null}
* if not found
@@ -423,10 +421,9 @@ public abstract class AnnotationUtils {
}
/**
* Determine if the supplied {@link Annotation} is defined in the
* Determine if the supplied {@link Annotation} is defined in the core JDK
* {@code java.lang.annotation} package.
*
* @param annotation the annotation to check; never {@code null}
* @param annotation the annotation to check (never {@code null})
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
*/
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
@@ -435,11 +432,10 @@ public abstract class AnnotationUtils {
}
/**
* Retrieve the given annotation's attributes as a Map, preserving all attribute types
* as-is.
* <p>Note: As of Spring 3.1.1, the returned map is actually an
* {@link AnnotationAttributes} instance, however the Map signature of this method has
* been preserved for binary compatibility.
* Retrieve the given annotation's attributes as a {@link Map}, preserving all
* attribute types as-is.
* <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
* However, the {@code Map} signature has been preserved for binary compatibility.
* @param annotation the annotation to retrieve the attributes for
* @return the Map of annotation attributes, with attribute names as keys and
* corresponding attribute values as values
@@ -449,16 +445,15 @@ public abstract class AnnotationUtils {
}
/**
* Retrieve the given annotation's attributes as a Map. Equivalent to calling
* {@link #getAnnotationAttributes(Annotation, boolean, boolean)} with
* Retrieve the given annotation's attributes as a {@link Map}. Equivalent to
* calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} with
* the {@code nestedAnnotationsAsMap} parameter set to {@code false}.
* <p>Note: As of Spring 3.1.1, the returned map is actually an
* {@link AnnotationAttributes} instance, however the Map signature of this method has
* been preserved for binary compatibility.
* <p>Note: This method actually returns an {@link AnnotationAttributes} instance.
* However, the {@code Map} signature has been preserved for binary compatibility.
* @param annotation the annotation to retrieve the attributes for
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* compatibility with {@link org.springframework.core.type.AnnotationMetadata}
* or to preserve them as Class references
* @return the Map of annotation attributes, with attribute names as keys and
* corresponding attribute values as values
*/
@@ -468,13 +463,13 @@ public abstract class AnnotationUtils {
/**
* Retrieve the given annotation's attributes as an {@link AnnotationAttributes}
* map structure. Implemented in Spring 3.1.1 to provide fully recursive annotation
* reading capabilities on par with that of the reflection-based
* {@link org.springframework.core.type.StandardAnnotationMetadata}.
* map structure.
* <p>This method provides fully recursive annotation reading capabilities on par with
* the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}.
* @param annotation the annotation to retrieve the attributes for
* @param classValuesAsString whether to turn Class references into Strings (for
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} or to
* preserve them as Class references
* compatibility with {@link org.springframework.core.type.AnnotationMetadata}
* or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into
* {@link AnnotationAttributes} maps (for compatibility with
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as
@@ -507,14 +502,13 @@ public abstract class AnnotationUtils {
}
if (nestedAnnotationsAsMap && value instanceof Annotation) {
attrs.put(method.getName(),
getAnnotationAttributes((Annotation) value, classValuesAsString, nestedAnnotationsAsMap));
getAnnotationAttributes((Annotation) value, classValuesAsString, true));
}
else if (nestedAnnotationsAsMap && value instanceof Annotation[]) {
Annotation[] realAnnotations = (Annotation[]) value;
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length];
for (int i = 0; i < realAnnotations.length; i++) {
mappedAnnotations[i] = getAnnotationAttributes(
realAnnotations[i], classValuesAsString, nestedAnnotationsAsMap);
mappedAnnotations[i] = getAnnotationAttributes(realAnnotations[i], classValuesAsString, true);
}
attrs.put(method.getName(), mappedAnnotations);
}
@@ -542,7 +536,7 @@ public abstract class AnnotationUtils {
}
/**
* Retrieve the <em>value</em> of a named Annotation attribute, given an annotation instance.
* Retrieve the <em>value</em> of a named attribute, given an annotation instance.
* @param annotation the annotation instance from which to retrieve the value
* @param attributeName the name of the attribute value to retrieve
* @return the attribute value, or {@code null} if not found
@@ -550,7 +544,7 @@ public abstract class AnnotationUtils {
*/
public static Object getValue(Annotation annotation, String attributeName) {
try {
Method method = annotation.annotationType().getDeclaredMethod(attributeName, new Class<?>[0]);
Method method = annotation.annotationType().getDeclaredMethod(attributeName);
ReflectionUtils.makeAccessible(method);
return method.invoke(annotation);
}
@@ -571,7 +565,7 @@ public abstract class AnnotationUtils {
}
/**
* Retrieve the <em>default value</em> of a named Annotation attribute, given an annotation instance.
* Retrieve the <em>default value</em> of a named attribute, given an annotation instance.
* @param annotation the annotation instance from which to retrieve the default value
* @param attributeName the name of the attribute value to retrieve
* @return the default value of the named attribute, or {@code null} if not found
@@ -593,7 +587,8 @@ public abstract class AnnotationUtils {
}
/**
* Retrieve the <em>default value</em> of a named Annotation attribute, given the {@link Class annotation type}.
* Retrieve the <em>default value</em> of a named attribute, given the
* {@link Class annotation type}.
* @param annotationType the <em>annotation type</em> for which the default value should be retrieved
* @param attributeName the name of the attribute value to retrieve.
* @return the default value of the named attribute, or {@code null} if not found
@@ -601,8 +596,7 @@ public abstract class AnnotationUtils {
*/
public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {
try {
Method method = annotationType.getDeclaredMethod(attributeName, new Class<?>[0]);
return method.getDefaultValue();
return annotationType.getDeclaredMethod(attributeName).getDefaultValue();
}
catch (Exception ex) {
return null;
@@ -620,14 +614,11 @@ public abstract class AnnotationUtils {
private final Set<A> result = new LinkedHashSet<A>();
public AnnotationCollector(Class<? extends Annotation> containerAnnotationType,
Class<A> annotationType) {
public AnnotationCollector(Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) {
this.containerAnnotationType = containerAnnotationType;
this.annotationType = annotationType;
}
public Set<A> getResult(AnnotatedElement element) {
process(element);
return Collections.unmodifiableSet(this.result);
@@ -641,7 +632,7 @@ public abstract class AnnotationUtils {
this.result.add((A) annotation);
}
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, annotation.annotationType())) {
result.addAll(Arrays.asList(getValue(annotation)));
this.result.addAll(Arrays.asList(getValue(annotation)));
}
else if (!isInJavaLangAnnotationPackage(annotation)) {
process(annotation.annotationType());
@@ -658,10 +649,10 @@ public abstract class AnnotationUtils {
return (A[]) method.invoke(annotation);
}
catch (Exception ex) {
throw new IllegalStateException("Unable to read value from repeating annotation container "
+ this.containerAnnotationType.getName(), ex);
throw new IllegalStateException("Unable to read value from repeating annotation container " +
this.containerAnnotationType.getName(), ex);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import org.springframework.core.convert.converter.Converter;
/**
* Simply calls {@link Object#toString()} to convert a source Object to a String.
*
* @author Keith Donald
* @since 3.0
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,12 +29,11 @@ import java.util.Set;
*/
public class CompositePropertySource extends PropertySource<Object> {
private Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>();
private final Set<PropertySource<?>> propertySources = new LinkedHashSet<PropertySource<?>>();
/**
* Create a new {@code CompositePropertySource}.
*
* @param name the name of the property source
*/
public CompositePropertySource(String name) {
@@ -60,6 +59,7 @@ public class CompositePropertySource extends PropertySource<Object> {
@Override
public String toString() {
return String.format("%s [name='%s', propertySources=%s]",
this.getClass().getSimpleName(), this.name, this.propertySources);
getClass().getSimpleName(), this.name, this.propertySources);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.core.env;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
/**
@@ -53,22 +54,23 @@ public abstract class EnumerablePropertySource<T> extends PropertySource<T> {
super(name, source);
}
/**
* Return the names of all properties contained by the {@linkplain #getSource()
* source} object (never {@code null}).
* Return the names of all properties contained by the
* {@linkplain #getSource() source} object (never {@code null}).
*/
public abstract String[] getPropertyNames();
/**
* Return whether this {@code PropertySource} contains a property with the given name.
* <p>This implementation checks for the presence of the given name within
* the {@link #getPropertyNames()} array.
* @param name the property to find
* <p>This implementation checks for the presence of the given name within the
* {@link #getPropertyNames()} array.
* @param name the name of the property to find
*/
@Override
public boolean containsProperty(String name) {
Assert.notNull(name, "property name must not be null");
for (String candidate : this.getPropertyNames()) {
Assert.notNull(name, "Property name must not be null");
for (String candidate : getPropertyNames()) {
if (candidate.equals(name)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("PropertySource [%s] contains '%s'", getName(), name));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,13 +30,18 @@ import java.util.Properties;
* {@link Properties#getProperty} and {@link Properties#setProperty}.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
*/
public class PropertiesPropertySource extends MapPropertySource {
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public PropertiesPropertySource(String name, Properties source) {
super(name, (Map) source);
}
protected PropertiesPropertySource(String name, Map<String, Object> source) {
super(name, source);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,9 @@ package org.springframework.core.env;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Abstract base class representing a source of name/value property pairs. The underlying
@@ -55,12 +57,13 @@ import org.springframework.util.Assert;
*/
public abstract class PropertySource<T> {
protected final Log logger = LogFactory.getLog(this.getClass());
protected final Log logger = LogFactory.getLog(getClass());
protected final String name;
protected final T source;
/**
* Create a new {@code PropertySource} with the given name and source object.
*/
@@ -74,15 +77,15 @@ public abstract class PropertySource<T> {
/**
* Create a new {@code PropertySource} with the given name and with a new {@code Object}
* instance as the underlying source.
* <p>Often useful in testing scenarios when creating
* anonymous implementations that never query an actual source, but rather return
* hard-coded values.
* <p>Often useful in testing scenarios when creating anonymous implementations that
* never query an actual source but rather return hard-coded values.
*/
@SuppressWarnings("unchecked")
public PropertySource(String name) {
this(name, (T) new Object());
}
/**
* Return the name of this {@code PropertySource}
*/
@@ -94,91 +97,75 @@ public abstract class PropertySource<T> {
* Return the underlying source object for this {@code PropertySource}.
*/
public T getSource() {
return source;
return this.source;
}
/**
* Return whether this {@code PropertySource} contains the given name.
* <p>This implementation simply checks for a null return value
* from {@link #getProperty(String)}. Subclasses may wish to
* implement a more efficient algorithm if possible.
* <p>This implementation simply checks for a {@code null} return value
* from {@link #getProperty(String)}. Subclasses may wish to implement
* a more efficient algorithm if possible.
* @param name the property name to find
*/
public boolean containsProperty(String name) {
return this.getProperty(name) != null;
return (getProperty(name) != null);
}
/**
* Return the value associated with the given name, {@code null} if not found.
* Return the value associated with the given name,
* or {@code null} if not found.
* @param name the property to find
* @see PropertyResolver#getRequiredProperty(String)
*/
public abstract Object getProperty(String name);
/**
* Return a hashcode derived from the {@code name} property of this {@code PropertySource}
* object.
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
/**
* This {@code PropertySource} object is equal to the given object if:
* <ul>
* <li>they are the same instance
* <li>the {@code name} properties for both objects are equal
* <li>they are the same instance
* <li>the {@code name} properties for both objects are equal
* </ul>
*
* <P>No properties other than {@code name} are evaluated.
* <p>No properties other than {@code name} are evaluated.
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof PropertySource))
return false;
PropertySource<?> other = (PropertySource<?>) obj;
if (this.name == null) {
if (other.name != null)
return false;
} else if (!this.name.equals(other.name))
return false;
return true;
return (this == obj || (obj instanceof PropertySource &&
ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) obj).name)));
}
/**
* Return a hash code derived from the {@code name} property
* of this {@code PropertySource} object.
*/
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.name);
}
/**
* Produce concise output (type and name) if the current log level does not include
* debug. If debug is enabled, produce verbose output including hashcode of the
* debug. If debug is enabled, produce verbose output including the hash code of the
* PropertySource instance and every name/value property pair.
*
* This variable verbosity is useful as a property source such as system properties
* <p>This variable verbosity is useful as a property source such as system properties
* or environment variables may contain an arbitrary number of property pairs,
* potentially leading to difficult to read exception and log messages.
*
* @see Log#isDebugEnabled()
*/
@Override
public String toString() {
if (logger.isDebugEnabled()) {
return String.format("%s@%s [name='%s', properties=%s]",
this.getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);
getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);
}
else {
return String.format("%s [name='%s']", getClass().getSimpleName(), this.name);
}
return String.format("%s [name='%s']",
this.getClass().getSimpleName(), this.name);
}
/**
* Return a {@code PropertySource} implementation intended for collection comparison purposes only.
*
* <p>Primarily for internal use, but given a collection of {@code PropertySource} objects, may be
* used as follows:
* <pre class="code">
@@ -189,11 +176,9 @@ public abstract class PropertySource<T> {
* assert sources.contains(PropertySource.named("sourceB"));
* assert !sources.contains(PropertySource.named("sourceC"));
* }</pre>
*
* The returned {@code PropertySource} will throw {@code UnsupportedOperationException}
* if any methods other than {@code equals(Object)}, {@code hashCode()}, and {@code toString()}
* are called.
*
* @param name the name of the comparison {@code PropertySource} to be created and returned.
*/
public static PropertySource<?> named(String name) {
@@ -209,7 +194,6 @@ public abstract class PropertySource<T> {
* {@code ApplicationContext}. In such cases, a stub should be used to hold the
* intended default position/order of the property source, then be replaced
* during context refresh.
*
* @see org.springframework.context.support.AbstractApplicationContext#initPropertySources()
* @see org.springframework.web.context.support.StandardServletEnvironment
* @see org.springframework.web.context.support.ServletContextPropertySource
@@ -221,7 +205,7 @@ public abstract class PropertySource<T> {
}
/**
* Always return {@code null}.
* Always returns {@code null}.
*/
@Override
public String getProperty(String name) {
@@ -236,8 +220,7 @@ public abstract class PropertySource<T> {
static class ComparisonPropertySource extends StubPropertySource {
private static final String USAGE_ERROR =
"ComparisonPropertySource instances are for collection comparison " +
"use only";
"ComparisonPropertySource instances are for use with collection comparison only";
public ComparisonPropertySource(String name) {
super(name);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,9 +50,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
/**
* Create a new ClassPathResource for ClassLoader usage.
* A leading slash will be removed, as the ClassLoader
* resource access methods will not accept it.
* Create a new {@code ClassPathResource} for {@code ClassLoader} usage.
* A leading slash will be removed, as the ClassLoader resource access
* methods will not accept it.
* <p>The thread context class loader will be used for
* loading the resource.
* @param path the absolute path within the class path
@@ -64,9 +64,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* Create a new ClassPathResource for ClassLoader usage.
* A leading slash will be removed, as the ClassLoader
* resource access methods will not accept it.
* Create a new {@code ClassPathResource} for {@code ClassLoader} usage.
* A leading slash will be removed, as the ClassLoader resource access
* methods will not accept it.
* @param path the absolute path within the classpath
* @param classLoader the class loader to load the resource with,
* or {@code null} for the thread context class loader
@@ -83,9 +83,9 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* Create a new ClassPathResource for Class usage.
* The path can be relative to the given class,
* or absolute within the classpath via a leading slash.
* Create a new {@code ClassPathResource} for {@code Class} usage.
* The path can be relative to the given class, or absolute within
* the classpath via a leading slash.
* @param path relative or absolute path within the class path
* @param clazz the class to load resources with
* @see java.lang.Class#getResourceAsStream
@@ -97,8 +97,8 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* Create a new ClassPathResource with optional ClassLoader and Class.
* Only for internal usage.
* Create a new {@code ClassPathResource} with optional {@code ClassLoader}
* and {@code Class}. Only for internal usage.
* @param path relative or absolute path within the classpath
* @param classLoader the class loader to load the resource with, if any
* @param clazz the class to load resources with, if any
@@ -109,6 +109,7 @@ public class ClassPathResource extends AbstractFileResolvingResource {
this.clazz = clazz;
}
/**
* Return the path for this resource (as resource path within the class path).
*/
@@ -120,9 +121,10 @@ public class ClassPathResource extends AbstractFileResolvingResource {
* Return the ClassLoader that this resource will be obtained from.
*/
public final ClassLoader getClassLoader() {
return (this.classLoader != null ? this.classLoader : this.clazz.getClassLoader());
return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
}
/**
* This implementation checks for the resolution of a resource URL.
* @see java.lang.ClassLoader#getResource(String)
@@ -130,14 +132,23 @@ public class ClassPathResource extends AbstractFileResolvingResource {
*/
@Override
public boolean exists() {
URL url;
return (resolveURL() != null);
}
/**
* Resolves a URL for the underlying class path resource.
* @return the resolved URL, or {@code null} if not resolvable
*/
protected URL resolveURL() {
if (this.clazz != null) {
url = this.clazz.getResource(this.path);
return this.clazz.getResource(this.path);
}
else if (this.classLoader != null) {
return this.classLoader.getResource(this.path);
}
else {
url = this.classLoader.getResource(this.path);
return ClassLoader.getSystemResource(this.path);
}
return (url != null);
}
/**
@@ -151,9 +162,12 @@ public class ClassPathResource extends AbstractFileResolvingResource {
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
}
else {
else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
}
else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
@@ -161,19 +175,14 @@ public class ClassPathResource extends AbstractFileResolvingResource {
}
/**
* This implementation returns a URL for the underlying class path resource.
* This implementation returns a URL for the underlying class path resource,
* if available.
* @see java.lang.ClassLoader#getResource(String)
* @see java.lang.Class#getResource(String)
*/
@Override
public URL getURL() throws IOException {
URL url;
if (this.clazz != null) {
url = this.clazz.getResource(this.path);
}
else {
url = this.classLoader.getResource(this.path);
}
URL url = resolveURL();
if (url == null) {
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
/**
* Create a new FileSystemResource from a File handle.
* Create a new {@code FileSystemResource} from a {@link File} handle.
* <p>Note: When building relative resources via {@link #createRelative},
* the relative path will apply <i>at the same directory level</i>:
* e.g. new File("C:/dir1"), relative path "dir2" -> "C:/dir2"!
@@ -62,7 +62,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
}
/**
* Create a new FileSystemResource from a file path.
* Create a new {@code FileSystemResource} from a file path.
* <p>Note: When building relative resources via {@link #createRelative},
* it makes a difference whether the specified resource base path here
* ends with a slash or not. In the case of "C:/dir1/", relative paths
@@ -77,6 +77,7 @@ public class FileSystemResource extends AbstractResource implements WritableReso
this.path = StringUtils.cleanPath(path);
}
/**
* Return the file path for this resource.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,7 +70,9 @@ public interface ResourceLoader {
* <p>Clients which need to access the ClassLoader directly can do so
* in a uniform manner with the ResourceLoader, rather than relying
* on the thread context ClassLoader.
* @return the ClassLoader (never {@code null})
* @return the ClassLoader (only {@code null} if even the system
* ClassLoader isn't accessible)
* @see org.springframework.util.ClassUtils#getDefaultClassLoader()
*/
ClassLoader getClassLoader();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,11 @@ import org.springframework.core.NestedIOException;
import org.springframework.util.Assert;
/**
* VFS based {@link Resource} implementation.
* Supports the corresponding VFS API versions on JBoss AS 5.x as well as 6.x and 7.x.
* JBoss VFS based {@link Resource} implementation.
*
* <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+ (package
* {@code org.jboss.vfs}) and is in particular compatible with JBoss AS 7 and
* WildFly 8.
*
* @author Ales Justin
* @author Juergen Hoeller
@@ -40,9 +43,9 @@ public class VfsResource extends AbstractResource {
private final Object resource;
public VfsResource(Object resources) {
Assert.notNull(resources, "VirtualFile must not be null");
this.resource = resources;
public VfsResource(Object resource) {
Assert.notNull(resource, "VirtualFile must not be null");
this.resource = resource;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,8 +29,10 @@ import org.springframework.util.ReflectionUtils;
/**
* Utility for detecting and accessing JBoss VFS in the classpath.
* As of Spring 4.0, supports VFS 3.x on JBoss AS 6+ (package {@code org.jboss.vfs})
* and is in particular compatible with JBoss AS 7 and WildFly 8.
*
* <p>As of Spring 4.0, this class supports VFS 3.x on JBoss AS 6+ (package
* {@code org.jboss.vfs}) and is in particular compatible with JBoss AS 7 and
* WildFly 8.
*
* <p>Thanks go to Marius Bogoevici for the initial patch.
* <b>Note:</b> This is an internal class and should not be used outside the framework.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@ import org.springframework.core.io.UrlResource;
import org.springframework.core.io.VfsResource;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.PathMatcher;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ResourceUtils;
@@ -143,11 +144,15 @@ import org.springframework.util.StringUtils;
*
* <p><b>WARNING:</b> Ant-style patterns with "classpath:" resources are not
* guaranteed to find matching resources if the root package to search is available
* in multiple class path locations. This is because a resource such as<pre class="code">
* in multiple class path locations. This is because a resource such as
* <pre class="code">
* com/mycompany/package1/service-context.xml
* </pre>may be in only one location, but when a path such as<pre class="code">
* </pre>
* may be in only one location, but when a path such as
* <pre class="code">
* classpath:com/mycompany/**&#47;service-context.xml
* </pre>is used to try to resolve it, the resolver will work off the (first) URL
* </pre>
* is used to try to resolve it, the resolver will work off the (first) URL
* returned by {@code getResource("com/mycompany");}. If this base package
* node exists in multiple classloader locations, the actual end resource may
* not be underneath. Therefore, preferably, use "{@code classpath*:}" with the same
@@ -171,10 +176,10 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
private static Method equinoxResolveMethod;
static {
// Detect Equinox OSGi (e.g. on WebSphere 6.1)
try {
Class<?> fileLocatorClass = PathMatchingResourcePatternResolver.class.getClassLoader().loadClass(
"org.eclipse.core.runtime.FileLocator");
// Detect Equinox OSGi (e.g. on WebSphere 6.1)
Class<?> fileLocatorClass = ClassUtils.forName("org.eclipse.core.runtime.FileLocator",
PathMatchingResourcePatternResolver.class.getClassLoader());
equinoxResolveMethod = fileLocatorClass.getMethod("resolve", URL.class);
logger.debug("Found Equinox FileLocator for OSGi bundle URL resolution");
}
@@ -198,17 +203,6 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
this.resourceLoader = new DefaultResourceLoader();
}
/**
* Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
* @param classLoader the ClassLoader to load classpath resources with,
* or {@code null} for using the thread context class loader
* at the time of actual resource access
* @see org.springframework.core.io.DefaultResourceLoader
*/
public PathMatchingResourcePatternResolver(ClassLoader classLoader) {
this.resourceLoader = new DefaultResourceLoader(classLoader);
}
/**
* Create a new PathMatchingResourcePatternResolver.
* <p>ClassLoader access will happen via the thread context class loader.
@@ -220,6 +214,18 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
this.resourceLoader = resourceLoader;
}
/**
* Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
* @param classLoader the ClassLoader to load classpath resources with,
* or {@code null} for using the thread context class loader
* at the time of actual resource access
* @see org.springframework.core.io.DefaultResourceLoader
*/
public PathMatchingResourcePatternResolver(ClassLoader classLoader) {
this.resourceLoader = new DefaultResourceLoader(classLoader);
}
/**
* Return the ResourceLoader that this pattern resolver works with.
*/
@@ -227,10 +233,6 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
return this.resourceLoader;
}
/**
* Return the ClassLoader that this pattern resolver works with
* (never {@code null}).
*/
@Override
public ClassLoader getClassLoader() {
return getResourceLoader().getClassLoader();
@@ -301,7 +303,8 @@ public class PathMatchingResourcePatternResolver implements ResourcePatternResol
if (path.startsWith("/")) {
path = path.substring(1);
}
Enumeration<URL> resourceUrls = getClassLoader().getResources(path);
ClassLoader cl = getClassLoader();
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
Set<Resource> result = new LinkedHashSet<Resource>(16);
while (resourceUrls.hasMoreElements()) {
URL url = resourceUrls.nextElement();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -170,12 +170,13 @@ public abstract class PropertiesLoaderUtils {
*/
public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
Assert.notNull(resourceName, "Resource name must not be null");
ClassLoader clToUse = classLoader;
if (clToUse == null) {
clToUse = ClassUtils.getDefaultClassLoader();
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = ClassUtils.getDefaultClassLoader();
}
Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
ClassLoader.getSystemResources(resourceName));
Properties props = new Properties();
Enumeration<URL> urls = clToUse.getResources(resourceName);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
URLConnection con = url.openConnection();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.core.io.support;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import org.springframework.core.env.PropertiesPropertySource;
@@ -36,6 +37,8 @@ import org.springframework.util.StringUtils;
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see org.springframework.core.io.Resource
* @see org.springframework.core.io.support.EncodedResource
*/
public class ResourcePropertySource extends PropertiesPropertySource {
@@ -112,10 +115,27 @@ public class ResourcePropertySource extends PropertiesPropertySource {
this(new DefaultResourceLoader().getResource(location));
}
private ResourcePropertySource(String name, Map<String, Object> source) {
super(name, source);
}
/**
* Return the description string for the resource, and if empty returns
* the class name of the resource plus its identity hash code.
* Return a potentially adapted variant of this {@link ResourcePropertySource},
* overriding the previously given (or derived) name with the specified name.
*/
public ResourcePropertySource withName(String name) {
if (this.name.equals(name)) {
return this;
}
return new ResourcePropertySource(name, this.source);
}
/**
* Return the description String for the given Resource; it the description is
* empty, return the class name of the resource plus its identity hash code.
* @see org.springframework.core.io.Resource#getDescription()
*/
private static String getNameForResource(Resource resource) {
String name = resource.getDescription();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,16 +67,17 @@ public abstract class SpringFactoriesLoader {
*/
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {
Assert.notNull(factoryClass, "'factoryClass' must not be null");
if (classLoader == null) {
classLoader = SpringFactoriesLoader.class.getClassLoader();
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
List<String> factoryNames = loadFactoryNames(factoryClass, classLoader);
List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
}
List<T> result = new ArrayList<T>(factoryNames.size());
for (String factoryName : factoryNames) {
result.add(instantiateFactory(factoryName, factoryClass, classLoader));
result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
}
OrderComparator.sort(result);
return result;
@@ -85,8 +86,9 @@ public abstract class SpringFactoriesLoader {
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -128,7 +128,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
public boolean hasAnnotatedMethods(String annotationType) {
Method[] methods = getIntrospectedClass().getDeclaredMethods();
for (Method method : methods) {
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
if (!method.isBridge() && AnnotatedElementUtils.isAnnotated(method, annotationType)) {
return true;
}
}
@@ -140,7 +140,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
Method[] methods = getIntrospectedClass().getDeclaredMethods();
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
for (Method method : methods) {
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
if (!method.isBridge() && AnnotatedElementUtils.isAnnotated(method, annotationType)) {
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
}
}
@@ -25,6 +25,7 @@ import java.util.Set;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
@@ -55,10 +56,9 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
/**
* Declared as a {@link LinkedMultiValueMap} instead of a {@link MultiValueMap}
* to ensure that the hierarchical ordering of the entries is preserved.
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes(LinkedMultiValueMap, String)
* @see AnnotationReadingVisitorUtils#getMergedAnnotationAttributes
*/
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(
4);
protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = new LinkedMultiValueMap<String, AnnotationAttributes>(4);
protected final Set<MethodMetadata> methodMetadataSet = new LinkedHashSet<MethodMetadata>(4);
@@ -70,6 +70,11 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// Skip bridge methods - we're only interested in original annotation-defining user methods.
// On JDK 8, we'd otherwise run into double detection of the same annotated method...
if ((access & Opcodes.ACC_BRIDGE) != 0) {
return super.visitMethod(access, name, desc, signature, exceptions);
}
return new MethodMetadataReadingVisitor(name, access, getClassName(), this.classLoader, this.methodMetadataSet);
}
@@ -119,8 +124,8 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
@Override
public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(this.attributesMap,
annotationType);
AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes(
this.attributesMap, this.metaAnnotationMap, annotationType);
return AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw, classValuesAsString);
}
@@ -25,10 +25,9 @@ import java.util.Set;
import org.springframework.asm.Type;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.LinkedMultiValueMap;
import static org.springframework.core.annotation.AnnotationUtils.VALUE;
/**
* Internal utility class used when reading annotations.
*
@@ -98,20 +97,23 @@ abstract class AnnotationReadingVisitorUtils {
}
/**
* Retrieve the merged attributes of the annotation of the given type, if any,
* from the supplied {@code attributesMap}.
* Retrieve the merged attributes of the annotation of the given type,
* if any, from the supplied {@code attributesMap}.
* <p>Annotation attribute values appearing <em>lower</em> in the annotation
* hierarchy (i.e., closer to the declaring class) will override those
* defined <em>higher</em> in the annotation hierarchy.
* @param attributesMap the map of annotation attribute lists, keyed by
* annotation type name
* @param attributesMap the map of annotation attribute lists,
* keyed by annotation type name
* @param metaAnnotationMap the map of meta annotation relationships,
* keyed by annotation type name
* @param annotationType the name of the annotation type to look for
* @return the merged annotation attributes; or {@code null} if no matching
* annotation is present in the {@code attributesMap}
* @return the merged annotation attributes, or {@code null} if no
* matching annotation is present in the {@code attributesMap}
* @since 4.0.3
*/
public static AnnotationAttributes getMergedAnnotationAttributes(
LinkedMultiValueMap<String, AnnotationAttributes> attributesMap, String annotationType) {
LinkedMultiValueMap<String, AnnotationAttributes> attributesMap,
Map<String, Set<String>> metaAnnotationMap, String annotationType) {
// Get the unmerged list of attributes for the target annotation.
List<AnnotationAttributes> attributesList = attributesMap.get(annotationType);
@@ -119,12 +121,14 @@ abstract class AnnotationReadingVisitorUtils {
return null;
}
// To start with, we populate the results with all attribute values from the
// target annotation.
AnnotationAttributes results = attributesList.get(0);
// To start with, we populate the results with a copy of all attribute
// values from the target annotation. A copy is necessary so that we do
// not inadvertently mutate the state of the metadata passed to this
// method.
AnnotationAttributes results = new AnnotationAttributes(attributesList.get(0));
Set<String> overridableAttributeNames = new HashSet<String>(results.keySet());
overridableAttributeNames.remove(VALUE);
overridableAttributeNames.remove(AnnotationUtils.VALUE);
// Since the map is a LinkedMultiValueMap, we depend on the ordering of
// elements in the map and reverse the order of the keys in order to traverse
@@ -132,17 +136,23 @@ abstract class AnnotationReadingVisitorUtils {
List<String> annotationTypes = new ArrayList<String>(attributesMap.keySet());
Collections.reverse(annotationTypes);
// No need to revisit the target annotation type:
annotationTypes.remove(annotationType);
for (String currentAnnotationType : annotationTypes) {
List<AnnotationAttributes> currentAttributesList = attributesMap.get(currentAnnotationType);
if (currentAttributesList != null && !currentAttributesList.isEmpty()) {
AnnotationAttributes currentAttributes = currentAttributesList.get(0);
for (String overridableAttributeName : overridableAttributeNames) {
Object value = currentAttributes.get(overridableAttributeName);
if (value != null) {
// Store the value, potentially overriding a value from an
// attribute of the same name found higher in the annotation
// hierarchy.
results.put(overridableAttributeName, value);
Set<String> metaAnns = metaAnnotationMap.get(currentAnnotationType);
if (metaAnns != null && metaAnns.contains(annotationType)) {
AnnotationAttributes currentAttributes = currentAttributesList.get(0);
for (String overridableAttributeName : overridableAttributeNames) {
Object value = currentAttributes.get(overridableAttributeName);
if (value != null) {
// Store the value, potentially overriding a value from an
// attribute of the same name found higher in the annotation
// hierarchy.
results.put(overridableAttributeName, value);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@ package org.springframework.core.type.filter;
import java.io.IOException;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
/**
* Type filter that is aware of traversing over hierarchy.
@@ -61,40 +61,38 @@ public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilte
return true;
}
if (!this.considerInherited) {
return false;
}
if (metadata.hasSuperClass()) {
// Optimization to avoid creating ClassReader for super class.
Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
if (superClassMatch != null) {
if (superClassMatch.booleanValue()) {
return true;
if (this.considerInherited) {
if (metadata.hasSuperClass()) {
// Optimization to avoid creating ClassReader for super class.
Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
if (superClassMatch != null) {
if (superClassMatch.booleanValue()) {
return true;
}
}
}
else {
// Need to read super class to determine a match...
if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
return true;
else {
// Need to read super class to determine a match...
if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
return true;
}
}
}
}
if (!this.considerInterfaces) {
return false;
}
for (String ifc : metadata.getInterfaceNames()) {
// Optimization to avoid creating ClassReader for super class
Boolean interfaceMatch = matchInterface(ifc);
if (interfaceMatch != null) {
if (interfaceMatch.booleanValue()) {
return true;
if (this.considerInterfaces) {
for (String ifc : metadata.getInterfaceNames()) {
// Optimization to avoid creating ClassReader for super class
Boolean interfaceMatch = matchInterface(ifc);
if (interfaceMatch != null) {
if (interfaceMatch.booleanValue()) {
return true;
}
}
}
else {
// Need to read interface to determine a match...
if (match(ifc, metadataReaderFactory)) {
return true;
else {
// Need to read interface to determine a match...
if (match(ifc, metadataReaderFactory)) {
return true;
}
}
}
}
@@ -132,7 +130,7 @@ public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilte
/**
* Override this to match on interface type name.
*/
protected Boolean matchInterface(String interfaceNames) {
protected Boolean matchInterface(String interfaceName) {
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,10 @@ package org.springframework.core.type.filter;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.util.ClassUtils;
/**
* A simple filter which matches classes with a given annotation,
@@ -49,7 +51,7 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
* @param annotationType the annotation type to match
*/
public AnnotationTypeFilter(Class<? extends Annotation> annotationType) {
this(annotationType, true);
this(annotationType, true, false);
}
/**
@@ -84,16 +86,26 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
@Override
protected Boolean matchSuperClass(String superClassName) {
if (Object.class.getName().equals(superClassName)) {
return Boolean.FALSE;
return hasAnnotation(superClassName);
}
@Override
protected Boolean matchInterface(String interfaceName) {
return hasAnnotation(interfaceName);
}
protected Boolean hasAnnotation(String typeName) {
if (Object.class.getName().equals(typeName)) {
return false;
}
else if (superClassName.startsWith("java.")) {
else if (typeName.startsWith("java")) {
try {
Class<?> clazz = getClass().getClassLoader().loadClass(superClassName);
return (clazz.getAnnotation(this.annotationType) != null);
Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
return ((this.considerMetaAnnotations ? AnnotationUtils.getAnnotation(clazz, this.annotationType) :
clazz.getAnnotation(this.annotationType)) != null);
}
catch (ClassNotFoundException ex) {
// Class not found - can't determine a match that way.
catch (Throwable ex) {
// Class not regularly loadable - can't determine a match that way.
}
}
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.springframework.core.type.filter;
import org.springframework.util.ClassUtils;
/**
* A simple filter which matches classes that are assignable to a given type.
*
@@ -59,15 +61,15 @@ public class AssignableTypeFilter extends AbstractTypeHierarchyTraversingFilter
return true;
}
else if (Object.class.getName().equals(typeName)) {
return Boolean.FALSE;
return false;
}
else if (typeName.startsWith("java.")) {
else if (typeName.startsWith("java")) {
try {
Class<?> clazz = getClass().getClassLoader().loadClass(typeName);
return Boolean.valueOf(this.targetType.isAssignableFrom(clazz));
Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
return this.targetType.isAssignableFrom(clazz);
}
catch (ClassNotFoundException ex) {
// Class not found - can't determine a match that way.
catch (Throwable ex) {
// Class not regularly loadable - can't determine a match that way.
}
}
return null;
@@ -142,12 +142,14 @@ public abstract class ClassUtils {
* ClassLoader, if available; the ClassLoader that loaded the ClassUtils
* class will be used as fallback.
* <p>Call this method if you intend to use the thread context ClassLoader
* in a scenario where you absolutely need a non-null ClassLoader reference:
* in a scenario where you clearly prefer a non-null ClassLoader reference:
* for example, for class path resource loading (but not necessarily for
* {@code Class.forName}, which accepts a {@code null} ClassLoader
* reference as well).
* @return the default ClassLoader (never {@code null})
* @return the default ClassLoader (only {@code null} if even the system
* ClassLoader isn't accessible)
* @see Thread#getContextClassLoader()
* @see ClassLoader#getSystemClassLoader()
*/
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
@@ -155,11 +157,20 @@ public abstract class ClassUtils {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
@@ -185,7 +196,7 @@ public abstract class ClassUtils {
/**
* Replacement for {@code Class.forName()} that also returns Class instances
* for primitives (e.g."int") and array class names (e.g. "String[]").
* for primitives (e.g. "int") and array class names (e.g. "String[]").
* Furthermore, it is also capable of resolving inner class names in Java source
* style (e.g. "java.lang.Thread.State" instead of "java.lang.Thread$State").
* @param name the name of the Class
@@ -228,19 +239,19 @@ public abstract class ClassUtils {
return Array.newInstance(elementClass, 0).getClass();
}
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = getDefaultClassLoader();
ClassLoader clToUse = classLoader;
if (clToUse == null) {
clToUse = getDefaultClassLoader();
}
try {
return classLoaderToUse.loadClass(name);
return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
}
catch (ClassNotFoundException ex) {
int lastDotIndex = name.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);
try {
return classLoaderToUse.loadClass(innerClassName);
return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
}
catch (ClassNotFoundException ex2) {
// swallow - let original exception get through
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -317,7 +317,7 @@ public abstract class CollectionUtils {
* Enumeration elements must be assignable to the type of the given array. The array
* returned will be a different instance than the array given.
*/
public static <A,E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) {
public static <A, E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) {
ArrayList<A> elements = new ArrayList<A>();
while (enumeration.hasMoreElements()) {
elements.add(enumeration.nextElement());
@@ -387,7 +387,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
protected static int calculateShift(int minimumValue, int maximumValue) {
int shift = 0;
int value = 1;
while (value < minimumValue && value < minimumValue) {
while (value < minimumValue && value < maximumValue) {
value <<= 1;
shift++;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -287,7 +287,7 @@ public class MimeType implements Comparable<MimeType>, Serializable {
* method is <b>not</b> symmetric.
* @param other the reference media type with which to compare
* @return {@code true} if this media type includes the given media type;
* {@code false} otherwise
* {@code false} otherwise
*/
public boolean includes(MimeType other) {
if (other == null) {
@@ -424,7 +424,8 @@ public class MimeType implements Comparable<MimeType>, Serializable {
return false;
}
MimeType otherType = (MimeType) other;
return (this.type.equalsIgnoreCase(otherType.type) && this.subtype.equalsIgnoreCase(otherType.subtype) &&
return (this.type.equalsIgnoreCase(otherType.type) &&
this.subtype.equalsIgnoreCase(otherType.subtype) &&
this.parameters.equals(otherType.parameters));
}
@@ -29,7 +29,7 @@ import java.io.ByteArrayOutputStream;
*
* @author Brian Clozel
* @author Juergen Hoeller
* @since 4.0
* @since 4.0.3
*/
public class ResizableByteArrayOutputStream extends ByteArrayOutputStream {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,15 +66,15 @@ public abstract class ResourceUtils {
/** URL protocol for an entry from a zip file: "zip" */
public static final String URL_PROTOCOL_ZIP = "zip";
/** URL protocol for an entry from a WebSphere jar file: "wsjar" */
public static final String URL_PROTOCOL_WSJAR = "wsjar";
/** URL protocol for an entry from a JBoss jar file: "vfszip" */
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
/** URL protocol for a JBoss VFS resource: "vfs" */
public static final String URL_PROTOCOL_VFS = "vfs";
/** URL protocol for an entry from a WebSphere jar file: "wsjar" */
public static final String URL_PROTOCOL_WSJAR = "wsjar";
/** Separator between JAR URL and file path within the JAR */
public static final String JAR_URL_SEPARATOR = "!/";
@@ -116,7 +116,8 @@ public abstract class ResourceUtils {
Assert.notNull(resourceLocation, "Resource location must not be null");
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
URL url = ClassUtils.getDefaultClassLoader().getResource(path);
ClassLoader cl = ClassUtils.getDefaultClassLoader();
URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
if (url == null) {
String description = "class path resource [" + path + "]";
throw new FileNotFoundException(
@@ -156,7 +157,8 @@ public abstract class ResourceUtils {
if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
String description = "class path resource [" + path + "]";
URL url = ClassUtils.getDefaultClassLoader().getResource(path);
ClassLoader cl = ClassUtils.getDefaultClassLoader();
URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
if (url == null) {
throw new FileNotFoundException(
description + " cannot be resolved to absolute file path " +
@@ -252,7 +254,7 @@ public abstract class ResourceUtils {
*/
public static boolean isFileURL(URL url) {
String protocol = url.getProtocol();
return (URL_PROTOCOL_FILE.equals(protocol) || protocol.startsWith(URL_PROTOCOL_VFS));
return (URL_PROTOCOL_FILE.equals(protocol) || URL_PROTOCOL_VFS.equals(protocol));
}
/**
@@ -264,8 +266,9 @@ public abstract class ResourceUtils {
* @return whether the URL has been identified as a JAR URL
*/
public static boolean isJarURL(URL url) {
String up = url.getProtocol();
return (URL_PROTOCOL_JAR.equals(up) || URL_PROTOCOL_ZIP.equals(up) || URL_PROTOCOL_WSJAR.equals(up));
String protocol = url.getProtocol();
return (URL_PROTOCOL_JAR.equals(protocol) || URL_PROTOCOL_ZIP.equals(protocol) ||
URL_PROTOCOL_WSJAR.equals(protocol) || URL_PROTOCOL_VFSZIP.equals(protocol));
}
/**
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.Set;
import org.junit.Test;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
@@ -123,6 +124,63 @@ public class AnnotationMetadataTests {
assertThat("length of basePackageClasses[]", basePackageClasses.length, is(0));
}
/**
* https://jira.spring.io/browse/SPR-11649
*/
@Test
public void multipleAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
AnnotationMetadata metadata = new StandardAnnotationMetadata(NamedAnnotationsClass.class);
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
}
/**
* https://jira.spring.io/browse/SPR-11649
*/
@Test
public void multipleAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedAnnotationsClass.class.getName());
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
}
/**
* https://jira.spring.io/browse/SPR-11649
*/
@Test
public void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
AnnotationMetadata metadata = new StandardAnnotationMetadata(NamedComposedAnnotationClass.class);
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
}
/**
* https://jira.spring.io/browse/SPR-11649
*/
@Test
public void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedComposedAnnotationClass.class.getName());
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
assertMultipleAnnotationsWithIdenticalAttributeNames(metadata);
}
private void assertMultipleAnnotationsWithIdenticalAttributeNames(AnnotationMetadata metadata) {
AnnotationAttributes attributes1 = (AnnotationAttributes) metadata.getAnnotationAttributes(
NamedAnnotation1.class.getName(), false);
String name1 = attributes1.getString("name");
assertThat("name of NamedAnnotation1", name1, is("name 1"));
AnnotationAttributes attributes2 = (AnnotationAttributes) metadata.getAnnotationAttributes(
NamedAnnotation2.class.getName(), false);
String name2 = attributes2.getString("name");
assertThat("name of NamedAnnotation2", name2, is("name 2"));
AnnotationAttributes attributes3 = (AnnotationAttributes) metadata.getAnnotationAttributes(
NamedAnnotation3.class.getName(), false);
String name3 = attributes3.getString("name");
assertThat("name of NamedAnnotation3", name3, is("name 3"));
}
private void doTestAnnotationInfo(AnnotationMetadata metadata) {
assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName()));
assertThat(metadata.isInterface(), is(false));
@@ -318,8 +376,10 @@ public class AnnotationMetadataTests {
// SPR-10914
public static enum SubclassEnum {
FOO {
/* Do not delete! This subclassing is intentional. */
},
BAR {
/* Do not delete! This subclassing is intentional. */
};
}
@@ -346,6 +406,7 @@ public class AnnotationMetadataTests {
}
}
@SuppressWarnings({ "serial" })
private static class AnnotatedComponentSubClass extends AnnotatedComponent {
}
@@ -382,4 +443,40 @@ public class AnnotationMetadataTests {
public static class ComposedConfigurationWithAttributeOverridesClass {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface NamedAnnotation1 {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface NamedAnnotation2 {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface NamedAnnotation3 {
String name() default "";
}
@NamedAnnotation1(name = "name 1")
@NamedAnnotation2(name = "name 2")
@NamedAnnotation3(name = "name 3")
public static class NamedAnnotationsClass {
}
@NamedAnnotation1(name = "name 1")
@NamedAnnotation2(name = "name 2")
@NamedAnnotation3(name = "name 3")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface NamedComposedAnnotation {
}
@NamedComposedAnnotation
public static class NamedComposedAnnotationClass {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,22 +21,19 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue;
/**
* Implements equality operator.
* Implements the equality operator.
*
* @author Andy Clement
* @since 3.0
*/
public class OpEQ extends Operator {
public OpEQ(int pos, SpelNodeImpl... operands) {
super("==", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state)
throws EvaluationException {
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
return BooleanTypedValue.forValue(equalityCheck(state, left, right));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,20 +24,19 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;
/**
* Implements greater-than operator.
* Implements the greater-than operator.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
public class OpGT extends Operator {
public OpGT(int pos, SpelNodeImpl... operands) {
super(">", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
@@ -67,6 +66,12 @@ public class OpGT extends Operator {
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
}
if (left instanceof CharSequence && right instanceof CharSequence) {
left = left.toString();
right = right.toString();
}
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,20 +27,18 @@ import org.springframework.util.NumberUtils;
* Implements the less-than operator.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
public class OpLT extends Operator {
public OpLT(int pos, SpelNodeImpl... operands) {
super("<", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state)
throws EvaluationException {
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
@@ -68,6 +66,12 @@ public class OpLT extends Operator {
return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue());
}
if (left instanceof CharSequence && right instanceof CharSequence) {
left = left.toString();
right = right.toString();
}
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,12 +28,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/
public class OpNE extends Operator {
public OpNE(int pos, SpelNodeImpl... operands) {
super("!=", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,15 +19,17 @@ package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.ClassUtils;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
/**
* Common supertype for operators that operate on either one or two operands. In the case
* of multiply or divide there would be two operands, but for unary plus or minus, there
* is only one.
* Common supertype for operators that operate on either one or two operands.
* In the case of multiply or divide there would be two operands, but for
* unary plus or minus, there is only one.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
@@ -70,6 +72,7 @@ public abstract class Operator extends SpelNodeImpl {
return sb.toString();
}
protected boolean equalityCheck(ExpressionState state, Object left, Object right) {
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
@@ -96,11 +99,22 @@ public abstract class Operator extends SpelNodeImpl {
return (leftNumber.intValue() == rightNumber.intValue());
}
if (left != null && (left instanceof Comparable)) {
return (state.getTypeComparator().compare(left, right) == 0);
if (left instanceof CharSequence && right instanceof CharSequence) {
return left.toString().equals(right.toString());
}
return ObjectUtils.nullSafeEquals(left, right);
if (ObjectUtils.nullSafeEquals(left, right)) {
return true;
}
if (left instanceof Comparable && right instanceof Comparable) {
Class<?> ancestor = ClassUtils.determineCommonAncestor(left.getClass(), right.getClass());
if (ancestor != null && Comparable.class.isAssignableFrom(ancestor)) {
return (state.getTypeComparator().compare(left, right) == 0);
}
}
return false;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -98,7 +98,7 @@ public class StandardTypeLocator implements TypeLocator {
public Class<?> findType(String typeName) throws EvaluationException {
String nameToLookup = typeName;
try {
return this.classLoader.loadClass(nameToLookup);
return ClassUtils.forName(nameToLookup, this.classLoader);
}
catch (ClassNotFoundException ey) {
// try any registered prefixes before giving up
@@ -106,7 +106,7 @@ public class StandardTypeLocator implements TypeLocator {
for (String prefix : this.knownPackagePrefixes) {
try {
nameToLookup = prefix + "." + typeName;
return this.classLoader.loadClass(nameToLookup);
return ClassUtils.forName(nameToLookup, this.classLoader);
}
catch (ClassNotFoundException ex) {
// might be a different prefix
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,121 +16,24 @@
package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals;
import java.math.BigDecimal;
import org.junit.Test;
import org.springframework.expression.spel.ast.Operator;
import org.springframework.expression.spel.standard.SpelExpression;
import static org.junit.Assert.*;
/**
* Tests the evaluation of expressions using relational operators.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
*/
public class OperatorTests extends AbstractExpressionTests {
@Test
public void testIntegerLiteral() {
evaluate("3", 3, Integer.class);
}
@Test
public void testRealLiteral() {
evaluate("3.5", 3.5d, Double.class);
}
@Test
public void testLessThan() {
evaluate("5 < 5", false, Boolean.class);
evaluate("3 < 5", true, Boolean.class);
evaluate("5 < 3", false, Boolean.class);
evaluate("3L < 5L", true, Boolean.class);
evaluate("5L < 3L", false, Boolean.class);
evaluate("3.0d < 5.0d", true, Boolean.class);
evaluate("5.0d < 3.0d", false, Boolean.class);
evaluate("'abc' < 'def'",true,Boolean.class);
evaluate("'def' < 'abc'",false,Boolean.class);
evaluate("new java.math.BigDecimal('3') < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') < new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') < 5", true, Boolean.class);
evaluate("3L < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L < new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("3 lt 5", true, Boolean.class);
evaluate("5 lt 3", false, Boolean.class);
evaluate("3L lt 5L", true, Boolean.class);
evaluate("5L lt 3L", false, Boolean.class);
evaluate("3.0d lT 5.0d", true, Boolean.class);
evaluate("5.0d Lt 3.0d", false, Boolean.class);
evaluate("'abc' LT 'def'",true,Boolean.class);
evaluate("'def' lt 'abc'",false,Boolean.class);
evaluate("new java.math.BigDecimal('3') lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') lt new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') lt 5", true, Boolean.class);
evaluate("3L lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L lt new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('3.0')", false, Boolean.class);
}
@Test
public void testLessThanOrEqual() {
evaluate("3 <= 5", true, Boolean.class);
evaluate("5 <= 3", false, Boolean.class);
evaluate("6 <= 6", true, Boolean.class);
evaluate("3L <= 5L", true, Boolean.class);
evaluate("5L <= 3L", false, Boolean.class);
evaluate("5L <= 5L", true, Boolean.class);
evaluate("3.0d <= 5.0d", true, Boolean.class);
evaluate("5.0d <= 3.0d", false, Boolean.class);
evaluate("5.0d <= 5.0d", true, Boolean.class);
evaluate("'abc' <= 'def'",true,Boolean.class);
evaluate("'def' <= 'abc'",false,Boolean.class);
evaluate("'abc' <= 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') <= 5", true, Boolean.class);
evaluate("3L <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L <= new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("3 le 5", true, Boolean.class);
evaluate("5 le 3", false, Boolean.class);
evaluate("6 Le 6", true, Boolean.class);
evaluate("3L lE 5L", true, Boolean.class);
evaluate("5L LE 3L", false, Boolean.class);
evaluate("5L le 5L", true, Boolean.class);
evaluate("3.0d LE 5.0d", true, Boolean.class);
evaluate("5.0d lE 3.0d", false, Boolean.class);
evaluate("5.0d Le 5.0d", true, Boolean.class);
evaluate("'abc' Le 'def'",true,Boolean.class);
evaluate("'def' LE 'abc'",false,Boolean.class);
evaluate("'abc' le 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') le 5", true, Boolean.class);
evaluate("3L le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L le new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('3.0')", true, Boolean.class);
}
@Test
public void testEqual() {
evaluate("3 == 5", false, Boolean.class);
@@ -138,7 +41,6 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("6 == 6", true, Boolean.class);
evaluate("3.0f == 5.0f", false, Boolean.class);
evaluate("3.0f == 3.0f", true, Boolean.class);
evaluate("'abc' == null", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') == new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') == new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') == new java.math.BigDecimal('3')", false, Boolean.class);
@@ -149,13 +51,19 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L == new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d == new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d == new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("3.0f == 3.0d", true, Boolean.class);
evaluate("10 == '10'", false, Boolean.class);
evaluate("'abc' == 'abc'", true, Boolean.class);
evaluate("'abc' == new java.lang.StringBuilder('abc')", true, Boolean.class);
evaluate("'abc' == 'def'", false, Boolean.class);
evaluate("'abc' == null", false, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() == new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", true, Boolean.class);
evaluate("3 eq 5", false, Boolean.class);
evaluate("5 eQ 3", false, Boolean.class);
evaluate("6 Eq 6", true, Boolean.class);
evaluate("3.0f eq 5.0f", false, Boolean.class);
evaluate("3.0f EQ 3.0f", true, Boolean.class);
evaluate("'abc' EQ null", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') eq new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') eq new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') eq new java.math.BigDecimal('3')", false, Boolean.class);
@@ -166,6 +74,13 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L eq new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d eq new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d eq new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("3.0f eq 3.0d", true, Boolean.class);
evaluate("10 eq '10'", false, Boolean.class);
evaluate("'abc' eq 'abc'", true, Boolean.class);
evaluate("'abc' eq new java.lang.StringBuilder('abc')", true, Boolean.class);
evaluate("'abc' eq 'def'", false, Boolean.class);
evaluate("'abc' eq null", false, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() eq new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", true, Boolean.class);
}
@Test
@@ -185,6 +100,13 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L != new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d != new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d != new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("3.0f != 3.0d", false, Boolean.class);
evaluate("10 != '10'", true, Boolean.class);
evaluate("'abc' != 'abc'", false, Boolean.class);
evaluate("'abc' != new java.lang.StringBuilder('abc')", false, Boolean.class);
evaluate("'abc' != 'def'", true, Boolean.class);
evaluate("'abc' != null", true, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() != new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", false, Boolean.class);
evaluate("3 ne 5", true, Boolean.class);
evaluate("5 nE 3", true, Boolean.class);
@@ -201,6 +123,145 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L ne new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d ne new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d ne new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("3.0f ne 3.0d", false, Boolean.class);
evaluate("10 ne '10'", true, Boolean.class);
evaluate("'abc' ne 'abc'", false, Boolean.class);
evaluate("'abc' ne new java.lang.StringBuilder('abc')", false, Boolean.class);
evaluate("'abc' ne 'def'", true, Boolean.class);
evaluate("'abc' ne null", true, Boolean.class);
evaluate("new org.springframework.expression.spel.OperatorTests$SubComparable() ne new org.springframework.expression.spel.OperatorTests$OtherSubComparable()", false, Boolean.class);
}
@Test
public void testLessThan() {
evaluate("5 < 5", false, Boolean.class);
evaluate("3 < 5", true, Boolean.class);
evaluate("5 < 3", false, Boolean.class);
evaluate("3L < 5L", true, Boolean.class);
evaluate("5L < 3L", false, Boolean.class);
evaluate("3.0d < 5.0d", true, Boolean.class);
evaluate("5.0d < 3.0d", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') < new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') < 5", true, Boolean.class);
evaluate("3L < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L < new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("'abc' < 'def'", true, Boolean.class);
evaluate("'abc' < new java.lang.StringBuilder('def')", true, Boolean.class);
evaluate("'def' < 'abc'", false, Boolean.class);
evaluate("3 lt 5", true, Boolean.class);
evaluate("5 lt 3", false, Boolean.class);
evaluate("3L lt 5L", true, Boolean.class);
evaluate("5L lt 3L", false, Boolean.class);
evaluate("3.0d lT 5.0d", true, Boolean.class);
evaluate("5.0d Lt 3.0d", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') lt new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') lt 5", true, Boolean.class);
evaluate("3L lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L lt new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("'abc' LT 'def'", true, Boolean.class);
evaluate("'abc' lt new java.lang.StringBuilder('def')", true, Boolean.class);
evaluate("'def' lt 'abc'", false, Boolean.class);
}
@Test
public void testLessThanOrEqual() {
evaluate("3 <= 5", true, Boolean.class);
evaluate("5 <= 3", false, Boolean.class);
evaluate("6 <= 6", true, Boolean.class);
evaluate("3L <= 5L", true, Boolean.class);
evaluate("5L <= 3L", false, Boolean.class);
evaluate("5L <= 5L", true, Boolean.class);
evaluate("3.0d <= 5.0d", true, Boolean.class);
evaluate("5.0d <= 3.0d", false, Boolean.class);
evaluate("5.0d <= 5.0d", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') <= 5", true, Boolean.class);
evaluate("3L <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L <= new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("'abc' <= 'def'", true, Boolean.class);
evaluate("'def' <= 'abc'", false, Boolean.class);
evaluate("'abc' <= 'abc'", true, Boolean.class);
evaluate("3 le 5", true, Boolean.class);
evaluate("5 le 3", false, Boolean.class);
evaluate("6 Le 6", true, Boolean.class);
evaluate("3L lE 5L", true, Boolean.class);
evaluate("5L LE 3L", false, Boolean.class);
evaluate("5L le 5L", true, Boolean.class);
evaluate("3.0d LE 5.0d", true, Boolean.class);
evaluate("5.0d lE 3.0d", false, Boolean.class);
evaluate("5.0d Le 5.0d", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') le 5", true, Boolean.class);
evaluate("3L le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L le new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("'abc' Le 'def'", true, Boolean.class);
evaluate("'def' LE 'abc'", false, Boolean.class);
evaluate("'abc' le 'abc'", true, Boolean.class);
}
@Test
public void testGreaterThan() {
evaluate("3 > 5", false, Boolean.class);
evaluate("5 > 3", true, Boolean.class);
evaluate("3L > 5L", false, Boolean.class);
evaluate("5L > 3L", true, Boolean.class);
evaluate("3.0d > 5.0d", false, Boolean.class);
evaluate("5.0d > 3.0d", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') > new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') > 5", false, Boolean.class);
evaluate("3L > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L > new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("'abc' > 'def'", false, Boolean.class);
evaluate("'abc' > new java.lang.StringBuilder('def')", false, Boolean.class);
evaluate("'def' > 'abc'", true, Boolean.class);
evaluate("3 gt 5", false, Boolean.class);
evaluate("5 gt 3", true, Boolean.class);
evaluate("3L gt 5L", false, Boolean.class);
evaluate("5L gt 3L", true, Boolean.class);
evaluate("3.0d gt 5.0d", false, Boolean.class);
evaluate("5.0d gT 3.0d", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') gt new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') gt 5", false, Boolean.class);
evaluate("3L gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L gt new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("'abc' Gt 'def'", false, Boolean.class);
evaluate("'abc' gt new java.lang.StringBuilder('def')", false, Boolean.class);
evaluate("'def' GT 'abc'", true, Boolean.class);
}
@Test
@@ -213,10 +274,7 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("5L >= 5L", true, Boolean.class);
evaluate("3.0d >= 5.0d", false, Boolean.class);
evaluate("5.0d >= 3.0d", true, Boolean.class);
evaluate("5.0d <= 5.0d", true, Boolean.class);
evaluate("'abc' >= 'def'",false,Boolean.class);
evaluate("'def' >= 'abc'",true,Boolean.class);
evaluate("'abc' >= 'abc'",true,Boolean.class);
evaluate("5.0d >= 5.0d", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') >= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') >= new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') >= new java.math.BigDecimal('3')", true, Boolean.class);
@@ -227,11 +285,19 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L >= new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d >= new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d >= new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("'abc' >= 'def'", false, Boolean.class);
evaluate("'def' >= 'abc'", true, Boolean.class);
evaluate("'abc' >= 'abc'", true, Boolean.class);
evaluate("3 GE 5", false, Boolean.class);
evaluate("5 gE 3", true, Boolean.class);
evaluate("6 Ge 6", true, Boolean.class);
evaluate("3L ge 5L", false, Boolean.class);
evaluate("5L ge 3L", true, Boolean.class);
evaluate("5L ge 5L", true, Boolean.class);
evaluate("3.0d ge 5.0d", false, Boolean.class);
evaluate("5.0d ge 3.0d", true, Boolean.class);
evaluate("5.0d ge 5.0d", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') ge new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') ge new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') ge new java.math.BigDecimal('3')", true, Boolean.class);
@@ -242,41 +308,19 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L ge new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d ge new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d ge new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("'abc' ge 'def'", false, Boolean.class);
evaluate("'def' ge 'abc'", true, Boolean.class);
evaluate("'abc' ge 'abc'", true, Boolean.class);
}
@Test
public void testGreaterThan() {
evaluate("3 > 5", false, Boolean.class);
evaluate("5 > 3", true, Boolean.class);
evaluate("3L > 5L", false, Boolean.class);
evaluate("5L > 3L", true, Boolean.class);
evaluate("3.0d > 5.0d", false, Boolean.class);
evaluate("5.0d > 3.0d", true, Boolean.class);
evaluate("'abc' > 'def'",false,Boolean.class);
evaluate("'def' > 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('3') > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') > new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') > 5", false, Boolean.class);
evaluate("3L > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L > new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('3.0')", false, Boolean.class);
public void testIntegerLiteral() {
evaluate("3", 3, Integer.class);
}
evaluate("3.0d gt 5.0d", false, Boolean.class);
evaluate("5.0d gT 3.0d", true, Boolean.class);
evaluate("'abc' Gt 'def'",false,Boolean.class);
evaluate("'def' GT 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('3') gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') gt new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') gt 5", false, Boolean.class);
evaluate("3L gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L gt new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('3.0')", false, Boolean.class);
@Test
public void testRealLiteral() {
evaluate("3.5", 3.5d, Double.class);
}
@Test
@@ -527,10 +571,10 @@ public class OperatorTests extends AbstractExpressionTests {
@Test
public void testStrings() {
evaluate("'abc' == 'abc'",true,Boolean.class);
evaluate("'abc' == 'def'",false,Boolean.class);
evaluate("'abc' != 'abc'",false,Boolean.class);
evaluate("'abc' != 'def'",true,Boolean.class);
evaluate("'abc' == 'abc'", true, Boolean.class);
evaluate("'abc' == 'def'", false, Boolean.class);
evaluate("'abc' != 'abc'", false, Boolean.class);
evaluate("'abc' != 'def'", true, Boolean.class);
}
@Test
@@ -544,25 +588,41 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L - 50L", -47L, Long.class);
}
// ---
private Operator getOperatorNode(SpelExpression e) {
SpelNode node = e.getAST();
return (Operator)findNode(node,Operator.class);
private Operator getOperatorNode(SpelExpression expr) {
SpelNode node = expr.getAST();
return findOperator(node);
}
private SpelNode findNode(SpelNode node, Class<Operator> clazz) {
if (clazz.isAssignableFrom(node.getClass())) {
return node;
private Operator findOperator(SpelNode node) {
if (node instanceof Operator) {
return (Operator) node;
}
int childCount = node.getChildCount();
for (int i=0;i<childCount;i++) {
SpelNode possible = findNode(node.getChild(i),clazz);
if (possible!=null) {
for (int i = 0; i < childCount; i++) {
Operator possible = findOperator(node.getChild(i));
if (possible != null) {
return possible;
}
}
return null;
}
public static class BaseComparable implements Comparable<BaseComparable> {
@Override
public int compareTo(BaseComparable other) {
return 0;
}
}
public static class SubComparable extends BaseComparable {
}
public static class OtherSubComparable extends BaseComparable {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package org.springframework.jdbc.core;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.rowset.CachedRowSet;
import javax.sql.rowset.RowSetFactory;
import javax.sql.rowset.RowSetProvider;
@@ -26,6 +25,7 @@ import javax.sql.rowset.RowSetProvider;
import org.springframework.core.JdkVersion;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.util.ClassUtils;
/**
* {@link ResultSetExtractor} implementation that returns a Spring {@link SqlRowSet}
@@ -134,12 +134,14 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
*/
private static class SunCachedRowSetFactory implements CachedRowSetFactory {
private static final Class<?> IMPLEMENTATION_CLASS;
private static final Class<?> implementationClass;
static {
try {
IMPLEMENTATION_CLASS = Class.forName("com.sun.rowset.CachedRowSetImpl");
implementationClass = ClassUtils.forName("com.sun.rowset.CachedRowSetImpl",
SqlRowSetResultSetExtractor.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
catch (Throwable ex) {
throw new IllegalStateException(ex);
}
}
@@ -147,12 +149,9 @@ public class SqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet
@Override
public CachedRowSet createCachedRowSet() throws SQLException {
try {
return (CachedRowSet) IMPLEMENTATION_CLASS.newInstance();
return (CachedRowSet) implementationClass.newInstance();
}
catch (InstantiationException ex) {
throw new IllegalStateException(ex);
}
catch (IllegalAccessException ex) {
catch (Throwable ex) {
throw new IllegalStateException(ex);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,9 @@ import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* The HSQL specific implementation of the {@link TableMetaDataProvider}.
* Supports a feature for retreiving generated keys without the JDBC 3.0 getGeneratedKeys support.
* The HSQL specific implementation of {@link TableMetaDataProvider}.
* Supports a feature for retrieving generated keys without the JDBC 3.0
* {@code getGeneratedKeys} support.
*
* @author Thomas Risberg
* @since 2.5
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,8 +29,8 @@ import org.springframework.util.ReflectionUtils;
/**
* Oracle-specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
* Supports a feature for including synonyms in the metadata lookup. Also supports lookup of current schema using
* the sys_context.
* Supports a feature for including synonyms in the metadata lookup. Also supports lookup of current schema
* using the sys_context.
*
* <p>Thanks to Mike Youngstrom and Bruce Campbell for submitting the original suggestion for the Oracle
* current schema lookup implementation.
@@ -56,9 +56,10 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
lookupDefaultSchema(databaseMetaData);
}
@Override
protected String getDefaultSchema() {
if (defaultSchema != null) {
if (this.defaultSchema != null) {
return defaultSchema;
}
return super.getDefaultSchema();
@@ -81,7 +82,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
}
boolean isOracleCon;
try {
Class<?> oracleConClass = getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection");
Class<?> oracleConClass = con.getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection");
isOracleCon = oracleConClass.isInstance(con);
}
catch (ClassNotFoundException ex) {
@@ -107,7 +108,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
ReflectionUtils.makeAccessible(getIncludeSynonyms);
originalValueForIncludeSynonyms = (Boolean) getIncludeSynonyms.invoke(con);
setIncludeSynonyms = con.getClass().getMethod("setIncludeSynonyms", new Class<?>[] {boolean.class});
setIncludeSynonyms = con.getClass().getMethod("setIncludeSynonyms", boolean.class);
ReflectionUtils.makeAccessible(setIncludeSynonyms);
setIncludeSynonyms.invoke(con, Boolean.TRUE);
}
@@ -126,9 +127,7 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
}
/*
* Oracle implementation for detecting current schema
*
* @param databaseMetaData
* Oracle-based implementation for detecting the current schema.
*/
private void lookupDefaultSchema(DatabaseMetaData databaseMetaData) {
try {
@@ -144,7 +143,9 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
cstmt.close();
}
}
} catch (Exception ignore) {}
}
catch (Exception ignore) {
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,9 @@ import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/**
* The PostgreSQL specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
* Suports a feature for retreiving generated keys without the JDBC 3.0 getGeneratedKeys support.
* The PostgreSQL specific implementation of {@link TableMetaDataProvider}.
* Supports a feature for retrieving generated keys without the JDBC 3.0
* {@code getGeneratedKeys} support.
*
* @author Thomas Risberg
* @since 2.5
@@ -38,7 +39,10 @@ public class PostgresTableMetaDataProvider extends GenericTableMetaDataProvider
return true;
}
else {
logger.warn("PostgreSQL does not support getGeneratedKeys or INSERT ... RETURNING in version " + getDatabaseVersion());
if (logger.isWarnEnabled()) {
logger.warn("PostgreSQL does not support getGeneratedKeys or INSERT ... RETURNING in version " +
getDatabaseVersion());
}
return false;
}
}
@@ -47,4 +51,5 @@ public class PostgresTableMetaDataProvider extends GenericTableMetaDataProvider
public String getSimpleQueryForGetGeneratedKey(String tableName, String keyColumnName) {
return "RETURNING " + keyColumnName;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,10 +33,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* {@link org.springframework.transaction.PlatformTransactionManager}
* implementation for a single JDBC {@link javax.sql.DataSource}. This class is
* capable of working in any environment with any JDBC driver, as long as the setup
* uses a JDBC 2.0 Standard Extensions / JDBC 3.0 {@code javax.sql.DataSource}
* as its Connection factory mechanism. Binds a JDBC Connection from the specified
* DataSource to the current thread, potentially allowing for one thread-bound
* Connection per DataSource.
* uses a {@code javax.sql.DataSource} as its {@code Connection} factory mechanism.
* Binds a JDBC Connection from the specified DataSource to the current thread,
* potentially allowing for one thread-bound Connection per DataSource.
*
* <p><b>Note: The DataSource that this transaction manager operates on needs
* to return independent Connections.</b> The Connections may come from a pool
@@ -75,8 +74,8 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* an actual JDBC Connection from the target DataSource until a Statement gets executed,
* lazily applying the specified transaction settings to the target Connection.
*
* <p>On JDBC 3.0, this transaction manager supports nested transactions via the
* JDBC 3.0 {@link java.sql.Savepoint} mechanism. The
* <p>This transaction manager supports nested transactions via the JDBC 3.0
* {@link java.sql.Savepoint} mechanism. The
* {@link #setNestedTransactionAllowed "nestedTransactionAllowed"} flag defaults
* to "true", since nested transactions will work without restrictions on JDBC
* drivers that support savepoints (such as the Oracle JDBC driver).
@@ -21,6 +21,7 @@ import javax.sql.DataSource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.datasource.init.ScriptUtils;
import org.springframework.util.Assert;
/**
@@ -161,7 +162,9 @@ public class EmbeddedDatabaseBuilder {
/**
* Specify the statement separator used in all SQL scripts, if a custom one.
* <p>Default is ";".
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
* to signal that each script contains a single statement without a separator.
* @param separator the statement separator
* @return {@code this}, to facilitate method chaining
* @since 4.0.3
@@ -173,7 +176,7 @@ public class EmbeddedDatabaseBuilder {
/**
* Specify the single-line comment prefix used in all SQL scripts.
* <p>Default is "--".
* <p>Defaults to {@code "--"}.
* @param commentPrefix the prefix for single-line comments
* @return {@code this}, to facilitate method chaining
* @since 4.0.3
@@ -185,7 +188,7 @@ public class EmbeddedDatabaseBuilder {
/**
* Specify the start delimiter for block comments in all SQL scripts.
* <p>Default is "/*".
* <p>Defaults to {@code "/*"}.
* @param blockCommentStartDelimiter the start delimiter for block comments
* @return {@code this}, to facilitate method chaining
* @since 4.0.3
@@ -199,7 +202,7 @@ public class EmbeddedDatabaseBuilder {
/**
* Specify the end delimiter for block comments in all SQL scripts.
* <p>Default is "*&#47;".
* <p>Defaults to <code>"*&#47;"</code>.
* @param blockCommentEndDelimiter the end delimiter for block comments
* @return {@code this}, to facilitate method chaining
* @since 4.0.3
@@ -136,16 +136,18 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
/**
* Specify the statement separator, if a custom one.
* <p>Default is ";".
* @param separator the statement separator
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
* to signal that each script contains a single statement without a separator.
* @param separator the script statement separator
*/
public void setSeparator(String separator) {
this.separator = separator;
}
/**
* Set the prefix that identifies line comments within the SQL scripts.
* <p>Default is "--".
* Set the prefix that identifies single-line comments within the SQL scripts.
* <p>Defaults to {@code "--"}.
* @param commentPrefix the prefix for single-line comments
*/
public void setCommentPrefix(String commentPrefix) {
@@ -155,7 +157,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
/**
* Set the start delimiter that identifies block comments within the SQL
* scripts.
* <p>Default is "/*".
* <p>Defaults to {@code "/*"}.
* @param blockCommentStartDelimiter the start delimiter for block comments
* @since 4.0.3
* @see #setBlockCommentEndDelimiter
@@ -167,7 +169,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
/**
* Set the end delimiter that identifies block comments within the SQL
* scripts.
* <p>Default is "*&#47;".
* <p>Defaults to <code>"*&#47;"</code>.
* @param blockCommentEndDelimiter the end delimiter for block comments
* @since 4.0.3
* @see #setBlockCommentStartDelimiter
@@ -61,6 +61,17 @@ public abstract class ScriptUtils {
*/
public static final String FALLBACK_STATEMENT_SEPARATOR = "\n";
/**
* End of file (EOF) SQL statement separator.
* <p>This value may be supplied as the {@code separator} to {@link
* #executeSqlScript(Connection, EncodedResource, boolean, boolean, String, String, String, String)}
* to denote that an SQL script contains a single statement (potentially
* spanning multiple lines) with no explicit statement separator. Note that
* such a script should not actually contain this value; it is merely a
* <em>virtual</em> statement separator.
*/
public static final String EOF_STATEMENT_SEPARATOR = "^^^ END OF SCRIPT ^^^";
/**
* Default prefix for line comments within SQL scripts.
*/
@@ -399,12 +410,17 @@ public abstract class ScriptUtils {
* typically "--"
* @param separator the script statement separator; defaults to
* {@value #DEFAULT_STATEMENT_SEPARATOR} if not specified and falls back to
* {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort
* {@value #FALLBACK_STATEMENT_SEPARATOR} as a last resort; may be set to
* {@value #EOF_STATEMENT_SEPARATOR} to signal that the script contains a
* single statement without a separator
* @param blockCommentStartDelimiter the <em>start</em> block comment delimiter; never
* {@code null} or empty
* @param blockCommentEndDelimiter the <em>end</em> block comment delimiter; never
* {@code null} or empty
* @throws ScriptException if an error occurred while executing the SQL script
* @see #DEFAULT_STATEMENT_SEPARATOR
* @see #FALLBACK_STATEMENT_SEPARATOR
* @see #EOF_STATEMENT_SEPARATOR
*/
public static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError,
boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter,
@@ -428,7 +444,7 @@ public abstract class ScriptUtils {
if (separator == null) {
separator = DEFAULT_STATEMENT_SEPARATOR;
}
if (!containsSqlScriptDelimiters(script, separator)) {
if (!EOF_STATEMENT_SEPARATOR.equals(separator) && !containsSqlScriptDelimiters(script, separator)) {
separator = FALLBACK_STATEMENT_SEPARATOR;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
package org.springframework.jdbc.object;
import java.util.Map;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
@@ -33,9 +33,7 @@ import org.springframework.jdbc.core.SqlParameter;
* {@link #execute} method.
*
* <p>The inherited {@code sql} property is the name of the stored
* procedure in the RDBMS. Note that JDBC 3.0 introduces named parameters,
* although the other features provided by this class are still necessary
* in JDBC 3.0.
* procedure in the RDBMS.
*
* @author Rod Johnson
* @author Thomas Risberg
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
@@ -51,7 +50,7 @@ import org.springframework.jdbc.support.JdbcUtils;
* is rolled back, the unused values will never be served. The maximum hole size in
* numbering is consequently the value of cacheSize.
*
* <b>HINT:</b> Since Derby supports the JDBC 3.0 {@code getGeneratedKeys} method,
* <b>HINT:</b> Since Derby supports the JDBC 3.0 {@code getGeneratedKeys} method,
* it is recommended to use IDENTITY columns directly in the tables and then utilizing
* a {@link org.springframework.jdbc.support.KeyHolder} when calling the with the
* {@code update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)}
@@ -1,16 +1,32 @@
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.support.incrementer;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* {@link DataFieldMaxValueIncrementer} that increments the maximum value of a given SQL Server table
* with the equivalent of an auto-increment column. Note: If you use this class, your Derby key
@@ -32,8 +48,8 @@ import java.sql.SQLException;
* is rolled back, the unused values will never be served. The maximum hole size in
* numbering is consequently the value of cacheSize.
*
* <b>HINT:</b> Since Microsoft SQL Server supports the JDBC 3.0 {@code getGeneratedKeys} method,
* it is recommended to use IDENTITY columns directly in the tables and then using a
* <b>HINT:</b> Since Microsoft SQL Server supports the JDBC 3.0 {@code getGeneratedKeys}
* method, it is recommended to use IDENTITY columns directly in the tables and then using a
* {@link org.springframework.jdbc.core.simple.SimpleJdbcInsert} or utilizing
* a {@link org.springframework.jdbc.support.KeyHolder} when calling the with the
* {@code update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder)}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import javax.sql.DataSource;
* is rolled back, the unused values will never be served. The maximum hole size in
* numbering is consequently the value of cacheSize.
*
* <b>HINT:</b> Since Sybase Anywhere supports the JDBC 3.0 {@code getGeneratedKeys} method,
* <b>HINT:</b> Since Sybase Anywhere supports the JDBC 3.0 {@code getGeneratedKeys} method,
* it is recommended to use IDENTITY columns directly in the tables and then using a
* {@link org.springframework.jdbc.core.simple.SimpleJdbcInsert} or utilizing
* a {@link org.springframework.jdbc.support.KeyHolder} when calling the with the

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