Compare commits

...

95 Commits

Author SHA1 Message Date
Spring Buildmaster f5e8f4983f Release version 5.0.6.RELEASE 2018-05-08 08:34:12 +00:00
Juergen Hoeller 2da02ccbd0 Polishing
(cherry picked from commit 70424a7)
2018-05-08 00:25:46 +02:00
Juergen Hoeller f2cc70ecf9 Explicit coverage of root vs cause exception matching in MVC ref docs
Issue: SPR-16743

(cherry picked from commit a200df6)
2018-05-07 23:18:33 +02:00
Rossen Stoyanchev e2115594c0 Document throwExceptionIfNoHandlerFound property
Issue: SPR-16786
2018-05-07 16:12:25 -04:00
Juergen Hoeller 2008e04354 Upgrade to Servlet API 4.0.1 2018-05-07 14:38:16 +02:00
Juergen Hoeller b4f83dbdc3 Polishing 2018-05-07 14:30:50 +02:00
Juergen Hoeller 0795ae5c6a Polishing 2018-05-05 16:55:06 +02:00
Juergen Hoeller 41ab177b6c Fine-tuned assertions and related polishing 2018-05-05 14:59:13 +02:00
Juergen Hoeller 8848ec73ab Refined backport of gh-1817 2018-05-05 13:18:08 +02:00
Juergen Hoeller 9f9481ec7b Upgrade to Tomcat 8.5.31, Undertow 1.4.25, Jetty 9.4.10, Gson 2.8.4
Includes upgrade from Reactor snapshots to Bismuth SR9.
2018-05-05 13:17:44 +02:00
Juergen Hoeller f6275e009b YamlProcessor embraces SnakeYAML 1.18+ duplicate key handling
Includes deprecation of StrictMapAppenderConstructor.

Issue: SPR-16791

(cherry picked from commit 138b0d0)
2018-05-05 13:17:10 +02:00
Juergen Hoeller ed44262a71 ResponseEntityExceptionHandler rethrows unknown exception (for further processing in DispatcherServlet's HandlerExceptionResolver chain)
Issue: SPR-16743

(cherry picked from commit 7b894fe)
2018-05-05 13:17:00 +02:00
Johnny Lim a0d37ac29e Remove inconsistent spaces
(cherry picked from commit fb898e1)
2018-05-05 12:49:26 +02:00
Johnny Lim a39938d251 Polish DatabaseStartupValidator
(cherry picked from commit 8f21cb1)
2018-05-05 12:49:10 +02:00
nkjackzhang edb33331ed Task "docsZip" copies duplicate reference files
Specify task "docsZip" source directory.
Issue: SPR-16789
2018-05-03 16:39:51 -04:00
Arjen Poutsma a63f04df09 Clean up path variables after non match
This commit makes sure the nested path variables are only commited to
the attributes when all predicates match.

Issue: SPR-16692

(cherry picked from commit 51325af)
2018-05-03 12:06:06 +02:00
Juergen Hoeller 5a98516f6c Lenient fallback to plain getBundle call without Control handle
Issue: SPR-16776
2018-05-02 16:54:38 +02:00
Juergen Hoeller 30363c84bd Consistent SpelEvaluationException messages in findAccessorForMethod
Issue: SPR-16762
2018-05-02 16:53:55 +02:00
Juergen Hoeller fa27130b82 Upgrade to RxJava 2.1.13, Hibernate ORM 5.2.17, AspectJ 1.9.1 2018-05-02 16:32:55 +02:00
Juergen Hoeller be4c07fc32 Expose FactoryBean's raw object on retrieval during post-processing
Issue: SPR-16783

(cherry picked from commit 9281f82)
2018-05-02 16:32:18 +02:00
Juergen Hoeller 22f421cc51 Introspect originating bean definition as configuration class candidate
Issue: SPR-16756

(cherry picked from commit c8b6233)
2018-05-02 16:31:57 +02:00
Juergen Hoeller 9dc538a7c6 Nullable HttpMethod parameter only on internal doExecute delegate
Issue: SPR-15540

(cherry picked from commit f8c2d7a)
2018-05-02 16:31:33 +02:00
Juergen Hoeller d74a2730ec SimpleClientHttpResponse catches any Exception on close
Issue: SPR-16773

(cherry picked from commit 21fad8e)
2018-05-02 16:07:22 +02:00
Juergen Hoeller 3e47f4564d Fine-tuned assertions and related polishing in WebFlux builders
(cherry picked from commit 9bff5b4)
2018-05-02 16:04:51 +02:00
Juergen Hoeller a9548f93e4 Support for non-standard HTTP status in reactive ClientHttpResponse
Issue: SPR-16748

(cherry picked from commit a683472)
2018-05-02 16:04:01 +02:00
Juergen Hoeller f2e77c292d Consistent target method resolution for event and caching expressions
Issue: SPR-16779

(cherry picked from commit eaff2c2)
2018-05-02 16:02:46 +02:00
Juergen Hoeller 8b051ab06e AopUtils.getMostSpecificMethod exposes dynamic proxy class methods
Includes efficient canApply check for IntroductionAwareMethodMatcher.

Issue: SPR-16757

(cherry picked from commit aa11721)
2018-05-02 16:01:48 +02:00
Oleksandr Hasheniuk 5a1d7f9c4b Improve performance of StringUtils#trimWhitespace
Issue: SPR-16766

(cherry picked from commit 6545cab)
2018-05-02 16:01:04 +02:00
Sebastien Deleuze b55f69deb1 Support decoding Mono in Jaxb2XmlDecoder
Issue: SPR-16759
2018-05-02 11:57:40 +02:00
Rossen Stoyanchev de1eb343e7 Polish WebSocketIntegrationTests 2018-05-01 14:26:44 -04:00
Rossen Stoyanchev 417bb302c3 ReactorNettyWebSocketSession implements close properly
Issue: SPR-16774
2018-05-01 12:05:20 -04:00
Rossen Stoyanchev b0aa08a671 Consistent handling of URISyntaxException
Issue: SPR-16778
2018-04-30 21:05:08 -04:00
Sebastien Deleuze 9dc79982e2 Upgrade to Kotlin 1.2.41
Fixes KT-23973 critical regression
2018-04-30 10:48:23 +02:00
Stephane Nicoll 43f2334e82 Keep YAML entries that haven an empty array value
Prior to this commit, a YAML entry that define an empty array value was
lost. This commit makes sure to flag it with an empty String, which
corresponds as an empty comma separated list of entries in the
properties format.

Issue: SPR-16769
2018-04-29 11:15:53 +02:00
Nickloas 6c6e44b58e Fix typo
Closes gh-1813
2018-04-28 10:52:03 +02:00
Johnny Lim c6b60f0c00 Polish 2018-04-27 14:09:35 -04:00
sdeleuze 7aba6ca9d6 Fine tune WebFlux server logging verbosity
With this commit, WebFlux server uses warning instead of error log level
for request handling, and also just print the message instead of the
stacktrace which is mostly meaningless in reactive world.

Complementary to this change, Reactor Netty removed additional logging
as part of https://github.com/reactor/reactor-netty/issues/339.

Issue: SPR-16688
2018-04-27 10:36:06 +02:00
nkjackzhang dca77c0666 Fix broken anchor link in WebFlux refdoc 2018-04-27 08:49:51 +02:00
sdeleuze df6e690e33 Reuse PartBodyStreamStorageFactory in SynchronossPartGenerator
Issue: SPR-16727
2018-04-26 11:01:17 +02:00
nkjackzhang a702ef8074 Fix typos in Spring MVC refdoc
1. Consistent with "xml code" examples.
2. "xml()" is a static method and will use default builder config,
   so use createXmlMapper(true) instead.
3. Fix mvc namespace tag typo.
2018-04-26 10:03:27 +02:00
Rossen Stoyanchev f7376bdde3 Better assertion message in MockPart
Issue: SPR-16767
2018-04-25 10:00:18 -04:00
nkjackzhang f9e31b503c Fix typos
Closes gh-1806
2018-04-25 10:07:34 +02:00
hasheniuk 3551dd92fb Fix typo
Closes gh-1804
2018-04-24 10:06:49 +02:00
Rossen Stoyanchev c23297fe76 Add more detail to ISE in ServerEndpointExporter
Issue: SPR-16655
2018-04-23 17:04:16 -04:00
Rossen Stoyanchev a5622d0dd2 Validate contextPath in RedirectView
Issue: SPR-16752
2018-04-23 15:21:33 -04:00
Brian Clozel 72cfe41f30 Disable HTTP Range support for InputStreamResource
Prior to this commit, the `AbstractMessageConverterMethodProcessor`
would fail to convert `InputStreamResource` to `ResourceRegion` as
expected, since the content length cannot be read without consuming the
stream. This is enforced by the `HttpRange` class.

Now the method processor would still try to output HTTP range response
headers to provide range support information. This step is using the
resource content length and reads the input stream, leading to
exceptions such as "IllegalStateException: InputStream has already been
read".

This commit improves the return type detection and excludes early
`InputStreamResource` return types. With those types, HTTP range support
is now completely disabled.

Issue: SPR-16754
(cherry picked from commit e9a8a5065b)
2018-04-23 18:40:15 +02:00
sdeleuze 4ff595e2bc Upgrade Kotlin to 1.2.40 2018-04-23 15:31:31 +02:00
sdeleuze 2c766b9501 Enable KotlinScriptTemplateTests after KT-18833 fix 2018-04-23 15:31:31 +02:00
Dimitrios (Dimi) Liapis 2960a558d7 Fix typo
See gh-1803
2018-04-21 18:21:19 +02:00
Brian Clozel d69a281e5c Upgrade to Netty 4.1.24.Final 2018-04-21 09:31:29 +02:00
Rossen Stoyanchev d3ed7b624d In 5.0.x we don't have Flux/Mono error with Supplier
Issue: SPR-16726
2018-04-19 13:41:01 -04:00
Rossen Stoyanchev 66bd277671 Use StringDecoder to split SSE stream
ServerSentEventHttpMessageReader had logic to split on new lines
and buffer until an empty new line (start of a new event). To account
for random data chunking, it later re-assembled the lines for each
event and split again on new lines. However bufferUntil was still
unreliable a chunk may contain nothing but a newline, which doesn't
necessarily mean an empty newline in the overall SSE stream.

This commit simplifies the above by delegating the splitting of the
stream along newlines to StringDecoder.

Issue: SPR-16744
2018-04-19 11:38:43 -04:00
Rossen Stoyanchev 881343e928 Polish tests to use WebClient retrieve() 2018-04-19 11:38:43 -04:00
Daniel Kift 922fd1e785 Polish WebFlux reference documentation 2018-04-18 11:58:37 +02:00
nkjackzhang ea8317a1f9 Fix a typo in @Nullable Javadoc 2018-04-18 11:55:13 +02:00
Rossen Stoyanchev 053ffe808f Polish (minor) in AbstractMessageReaderArgumentResolver 2018-04-17 17:58:56 -04:00
Rossen Stoyanchev daa2d37ad4 Avoid creating Exception instance if not needed
Issue: SPR-16726
2018-04-17 17:58:46 -04:00
Juergen Hoeller f800df12e3 Correctly delegate to OrderUtils.getPriority for DecoratingProxy
Issue: SPR-16739

(cherry picked from commit 2f4010e)
2018-04-17 23:38:30 +02:00
Juergen Hoeller 26652a6b83 Avoid repeated superclass introspection in findAnnotation(Method,...)
Issue: SPR-16730

(cherry picked from commit d78e27f)
2018-04-17 17:06:31 +02:00
Juergen Hoeller 4cd43dc793 Workaround for generic parameter types on inner class constructors
Issue: SPR-16734
2018-04-17 15:32:03 +02:00
sdeleuze 91c8b62817 Make ResponseSpec.expectBody Kotlin extension usable
Prior to this commit, due to KT-5464 type inference issue there was not
proper way to provide body expectations with WebTestClient. This commit
provides a workaround by updating the existing Kotlin extension to
return a Kotlin compatible API.

Issue: SPR-15692
2018-04-17 14:58:12 +02:00
Juergen Hoeller 9d37c099a8 OperatorMatches flags misguided evaluation attempts as FLAWED_PATTERN
Issue: SPR-16731

(cherry picked from commit d4a55a2)
2018-04-17 13:35:01 +02:00
Juergen Hoeller eb573d8b9e Restore original MethodMapTransactionAttributeSource matching rules
Issue: SPR-16733

(cherry picked from commit c5b524d)
2018-04-17 13:34:38 +02:00
Rossen Stoyanchev b312a62f64 Selector header name is exposed for configuration
Issue: SPR-16732
2018-04-16 23:58:47 -04:00
Rossen Stoyanchev 567733d2a1 Restore handling of 0 bytes read
Issue: SPR-16728
2018-04-16 10:01:51 -04:00
Juergen Hoeller 0f91f4b960 Local XMLUnit dependency declarations with consistent version 2.5.1
Includes upgrade to Undertow 1.4.24.

(cherry picked from commit 0754833)
2018-04-14 21:23:33 +02:00
Juergen Hoeller c1385f52c2 Polishing
(cherry picked from commit de4ff4b)
2018-04-14 21:03:59 +02:00
Sam Brannen c3bc125093 Suppress warning in SpringFailOnTimeoutTests 2018-04-14 16:44:47 +02:00
Juergen Hoeller b5922f75bb AspectJExpressionPointcut consistently resolves superinterface methods
Includes efficient check for same ClassLoader in ClassUtils.isVisible, efficient MethodMatchers check for IntroductionAwareMethodMatcher, and supertype method resolution in MethodMapTransactionAttributeSource.

Issue: SPR-16723

(cherry picked from commit b95e05d)
2018-04-14 15:49:55 +02:00
nkjackzhang bbe850d33a Fix typo in javadoc
Closes gh-1791
2018-04-13 13:16:40 +02:00
Juergen Hoeller 295929cc16 Cache-safety check for sibling loaders resolving the same classes
Issue: SPR-16714
2018-04-12 21:08:25 +02:00
Juergen Hoeller 4763154193 Consistent getTypeForFactoryMethod result for parameterized method
Issue: SPR-16720

(cherry picked from commit 6184c4e)
2018-04-12 21:08:14 +02:00
Juergen Hoeller 8f7e5e7c1a Fine-tuned JCA MessageEndpoint exception logging and propagation
Issue: SPR-16717

(cherry picked from commit 8e1ecec)
2018-04-12 21:07:44 +02:00
Juergen Hoeller cd79966c52 Revised reference example for linkable controller method signature
Issue: SPR-16710

(cherry picked from commit 7ee6130)
2018-04-12 21:07:39 +02:00
Brian Clozel 7631aa6062 Switch to Reactor Bismusth SNAPSHOTs 2018-04-12 17:01:24 +02:00
Sam Brannen 02e09098e4 Expand scope of SpringFailOnTimeoutTests
Issue: SPR-16716
2018-04-12 11:00:45 +02:00
Igor Suhorukov 230c8f93e8 Throw exception from user code in SpringFailOnTimeout even if a timeout occurs
Issue: SPR-16717
2018-04-12 11:00:35 +02:00
Rossen Stoyanchev c4296fa785 Remove write pausing in Undertow response
Using the simple example shown in the ticket but switching from
Mono<String> to Flux<String> (and 5,000,000 onNext calls) shows that
constant pausing causes significant overhead and is not worth the
trouble vs ignoring the onWritePossible in REQUESTED state.

Issue: SPR-16702
2018-04-11 14:37:35 -04:00
Rossen Stoyanchev ab78854f1b Avoid inifinite recursion in UndertowServerHttpResponse
Undertow does not provide a way to check if we can write so with the
current implementation of isWritePossible, deep recursion can occur
when writing slows down. We now use a flag to keep track of write
ChannelListener callbacks.

This commit also addresses a related issue in
AbstractListenerWriteProcessor that went undected since #3c2d186
where after a large (single) buffer that is not written fully, the
completion signal is processed before the all data is written.

Issue: SPR-16702
2018-04-11 14:37:19 -04:00
Juergen Hoeller 96a465a749 Upgrade to Tomcat 8.5.30 2018-04-11 16:27:34 +02:00
Juergen Hoeller 861b9dc938 Proper exception for controller method return types that do not work with MvcUriComponentsBuilder (e.g. final classes)
Includes direct use of ControllerMethodInvocationInterceptor for return type Object, avoiding the attempt to generate an Object subclass.

Issue: SPR-16710

(cherry picked from commit f28a5d0)
2018-04-11 16:27:14 +02:00
sdeleuze eda2720471 Add default ctor to Reactive UrlBasedCorsConfigurationSource
Issue: SPR-16712
2018-04-11 14:41:06 +02:00
Juergen Hoeller 7fe28ce8b7 Upgrade to Netty 4.1.23 and TestNG 6.14.3 2018-04-11 13:29:37 +02:00
Juergen Hoeller de8c4179fb Polishing 2018-04-11 13:29:15 +02:00
Juergen Hoeller 433877e5cb AnnotationUtils.getAnnotation non-null check for synthesizeAnnotation
Issue: SPR-16708

(cherry picked from commit da80502)
2018-04-11 13:28:53 +02:00
Juergen Hoeller ffa4f03fd4 Unwind _TestTypes to top-level public test classes in AOP test suite
(cherry picked from commit cdaa247)
2018-04-11 13:28:39 +02:00
Juergen Hoeller 7068282e1f Remove bogus DataSource test from JpaTransactionManagerTests
(cherry picked from commit ff53d78)
2018-04-11 13:28:33 +02:00
sdeleuze 3879179927 Document why "charset=UTF-8" is specified for JSON
Issue: SPR-14715
2018-04-09 12:01:21 +02:00
KwonJH 007da2a58d Fix Java 9 link in the reference documentation 2018-04-09 11:13:25 +02:00
sdeleuze 1be585562f Improve Kotlin + bean validation documentation
Issue: SPR-16701
2018-04-09 10:18:06 +02:00
Rossen Stoyanchev 7a896d7d80 TestDispatcherServlet unwraps to find mock request
Issue: SPR-16695
2018-04-06 11:04:29 -04:00
sdeleuze be1aaa06e7 Cleanup settings.gradle pluginManagement configuration 2018-04-04 11:11:38 +02:00
sdeleuze 2fa060f0e9 Fix Dokka reference to Spring Framework's Javadoc
This commit specifies a local packageListUrl and defines that dokka task
must be executed after the api task in order to be able to build KDoc
during the release process when the Spring Framework's Javadoc is not
published yet.

Issue: SPR-16687
2018-04-04 11:11:17 +02:00
Stephane Nicoll 4d2d889142 Initiate 5.0.x branch 2018-04-03 23:07:03 +02:00
Spring Buildmaster 4b9bc50fd0 Release version 5.0.5.RELEASE 2018-04-03 20:11:16 +00:00
235 changed files with 4125 additions and 2906 deletions
+2 -2
View File
@@ -38,7 +38,7 @@ it helps us to make a decision.
Reporting an issue or making a feature request is a great way to contribute. Your feedback
and the conversations that result from it provide a continuous flow of ideas.
Before you create a ticket, please take the time to [research first](#Discuss).
Before you create a ticket, please take the time to [research first](#discuss).
If creating a ticket after a discussion on StackOverflow, please provide a self-sufficient description in the ticket, independent of the details on StackOverview. We understand this is extra work but the issue tracker is an important place of record for design discussions and decisions that can often be referenced long after the fix version, for example to revisit decisions, to understand the origin of a feature, and so on.
@@ -64,7 +64,7 @@ You can contribute a source code change by submitting a pull request.
[Contributor License Agreement](https://cla.pivotal.io/sign/spring). You will also be reminded
automatically when you submit a pull request.
1. For all but the most trivial of contributions, please [create a ticket](#Create-a-Ticket).
1. For all but the most trivial of contributions, please [create a ticket](#create-a-ticket).
The purpose of the ticket is to understand and discuss the underlying issue or feature.
We use the JIRA issue tracker as the preferred place of record for conversations and
conclusions. In that sense discussions directly under a PR are more implementation detail
+9 -10
View File
@@ -14,7 +14,7 @@ buildscript {
plugins {
id "com.gradle.build-scan" version "1.8"
id "io.spring.dependency-management" version "1.0.3.RELEASE" apply false
id "org.jetbrains.kotlin.jvm" version "1.2.31" apply false
id "org.jetbrains.kotlin.jvm" version "1.2.41" apply false
id "org.jetbrains.dokka" version "0.9.16"
id "org.asciidoctor.convert" version "1.5.6"
}
@@ -46,21 +46,21 @@ configure(allprojects) { project ->
ext.groovyVersion = "2.4.15"
ext.hsqldbVersion = "2.4.0"
ext.jackson2Version = "2.9.5"
ext.jettyVersion = "9.4.9.v20180320"
ext.jettyVersion = "9.4.10.v20180503"
ext.junitJupiterVersion = "5.0.3"
ext.junitPlatformVersion = "1.0.3"
ext.junitVintageVersion = "4.12.3"
ext.kotlinVersion = "1.2.31"
ext.kotlinVersion = "1.2.41"
ext.log4jVersion = "2.11.0"
ext.nettyVersion = "4.1.22.Final"
ext.reactorVersion = "Bismuth-SR8"
ext.nettyVersion = "4.1.24.Final"
ext.reactorVersion = "Bismuth-SR9"
ext.rxjavaVersion = "1.3.8"
ext.rxjavaAdapterVersion = "1.2.1"
ext.rxjava2Version = "2.1.12"
ext.slf4jVersion = "1.7.25" // spring-jcl + consistent 3rd party deps
ext.rxjava2Version = "2.1.13"
ext.slf4jVersion = "1.7.25" // spring-jcl + consistent 3rd party deps
ext.tiles3Version = "3.0.8"
ext.tomcatVersion = "8.5.29"
ext.undertowVersion = "1.4.23.Final"
ext.tomcatVersion = "8.5.31"
ext.undertowVersion = "1.4.25.Final"
ext.gradleScriptDir = "${rootProject.projectDir}/gradle"
@@ -154,7 +154,6 @@ configure(allprojects) { project ->
exclude module:'mockito-core'
}
testCompile("org.hamcrest:hamcrest-all:1.3")
testCompile("org.xmlunit:xmlunit-matchers:2.3.0")
testRuntime("org.apache.logging.log4j:log4j-core:${log4jVersion}")
testRuntime("org.apache.logging.log4j:log4j-slf4j-impl:${log4jVersion}")
testRuntime("org.apache.logging.log4j:log4j-jul:${log4jVersion}")
+1 -1
View File
@@ -1 +1 @@
version=5.0.5.BUILD-SNAPSHOT
version=5.0.6.RELEASE
+6 -5
View File
@@ -49,12 +49,9 @@ task api(type: Javadoc) {
}
}
// Need https://github.com/Kotlin/dokka/issues/184 to be fixed to avoid "Can't find node by signature" log spam
dokka {
dependsOn {
subprojects.collect {
it.tasks.getByName("jar")
}
tasks.getByName("api")
}
doFirst {
classpath = subprojects.collect { project -> project.jar.outputs.files.getFiles() }.flatten()
@@ -69,6 +66,10 @@ dokka {
def kotlinDirs = project.sourceSets.main.kotlin.srcDirs.collect()
kotlinDirs -= project.sourceSets.main.java.srcDirs
})
externalDocumentationLink {
url = new URL("https://docs.spring.io/spring-framework/docs/$version/javadoc-api/")
packageListUrl = new File(buildDir, "api/package-list").toURI().toURL()
}
externalDocumentationLink {
url = new URL("http://projectreactor.io/docs/core/release/api/")
}
@@ -122,7 +123,7 @@ task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) {
into "javadoc-api"
}
from (asciidoctor) {
from (asciidoctor.outputDir) {
into "spring-framework-reference"
}
-19
View File
@@ -1,22 +1,3 @@
/*
pluginManagement {
repositories {
maven {
url "https://dl.bintray.com/kotlin/kotlin-eap-1.1"
}
gradlePluginPortal()
}
}
*/
// Workaround for https://github.com/Kotlin/dokka/issues/146
pluginManagement {
repositories {
jcenter()
gradlePluginPortal()
}
}
include "spring-aop"
include "spring-aspects"
include "spring-beans"
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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,10 +289,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
}
@Override
public boolean matches(Method method, @Nullable Class<?> targetClass, boolean beanHasIntroductions) {
public boolean matches(Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
obtainPointcutExpression();
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
ShadowMatch shadowMatch = getShadowMatch(targetMethod, method);
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Special handling for this, target, @this, @target, @annotation
// in Spring - we can optimize since we know we have exactly this class,
@@ -305,7 +304,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
}
else {
// the maybe case
if (beanHasIntroductions) {
if (hasIntroductions) {
return true;
}
// A match test returned maybe - if there are any subtype sensitive variables
@@ -331,8 +330,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
@Override
public boolean matches(Method method, @Nullable Class<?> targetClass, Object... args) {
obtainPointcutExpression();
ShadowMatch shadowMatch = getShadowMatch(AopUtils.getMostSpecificMethod(method, targetClass), method);
ShadowMatch originalShadowMatch = getShadowMatch(method, method);
ShadowMatch shadowMatch = getTargetShadowMatch(method, targetClass);
// Bind Spring AOP proxy to AspectJ "this" and Spring AOP target to AspectJ target,
// consistent with return of MethodInvocationProceedingJoinPoint
@@ -367,7 +365,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
* <p>See SPR-2979 for the original bug.
*/
if (pmi != null && thisObject != null) { // there is a current invocation
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(originalShadowMatch);
RuntimeTestWalker originalMethodResidueTest = getRuntimeTestWalker(getShadowMatch(method, method));
if (!originalMethodResidueTest.testThisInstanceOfResidue(thisObject.getClass())) {
return false;
}
@@ -427,6 +425,19 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
invocation.setUserAttribute(resolveExpression(), jpm);
}
private ShadowMatch getTargetShadowMatch(Method method, @Nullable Class<?> targetClass) {
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
if (targetClass != null && targetMethod.getDeclaringClass().isInterface()) {
Set<Class<?>> ifcs = ClassUtils.getAllInterfacesForClassAsSet(targetClass);
if (ifcs.size() > 1) {
Class<?> compositeInterface = ClassUtils.createCompositeInterface(
ClassUtils.toClassArray(ifcs), targetClass.getClassLoader());
targetMethod = ClassUtils.getMostSpecificMethod(targetMethod, compositeInterface);
}
}
return getShadowMatch(targetMethod, method);
}
private ShadowMatch getShadowMatch(Method targetMethod, Method originalMethod) {
// Avoid lock contention for known Methods through concurrent access...
ShadowMatch shadowMatch = this.shadowMatchCache.get(targetMethod);
@@ -434,9 +445,9 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
synchronized (this.shadowMatchCache) {
// Not found - now check again with full lock...
PointcutExpression fallbackExpression = null;
Method methodToMatch = targetMethod;
shadowMatch = this.shadowMatchCache.get(targetMethod);
if (shadowMatch == null) {
Method methodToMatch = targetMethod;
try {
try {
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
@@ -459,7 +470,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
try {
shadowMatch = obtainPointcutExpression().matchesMethodExecution(methodToMatch);
}
catch (ReflectionWorldException ex3) {
catch (ReflectionWorldException ex) {
// Could neither introspect the target class nor the proxy class ->
// let's try the original method's declaring class before we give up...
try {
@@ -468,7 +479,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
shadowMatch = fallbackExpression.matchesMethodExecution(methodToMatch);
}
}
catch (ReflectionWorldException ex4) {
catch (ReflectionWorldException ex2) {
fallbackExpression = null;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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,17 +33,15 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Implementation of AspectJ ProceedingJoinPoint interface
* wrapping an AOP Alliance MethodInvocation.
* An implementation of the AspectJ {@link ProceedingJoinPoint} interface
* wrapping an AOP Alliance {@link org.aopalliance.intercept.MethodInvocation}.
*
* <p><b>Note</b>: the {@code getThis()} method returns the current Spring AOP proxy.
* <p><b>Note</b>: The {@code getThis()} method returns the current Spring AOP proxy.
* The {@code getTarget()} method returns the current Spring AOP target (which may be
* {@code null} if there is no target), and is a plain POJO without any advice.
* <b>If you want to call the object and have the advice take effect, use
* {@code getThis()}.</b> A common example is casting the object to an
* introduced interface in the implementation of an introduction.
*
* <p>Of course there is no such distinction between target and proxy in AspectJ.
* {@code null} if there is no target instance) as a plain POJO without any advice.
* <b>If you want to call the object and have the advice take effect, use {@code getThis()}.</b>
* A common example is casting the object to an introduced interface in the implementation of
* an introduction. There is no such distinction between target and proxy in AspectJ itself.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -58,7 +56,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
private final ProxyMethodInvocation methodInvocation;
@Nullable
private Object[] defensiveCopyOfArgs;
private Object[] args;
/** Lazily initialized signature object */
@Nullable
@@ -79,6 +77,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
this.methodInvocation = methodInvocation;
}
@Override
public void set$AroundClosure(AroundClosure aroundClosure) {
throw new UnsupportedOperationException();
@@ -120,12 +119,10 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
@Override
public Object[] getArgs() {
if (this.defensiveCopyOfArgs == null) {
Object[] argsSource = this.methodInvocation.getArguments();
this.defensiveCopyOfArgs = new Object[argsSource.length];
System.arraycopy(argsSource, 0, this.defensiveCopyOfArgs, 0, argsSource.length);
if (this.args == null) {
this.args = this.methodInvocation.getArguments().clone();
}
return this.defensiveCopyOfArgs;
return this.args;
}
@Override
@@ -133,7 +130,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
if (this.signature == null) {
this.signature = new MethodSignatureImpl();
}
return signature;
return this.signature;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -205,9 +205,8 @@ class CglibAopProxy implements AopProxy, Serializable {
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
@@ -48,7 +48,7 @@ public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Seriali
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
@@ -192,8 +192,7 @@ public abstract class AopUtils {
* @see org.springframework.util.ClassUtils#getMostSpecificMethod
*/
public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
Class<?> specificTargetClass = (targetClass != null && !Proxy.isProxyClass(targetClass) ?
ClassUtils.getUserClass(targetClass) : null);
Class<?> specificTargetClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, specificTargetClass);
// If we are dealing with method with generic parameters, find the original method.
return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
@@ -247,8 +246,8 @@ public abstract class AopUtils {
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -90,8 +90,8 @@ public abstract class MethodMatchers {
*/
public static boolean matches(MethodMatcher mm, Method method, @Nullable Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(mm, "MethodMatcher must not be null");
return ((mm instanceof IntroductionAwareMethodMatcher &&
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions)) ||
return (mm instanceof IntroductionAwareMethodMatcher ?
((IntroductionAwareMethodMatcher) mm).matches(method, targetClass, hasIntroductions) :
mm.matches(method, targetClass));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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.aop.support.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.StaticMethodMatcher;
@@ -71,6 +72,10 @@ public class AnnotationMethodMatcher extends StaticMethodMatcher {
if (matchesMethod(method)) {
return true;
}
// Proxy classes never have annotations on their redeclared methods.
if (targetClass != null && Proxy.isProxyClass(targetClass)) {
return false;
}
// The method may be on an interface, so let's check on the target class as well.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
return (specificMethod != method && matchesMethod(specificMethod));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,6 @@
package org.springframework.aop.aspectj;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Test;
@@ -30,13 +27,7 @@ import org.junit.Test;
* @author Adrian Colyer
* @author Chris Beams
*/
public class AspectJAdviceParameterNameDiscoverAnnotationTests
extends AspectJAdviceParameterNameDiscovererTests {
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
public class AspectJAdviceParameterNameDiscoverAnnotationTests extends AspectJAdviceParameterNameDiscovererTests {
@Test
public void testAnnotationBinding() {
@@ -45,4 +36,9 @@ public class AspectJAdviceParameterNameDiscoverAnnotationTests
new String[] {"thisJoinPoint","ann"});
}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
@interface MyAnnotation {}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
@@ -34,47 +35,6 @@ import static org.junit.Assert.*;
*/
public class AspectJAdviceParameterNameDiscovererTests {
// methods to discover parameter names for
public void noArgs() {
}
public void tjp(JoinPoint jp) {
}
public void tjpsp(JoinPoint.StaticPart tjpsp) {
}
public void twoJoinPoints(JoinPoint jp1, JoinPoint jp2) {
}
public void oneThrowable(Exception ex) {
}
public void jpAndOneThrowable(JoinPoint jp, Exception ex) {
}
public void jpAndTwoThrowables(JoinPoint jp, Exception ex, Error err) {
}
public void oneObject(Object x) {
}
public void twoObjects(Object x, Object y) {
}
public void onePrimitive(int x) {
}
public void oneObjectOnePrimitive(Object x, int y) {
}
public void oneThrowableOnePrimitive(Throwable x, int y) {
}
public void theBigOne(JoinPoint jp, Throwable x, int y, Object foo) {
}
@Test
public void testNoArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
@@ -221,22 +181,26 @@ public class AspectJAdviceParameterNameDiscovererTests {
@Test
public void testThisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)", new String[] {"obj", "count"});
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"});
}
@Test
public void testTargetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)", new String[] {"obj", "count"});
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"});
}
@Test
public void testThrowingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex", new String[] {"ex", "count"});
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"});
}
@Test
public void testAllTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex", new String[] {"thisJoinPoint", "ex", "x", "foo"});
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"});
}
@Test
@@ -253,8 +217,8 @@ public class AspectJAdviceParameterNameDiscovererTests {
protected Method getMethod(String name) {
// assumes no overloading of test methods...
Method[] candidates = this.getClass().getMethods();
// Assumes no overloading of test methods...
Method[] candidates = getClass().getMethods();
for (Method candidate : candidates) {
if (candidate.getName().equals(name)) {
return candidate;
@@ -268,8 +232,8 @@ public class AspectJAdviceParameterNameDiscovererTests {
assertParameterNames(method, pointcut, null, null, parameterNames);
}
protected void assertParameterNames(Method method, String pointcut, String returning, String throwing,
String[] parameterNames) {
protected void assertParameterNames(
Method method, String pointcut, String returning, String throwing, String[] parameterNames) {
assertEquals("bad test specification, must have same number of parameter names as method arguments",
method.getParameterCount(), parameterNames.length);
@@ -300,8 +264,8 @@ public class AspectJAdviceParameterNameDiscovererTests {
assertException(method, pointcut, null, null, exceptionType, message);
}
protected void assertException(Method method, String pointcut, String returning, String throwing,
Class<?> exceptionType, String message) {
protected void assertException(
Method method, String pointcut, String returning, String throwing, Class<?> exceptionType, String message) {
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true);
@@ -333,4 +297,46 @@ public class AspectJAdviceParameterNameDiscovererTests {
return sb.toString();
}
// Methods to discover parameter names for
public void noArgs() {
}
public void tjp(JoinPoint jp) {
}
public void tjpsp(JoinPoint.StaticPart tjpsp) {
}
public void twoJoinPoints(JoinPoint jp1, JoinPoint jp2) {
}
public void oneThrowable(Exception ex) {
}
public void jpAndOneThrowable(JoinPoint jp, Exception ex) {
}
public void jpAndTwoThrowables(JoinPoint jp, Exception ex, Error err) {
}
public void oneObject(Object x) {
}
public void twoObjects(Object x, Object y) {
}
public void onePrimitive(int x) {
}
public void oneObjectOnePrimitive(Object x, int y) {
}
public void oneThrowableOnePrimitive(Throwable x, int y) {
}
public void theBigOne(JoinPoint jp, Throwable x, int y, Object foo) {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -218,38 +218,27 @@ public class AspectJExpressionPointcutTests {
@Test
public void testSimpleAdvice() {
String expression = "execution(int org.springframework.tests.sample.beans.TestBean.getAge())";
CallCountingInterceptor interceptor = new CallCountingInterceptor();
TestBean testBean = getAdvisedProxy(expression, interceptor);
assertEquals("Calls should be 0", 0, interceptor.getCount());
testBean.getAge();
assertEquals("Calls should be 1", 1, interceptor.getCount());
testBean.setAge(90);
assertEquals("Calls should still be 1", 1, interceptor.getCount());
}
@Test
public void testDynamicMatchingProxy() {
String expression = "execution(void org.springframework.tests.sample.beans.TestBean.setSomeNumber(Number)) && args(Double)";
CallCountingInterceptor interceptor = new CallCountingInterceptor();
TestBean testBean = getAdvisedProxy(expression, interceptor);
assertEquals("Calls should be 0", 0, interceptor.getCount());
testBean.setSomeNumber(new Double(30));
assertEquals("Calls should be 1", 1, interceptor.getCount());
testBean.setSomeNumber(new Integer(90));
assertEquals("Calls should be 1", 1, interceptor.getCount());
}
@@ -291,7 +280,7 @@ public class AspectJExpressionPointcutTests {
}
@Test
public void testWithUnsupportedPointcutPrimitive() throws Exception {
public void testWithUnsupportedPointcutPrimitive() {
String expression = "call(int org.springframework.tests.sample.beans.TestBean.getAge())";
try {
@@ -301,7 +290,6 @@ public class AspectJExpressionPointcutTests {
catch (UnsupportedPointcutPrimitiveException ex) {
assertEquals("Should not support call pointcut", PointcutPrimitive.CALL, ex.getUnsupportedPrimitive());
}
}
@Test
@@ -332,6 +320,7 @@ public class AspectJExpressionPointcutTests {
// Empty
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -77,6 +77,7 @@ public class BeanNamePointcutMatchingTests {
assertMisMatch("someName", "!bean(someName) || bean(someOtherName)");
}
private void assertMatch(String beanName, String pcExpression) {
assertTrue("Unexpected mismatch for bean \"" + beanName + "\" for pcExpression \"" + pcExpression + "\"",
matches(beanName, pcExpression));
@@ -98,4 +99,5 @@ public class BeanNamePointcutMatchingTests {
pointcut.setExpression(pcExpression);
return pointcut.matches(TestBean.class);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,25 +31,24 @@ import org.springframework.tests.sample.beans.TestBean;
import static org.junit.Assert.*;
/**
* Java5-specific {@link AspectJExpressionPointcutTests}.
* Java 5 specific {@link AspectJExpressionPointcutTests}.
*
* @author Rod Johnson
* @author Chris Beams
*/
public class TigerAspectJExpressionPointcutTests {
// TODO factor into static in AspectJExpressionPointcut
private Method getAge;
private Map<String,Method> methodsOnHasGeneric = new HashMap<>();
private final Map<String, Method> methodsOnHasGeneric = new HashMap<>();
@Before
public void setUp() throws NoSuchMethodException {
public void setup() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
// Assumes no overloading
for (Method m : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(m.getName(), m);
for (Method method : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(method.getName(), method);
}
}
@@ -87,11 +86,6 @@ public class TigerAspectJExpressionPointcutTests {
AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut();
jdbcVarArgs.setExpression(expression);
// TODO: the expression above no longer matches Object[]
// assertFalse(jdbcVarArgs.matches(
// JdbcTemplate.class.getMethod("queryForInt", String.class, Object[].class),
// JdbcTemplate.class));
assertTrue(jdbcVarArgs.matches(
MyTemplate.class.getMethod("queryForInt", String.class, Object[].class),
MyTemplate.class));
@@ -167,8 +161,10 @@ public class TigerAspectJExpressionPointcutTests {
anySpringMethodAnnotation.setExpression(expression);
assertFalse(anySpringMethodAnnotation.matches(getAge, TestBean.class));
assertFalse(anySpringMethodAnnotation.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class));
assertFalse(anySpringMethodAnnotation.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class));
assertFalse(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertTrue(anySpringMethodAnnotation.matches(BeanA.class.getMethod("getAge"), BeanA.class));
assertFalse(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
@@ -181,8 +177,10 @@ public class TigerAspectJExpressionPointcutTests {
takesSpringAnnotatedArgument2.setExpression(expression);
assertFalse(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
@@ -209,8 +207,10 @@ public class TigerAspectJExpressionPointcutTests {
takesSpringAnnotatedArgument2.setExpression(expression);
assertFalse(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
@@ -260,12 +260,14 @@ public class TigerAspectJExpressionPointcutTests {
@EmptySpringAnnotation
public static class SpringAnnotated {
public void foo() {
}
}
static class BeanA {
private String name;
private int age;
@@ -283,6 +285,7 @@ public class TigerAspectJExpressionPointcutTests {
@Tx
static class BeanB {
private String name;
public void setName(String name) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,6 @@ import test.aop.PerTargetAspect;
import test.aop.TwoAdviceAspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.aop.framework.ProxyFactory;
@@ -82,22 +81,24 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Test
public void testRejectsPerCflowAspect() {
try {
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(),"someBean"));
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(), "someBean"));
fail("Cannot accept cflow");
}
catch (AopConfigException ex) {
assertTrue(ex.getMessage().indexOf("PERCFLOW") != -1);
assertTrue(ex.getMessage().contains("PERCFLOW"));
}
}
@Test
public void testRejectsPerCflowBelowAspect() {
try {
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(),"someBean"));
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(), "someBean"));
fail("Cannot accept cflowbelow");
}
catch (AopConfigException ex) {
assertTrue(ex.getMessage().indexOf("PERCFLOWBELOW") != -1);
assertTrue(ex.getMessage().contains("PERCFLOWBELOW"));
}
}
@@ -112,7 +113,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
assertEquals("Around advice must NOT apply", realAge, itb.getAge());
Advised advised = (Advised) itb;
SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor sia =
(ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[3];
LazySingletonAspectInstanceFactoryDecorator maaif =
@@ -199,7 +201,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
Advised advised = (Advised) itb;
// Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors
assertEquals(4, advised.getAdvisors().length);
SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor sia =
(ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2];
LazySingletonAspectInstanceFactoryDecorator maaif =
@@ -227,16 +230,15 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
int realAge = 65;
target.setAge(realAge);
PerTypeWithinAspectInstanceFactory aif = new PerTypeWithinAspectInstanceFactory();
TestBean itb = (TestBean) createProxy(target,
getFixture().getAdvisors(aif),
TestBean.class);
TestBean itb = (TestBean) createProxy(target, getFixture().getAdvisors(aif), TestBean.class);
assertEquals("No method calls", 0, aif.getInstantiationCount());
assertEquals("Around advice must now apply", 0, itb.getAge());
Advised advised = (Advised) itb;
// Will be ExposeInvocationInterceptor, synthetic instantiation advisor, 2 method advisors
assertEquals(4, advised.getAdvisors().length);
SyntheticInstantiationAdvisor sia = (SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor sia =
(ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor) advised.getAdvisors()[1];
assertTrue(sia.getPointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
InstantiationModelAwarePointcutAdvisorImpl imapa = (InstantiationModelAwarePointcutAdvisorImpl) advised.getAdvisors()[2];
LazySingletonAspectInstanceFactoryDecorator maaif =
@@ -257,9 +259,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
assertEquals("Around advice must still apply", 1, itb.getAge());
assertEquals("Around advice must still apply", 2, itb.getAge());
TestBean itb2 = (TestBean) createProxy(target,
getFixture().getAdvisors(aif),
TestBean.class);
TestBean itb2 = (TestBean) createProxy(target, getFixture().getAdvisors(aif), TestBean.class);
assertEquals(1, aif.getInstantiationCount());
assertEquals("Around advice be independent for second instance", 0, itb2.getAge());
assertEquals(2, aif.getInstantiationCount());
@@ -284,7 +284,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testNamedPointcutFromAspectLibraryWithBinding() {
TestBean target = new TestBean();
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new NamedPointcutAspectFromLibraryWithBinding(),"someBean")),
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(
new NamedPointcutAspectFromLibraryWithBinding(), "someBean")),
ITestBean.class);
itb.setAge(10);
assertEquals("Around advice must apply", 20, itb.getAge());
@@ -296,7 +297,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
int realAge = 65;
target.setAge(realAge);
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance,"someBean")),
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, "someBean")),
ITestBean.class);
assertEquals("Around advice must apply", -1, itb.getAge());
assertEquals(realAge, target.getAge());
@@ -306,7 +307,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testBindingWithSingleArg() {
TestBean target = new TestBean();
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(),"someBean")),
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new BindingAspectWithSingleArg(), "someBean")),
ITestBean.class);
itb.setAge(10);
assertEquals("Around advice must apply", 20, itb.getAge());
@@ -317,7 +319,8 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testBindingWithMultipleArgsDifferentlyOrdered() {
ManyValuedArgs target = new ManyValuedArgs();
ManyValuedArgs mva = (ManyValuedArgs) createProxy(target,
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(),"someBean")),
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new ManyValuedArgs(), "someBean")),
ManyValuedArgs.class);
String a = "a";
@@ -338,7 +341,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
assertFalse(notLockableTarget instanceof Lockable);
NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget,
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
NotLockable.class);
assertTrue(notLockable1 instanceof Lockable);
Lockable lockable = (Lockable) notLockable1;
@@ -349,7 +352,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
NotLockable notLockable2Target = new NotLockable();
NotLockable notLockable2 = (NotLockable) createProxy(notLockable2Target,
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")),
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
NotLockable.class);
assertTrue(notLockable2 instanceof Lockable);
Lockable lockable2 = (Lockable) notLockable2;
@@ -368,11 +371,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Test
public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() {
assertTrue(AopUtils.findAdvisorsThatCanApply(
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(
new MakeLockable(),"someBean")),
CannotBeUnlocked.class).isEmpty());
assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size());
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
CannotBeUnlocked.class).isEmpty());
assertEquals(2, AopUtils.findAdvisorsThatCanApply(getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")), NotLockable.class).size());
}
@Test
@@ -408,42 +411,34 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
List.class
),
CannotBeUnlocked.class);
List.class);
assertFalse("Type pattern must have excluded mixin", proxy instanceof Lockable);
}
/* prereq AspectJ 1.6.7
@Test
public void testIntroductionBasedOnAnnotationMatch_Spr5307() {
public void testIntroductionBasedOnAnnotationMatch_SPR5307() {
AnnotatedTarget target = new AnnotatedTargetImpl();
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(),"someBean"));
Object proxy = createProxy(target,
advisors,
AnnotatedTarget.class);
new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(), "someBean"));
Object proxy = createProxy(target, advisors, AnnotatedTarget.class);
System.out.println(advisors.get(1));
assertTrue(proxy instanceof Lockable);
Lockable lockable = (Lockable)proxy;
lockable.locked();
}
*/
// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
@Test
@Ignore
public void testIntroductionWithArgumentBinding() {
TestBean target = new TestBean();
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(),"someBean"));
new SingletonMetadataAwareAspectInstanceFactory(new MakeITestBeanModifiable(), "someBean"));
advisors.addAll(getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(),"someBean")));
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")));
Modifiable modifiable = (Modifiable) createProxy(target,
advisors,
ITestBean.class);
Modifiable modifiable = (Modifiable) createProxy(target, advisors, ITestBean.class);
assertThat(modifiable, instanceOf(Modifiable.class));
Lockable lockable = (Lockable) modifiable;
assertFalse(lockable.locked());
@@ -477,11 +472,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testAspectMethodThrowsExceptionLegalOnSignature() {
TestBean target = new TestBean();
UnsupportedOperationException expectedException = new UnsupportedOperationException();
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean"));
assertEquals("One advice method was found", 1, advisors.size());
ITestBean itb = (ITestBean) createProxy(target,
advisors,
ITestBean.class);
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
try {
itb.getAge();
fail();
@@ -497,11 +492,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testAspectMethodThrowsExceptionIllegalOnSignature() {
TestBean target = new TestBean();
RemoteException expectedException = new RemoteException();
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException),"someBean"));
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean"));
assertEquals("One advice method was found", 1, advisors.size());
ITestBean itb = (ITestBean) createProxy(target,
advisors,
ITestBean.class);
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
try {
itb.getAge();
fail();
@@ -522,10 +517,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
// Required everywhere we use AspectJ proxies
pf.addAdvice(ExposeInvocationInterceptor.INSTANCE);
for (Object a : advisors) {
pf.addAdvisor((Advisor) a);
}
pf.addAdvisors(advisors);
pf.setExposeProxy(true);
return pf.getProxy();
@@ -534,13 +526,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Test
public void testTwoAdvicesOnOneAspect() {
TestBean target = new TestBean();
TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect,"someBean"));
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(twoAdviceAspect, "someBean"));
assertEquals("Two advice methods found", 2, advisors.size());
ITestBean itb = (ITestBean) createProxy(target,
advisors,
ITestBean.class);
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
itb.setName("");
assertEquals(0, itb.getAge());
int newAge = 32;
@@ -551,16 +541,15 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Test
public void testAfterAdviceTypes() throws Exception {
Echo target = new Echo();
ExceptionHandling afterReturningAspect = new ExceptionHandling();
List<Advisor> advisors = getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect,"someBean"));
Echo echo = (Echo) createProxy(target,
advisors,
Echo.class);
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect, "someBean"));
Echo echo = (Echo) createProxy(target, advisors, Echo.class);
assertEquals(0, afterReturningAspect.successCount);
assertEquals("", echo.echo(""));
assertEquals(1, afterReturningAspect.successCount);
assertEquals(0, afterReturningAspect.failureCount);
try {
echo.echo(new FileNotFoundException());
fail();
@@ -580,9 +569,9 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testFailureWithoutExplicitDeclarePrecedence() {
TestBean target = new TestBean();
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
new NoDeclarePrecedenceShouldFail(), "someBean");
new NoDeclarePrecedenceShouldFail(), "someBean");
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
itb.getAge();
}
@@ -590,21 +579,10 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
public void testDeclarePrecedenceNotSupported() {
TestBean target = new TestBean();
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
new DeclarePrecedenceShouldSucceed(), "someBean");
createProxy(target, getFixture().getAdvisors(aspectInstanceFactory),
ITestBean.class);
new DeclarePrecedenceShouldSucceed(), "someBean");
createProxy(target, getFixture().getAdvisors(aspectInstanceFactory), ITestBean.class);
}
/** Not supported in 2.0!
public void testExplicitDeclarePrecedencePreventsFailure() {
TestBean target = new TestBean();
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(new DeclarePrecedenceShouldSucceed(), "someBean")),
ITestBean.class);
assertEquals(666, itb.getAge());
}
*/
@Aspect("percflow(execution(* *(..)))")
public static class PerCflowAspect {
@@ -723,6 +701,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class NamedPointcutAspectWithoutFQN {
@Pointcut("execution(* getAge())")
public void getAge() {
}
@@ -779,7 +758,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Around(value="setAge(age)",argNames="age")
// @ArgNames({"age"}) // AMC needs more work here? ignoring pjp arg... ok??
// argNames should be suported in Around as it is in Pointcut
// argNames should be suported in Around as it is in Pointcut
public void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable {
pjp.proceed(new Object[] {age*2});
}
@@ -788,12 +767,12 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class ManyValuedArgs {
public String mungeArgs(String a, int b, int c, String d, StringBuffer e) {
return a + b + c + d + e;
}
@Around(value="execution(String mungeArgs(..)) && args(a, b, c, d, e)",
argNames="b,c,d,e,a")
@Around(value="execution(String mungeArgs(..)) && args(a, b, c, d, e)", argNames="b,c,d,e,a")
public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable {
assertEquals(a + b+ c+ d+ e, pjp.proceed());
return a + b + c + d + e;
@@ -803,6 +782,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class ExceptionAspect {
private final Exception ex;
public ExceptionAspect(Exception ex) {
@@ -829,8 +809,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class ExceptionHandling {
public int successCount;
public int failureCount;
public int afterCount;
@AfterReturning("execution(* echo(*))")
@@ -902,10 +885,12 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
abstract class AbstractMakeModifiable {
public interface MutableModifable extends Modifiable {
void markDirty();
}
public static class ModifiableImpl implements MutableModifable {
private boolean modified;
@Override
@@ -924,10 +909,9 @@ abstract class AbstractMakeModifiable {
}
}
@Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)",
argNames="modifiable,newValue")
public void recordModificationIfSetterArgumentDiffersFromOldValue(JoinPoint jp,
MutableModifable mixin, Object newValue) {
@Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)", argNames="modifiable,newValue")
public void recordModificationIfSetterArgumentDiffersFromOldValue(
JoinPoint jp, MutableModifable mixin, Object newValue) {
/*
* We use the mixin to check and, if necessary, change,
@@ -992,6 +976,7 @@ class MakeITestBeanModifiable extends AbstractMakeModifiable {
}
/**
* Adds a declare parents pointcut - spr5307
* @author Andy Clement
@@ -1001,8 +986,7 @@ class MakeITestBeanModifiable extends AbstractMakeModifiable {
class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable {
@DeclareParents(value = "(@org.springframework.aop.aspectj.annotation.Measured *)",
// @DeclareParents(value = "(@Measured *)", // this would be a nice alternative...
defaultImpl=DefaultLockable.class)
defaultImpl = DefaultLockable.class)
public static Lockable mixin;
}
@@ -1014,14 +998,11 @@ class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable {
@Aspect
class MakeLockable {
@DeclareParents(value = "org.springframework..*",
defaultImpl=DefaultLockable.class)
@DeclareParents(value = "org.springframework..*", defaultImpl = DefaultLockable.class)
public static Lockable mixin;
@Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin")
public void checkNotLocked(
Lockable mixin) // Bind to arg
{
public void checkNotLocked( Lockable mixin) {
// Can also obtain the mixin (this) this way
//Lockable mixin = (Lockable) jp.getThis();
if (mixin.locked()) {
@@ -1069,6 +1050,7 @@ interface Modifiable {
}
/**
* Used as a target.
* @author Andy Clement
@@ -1076,11 +1058,12 @@ interface Modifiable {
interface AnnotatedTarget {
}
@Measured
class AnnotatedTargetImpl implements AnnotatedTarget {
}
@Retention(RetentionPolicy.RUNTIME)
@interface Measured {}
@@ -1104,9 +1087,7 @@ class PerThisAspect {
public int count;
/**
* Just to check that this doesn't cause problems with introduction processing
*/
// Just to check that this doesn't cause problems with introduction processing
private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
@Around("execution(int *.getAge())")
@@ -70,13 +70,13 @@ public class HotSwappableTargetSourceTests {
@Test
public void testBasicFunctionality() {
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
assertEquals(INITIAL_COUNT, proxied.getCount() );
assertEquals(INITIAL_COUNT, proxied.getCount());
proxied.doWork();
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
assertEquals(INITIAL_COUNT + 1, proxied.getCount());
proxied = (SideEffectBean) beanFactory.getBean("swappable");
proxied.doWork();
assertEquals(INITIAL_COUNT + 2, proxied.getCount() );
assertEquals(INITIAL_COUNT + 2, proxied.getCount());
}
@Test
@@ -85,9 +85,9 @@ public class HotSwappableTargetSourceTests {
SideEffectBean target2 = (SideEffectBean) beanFactory.getBean("target2");
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
assertEquals(target1.getCount(), proxied.getCount() );
assertEquals(target1.getCount(), proxied.getCount());
proxied.doWork();
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
assertEquals(INITIAL_COUNT + 1, proxied.getCount());
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object old = swapper.swap(target2);
@@ -56,14 +56,14 @@ public class PrototypeTargetSourceTests {
@Test
public void testPrototypeAndSingletonBehaveDifferently() {
SideEffectBean singleton = (SideEffectBean) beanFactory.getBean("singleton");
assertEquals(INITIAL_COUNT, singleton.getCount() );
assertEquals(INITIAL_COUNT, singleton.getCount());
singleton.doWork();
assertEquals(INITIAL_COUNT + 1, singleton.getCount() );
assertEquals(INITIAL_COUNT + 1, singleton.getCount());
SideEffectBean prototype = (SideEffectBean) beanFactory.getBean("prototype");
assertEquals(INITIAL_COUNT, prototype.getCount() );
assertEquals(INITIAL_COUNT, prototype.getCount());
prototype.doWork();
assertEquals(INITIAL_COUNT, prototype.getCount() );
assertEquals(INITIAL_COUNT, prototype.getCount());
}
@@ -62,9 +62,9 @@ public class ThreadLocalTargetSourceTests {
@Test
public void testUseDifferentManagedInstancesInSameThread() {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
assertEquals(INITIAL_COUNT, apartment.getCount());
apartment.doWork();
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
assertEquals(INITIAL_COUNT + 1, apartment.getCount());
ITestBean test = (ITestBean) beanFactory.getBean("threadLocal2");
assertEquals("Rod", test.getName());
@@ -74,12 +74,12 @@ public class ThreadLocalTargetSourceTests {
@Test
public void testReuseInSameThread() {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
assertEquals(INITIAL_COUNT, apartment.getCount());
apartment.doWork();
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
assertEquals(INITIAL_COUNT + 1, apartment.getCount());
apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
assertEquals(INITIAL_COUNT + 1, apartment.getCount());
}
/**
@@ -106,20 +106,20 @@ public class ThreadLocalTargetSourceTests {
@Test
public void testNewThreadHasOwnInstance() throws InterruptedException {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
assertEquals(INITIAL_COUNT, apartment.getCount());
apartment.doWork();
apartment.doWork();
apartment.doWork();
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
assertEquals(INITIAL_COUNT + 3, apartment.getCount());
class Runner implements Runnable {
public SideEffectBean mine;
@Override
public void run() {
this.mine = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, mine.getCount() );
assertEquals(INITIAL_COUNT, mine.getCount());
mine.doWork();
assertEquals(INITIAL_COUNT + 1, mine.getCount() );
assertEquals(INITIAL_COUNT + 1, mine.getCount());
}
}
Runner r = new Runner();
@@ -130,11 +130,11 @@ public class ThreadLocalTargetSourceTests {
assertNotNull(r);
// Check it didn't affect the other thread's copy
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
assertEquals(INITIAL_COUNT + 3, apartment.getCount());
// When we use other thread's copy in this thread
// it should behave like ours
assertEquals(INITIAL_COUNT + 3, r.mine.getCount() );
assertEquals(INITIAL_COUNT + 3, r.mine.getCount());
// Bound to two threads
assertEquals(2, ((ThreadLocalTargetSourceStats) apartment).getObjectCount());
+2 -2
View File
@@ -80,8 +80,8 @@ compileTestJava {
dependencies {
aspects(project(":spring-orm"))
ajc("org.aspectj:aspectjtools:1.9.0") // for JDK 9+ build compatibility
rt("org.aspectj:aspectjrt:1.9.0") // for JDK 9+ build compatibility
ajc("org.aspectj:aspectjtools:1.9.1") // for JDK 9+ build compatibility
rt("org.aspectj:aspectjrt:1.9.1") // for JDK 9+ build compatibility
compile("org.aspectj:aspectjweaver:${aspectjVersion}") // for Maven POM exposure
optional(project(":spring-aop")) // for @Async support
optional(project(":spring-beans")) // for @Configurable support
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,8 +56,8 @@ import org.springframework.util.Assert;
* and obviates the need (<b>in part</b>) for a developer to code a method that
* simply checks that all required properties have actually been set.
*
* <p>Please note that an 'init' method may still need to implemented (and may
* still be desirable), because all that this class does is enforce that a
* <p>Please note that an 'init' method may still need to be implemented (and may
* still be desirable), because all that this class does is enforcing that a
* 'required' property has actually been configured with a value. It does
* <b>not</b> check anything else... In particular, it does not check that a
* configured value is not {@code null}.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,6 +64,8 @@ import org.springframework.lang.Nullable;
* Note that the value of "foo" in the first document is not simply replaced
* with the value in the second, but its nested values are merged.
*
* <p>Requires SnakeYAML 1.18 or higher, as of Spring Framework 5.0.6.
*
* @author Dave Syer
* @author Juergen Hoeller
* @since 4.1
@@ -30,6 +30,7 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.nodes.MappingNode;
@@ -45,6 +46,8 @@ import org.springframework.util.StringUtils;
/**
* Base class for YAML factories.
*
* <p>Requires SnakeYAML 1.18 or higher, as of Spring Framework 5.0.6.
*
* @author Dave Syer
* @author Juergen Hoeller
* @since 4.1
@@ -144,9 +147,14 @@ public abstract class YamlProcessor {
/**
* Create the {@link Yaml} instance to use.
* <p>The default implementation sets the "allowDuplicateKeys" flag to {@code false},
* enabling built-in duplicate key handling in SnakeYAML 1.18+.
* @see LoaderOptions#setAllowDuplicateKeys(boolean)
*/
protected Yaml createYaml() {
return new Yaml(new StrictMapAppenderConstructor());
LoaderOptions options = new LoaderOptions();
options.setAllowDuplicateKeys(false);
return new Yaml(options);
}
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
@@ -293,10 +301,14 @@ public abstract class YamlProcessor {
// Need a compound key
@SuppressWarnings("unchecked")
Collection<Object> collection = (Collection<Object>) value;
int count = 0;
for (Object object : collection) {
buildFlattenedMap(result,
Collections.singletonMap("[" + (count++) + "]", object), key);
if (collection.isEmpty()) {
result.put(key, "");
} else {
int count = 0;
for (Object object : collection) {
buildFlattenedMap(result, Collections.singletonMap(
"[" + (count++) + "]", object), key);
}
}
}
else {
@@ -389,7 +401,10 @@ public abstract class YamlProcessor {
/**
* A specialized {@link Constructor} that checks for duplicate keys.
* @deprecated as of Spring Framework 5.0.6 (not used anymore here),
* superseded by SnakeYAML's own duplicate key handling
*/
@Deprecated
protected static class StrictMapAppenderConstructor extends Constructor {
// Declared as public for use in subclasses
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,6 +74,8 @@ import org.springframework.lang.Nullable;
* servers[1]=foo.bar.com
* </pre>
*
* <p>Requires SnakeYAML 1.18 or higher, as of Spring Framework 5.0.6.
*
* @author Dave Syer
* @author Stephane Nicoll
* @author Juergen Hoeller
@@ -752,7 +752,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
factoryMethod, args, getBeanClassLoader());
uniqueCandidate = (commonType == null ? factoryMethod : null);
uniqueCandidate = (commonType == null && returnType == factoryMethod.getReturnType() ?
factoryMethod : null);
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
if (commonType == null) {
// Ambiguous return types found: return null to indicate "not determinable".
@@ -776,12 +777,15 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
}
if (commonType != null) {
// Clear return type found: all factory methods return same type.
mbd.factoryMethodReturnType = (uniqueCandidate != null ?
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
if (commonType == null) {
return null;
}
return commonType;
// Common return type found: all factory methods return same type. For a non-parameterized
// unique candidate, cache the full type declaration context of the target factory method.
cachedReturnType = (uniqueCandidate != null ?
ResolvableType.forMethodReturnType(uniqueCandidate) : ResolvableType.forClass(commonType));
mbd.factoryMethodReturnType = cachedReturnType;
return cachedReturnType.resolve();
}
/**
@@ -107,6 +107,11 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
beforeSingletonCreation(beanName);
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
@@ -114,6 +119,9 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,6 @@
package org.springframework.beans.factory.config;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import org.junit.After;
@@ -56,7 +53,7 @@ public class PropertyPlaceholderConfigurerTests {
@Before
public void setUp() {
public void setup() {
p1BeanDef = rootBeanDefinition(TestBean.class)
.addPropertyValue("name", "${" + P1 + "}")
.getBeanDefinition();
@@ -66,16 +63,14 @@ public class PropertyPlaceholderConfigurerTests {
ppcProperties = new Properties();
ppcProperties.setProperty(P1, P1_LOCAL_PROPS_VAL);
System.setProperty(P1, P1_SYSTEM_PROPS_VAL);
getModifiableSystemEnvironment().put(P1, P1_SYSTEM_ENV_VAL);
ppc = new PropertyPlaceholderConfigurer();
ppc.setProperties(ppcProperties);
}
@After
public void tearDown() {
public void cleanup() {
System.clearProperty(P1);
getModifiableSystemEnvironment().remove(P1);
}
@@ -84,8 +79,8 @@ public class PropertyPlaceholderConfigurerTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean",
genericBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
PropertyPlaceholderConfigurer pc = new PropertyPlaceholderConfigurer();
Resource resource = new ClassPathResource("PropertyPlaceholderConfigurerTests.properties", this.getClass());
@@ -95,7 +90,7 @@ public class PropertyPlaceholderConfigurerTests {
@Test
public void resolveFromSystemProperties() {
getModifiableSystemEnvironment().put("otherKey", "systemValue");
System.setProperty("otherKey", "systemValue");
p1BeanDef = rootBeanDefinition(TestBean.class)
.addPropertyValue("name", "${" + P1 + "}")
.addPropertyValue("sex", "${otherKey}")
@@ -105,12 +100,12 @@ public class PropertyPlaceholderConfigurerTests {
TestBean bean = bf.getBean(TestBean.class);
assertThat(bean.getName(), equalTo(P1_LOCAL_PROPS_VAL));
assertThat(bean.getSex(), equalTo("systemValue"));
getModifiableSystemEnvironment().remove("otherKey");
System.clearProperty("otherKey");
}
@Test
public void resolveFromLocalProperties() {
tearDown(); // eliminate entries from system props/environment
System.clearProperty(P1);
registerWithGeneratedName(p1BeanDef, bf);
ppc.postProcessBeanFactory(bf);
TestBean bean = bf.getBean(TestBean.class);
@@ -134,16 +129,6 @@ public class PropertyPlaceholderConfigurerTests {
assertThat(bean.getName(), equalTo(P1_SYSTEM_PROPS_VAL));
}
@Test
public void setSystemSystemPropertiesMode_toOverride_andResolveFromSystemEnvironment() {
registerWithGeneratedName(p1BeanDef, bf);
System.clearProperty(P1); // will now fall all the way back to system environment
ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE);
ppc.postProcessBeanFactory(bf);
TestBean bean = bf.getBean(TestBean.class);
assertThat(bean.getName(), equalTo(P1_SYSTEM_ENV_VAL));
}
@Test
public void setSystemSystemPropertiesMode_toOverride_andSetSearchSystemEnvironment_toFalse() {
registerWithGeneratedName(p1BeanDef, bf);
@@ -160,7 +145,7 @@ public class PropertyPlaceholderConfigurerTests {
* settings regarding resolving properties from the environment.
*/
@Test
public void twoPlacholderConfigurers_withConflictingSettings() {
public void twoPlaceholderConfigurers_withConflictingSettings() {
String P2 = "p2";
String P2_LOCAL_PROPS_VAL = "p2LocalPropsVal";
String P2_SYSTEM_PROPS_VAL = "p2SystemPropsVal";
@@ -178,7 +163,6 @@ public class PropertyPlaceholderConfigurerTests {
ppc.postProcessBeanFactory(bf);
System.setProperty(P2, P2_SYSTEM_PROPS_VAL);
getModifiableSystemEnvironment().put(P2, P2_SYSTEM_ENV_VAL);
Properties ppc2Properties = new Properties();
ppc2Properties.put(P2, P2_LOCAL_PROPS_VAL);
@@ -198,7 +182,6 @@ public class PropertyPlaceholderConfigurerTests {
assertThat(p2Bean.getCountry(), equalTo(P2_SYSTEM_PROPS_VAL));
System.clearProperty(P2);
getModifiableSystemEnvironment().remove(P2);
}
@Test
@@ -210,9 +193,9 @@ public class PropertyPlaceholderConfigurerTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean",
rootBeanDefinition(TestBean.class)
.addPropertyValue("name", "@<key1>")
.addPropertyValue("sex", "${key2}")
.getBeanDefinition());
.addPropertyValue("name", "@<key1>")
.addPropertyValue("sex", "${key2}")
.getBeanDefinition());
System.setProperty("key1", "systemKey1Value");
System.setProperty("key2", "systemKey2Value");
@@ -228,100 +211,41 @@ public class PropertyPlaceholderConfigurerTests {
public void nullValueIsPreserved() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setNullValue("customNull");
getModifiableSystemEnvironment().put("my.name", "customNull");
System.setProperty("my.name", "customNull");
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName(), nullValue());
getModifiableSystemEnvironment().remove("my.name");
System.clearProperty("my.name");
}
@Test
public void trimValuesIsOffByDefault() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
getModifiableSystemEnvironment().put("my.name", " myValue ");
System.setProperty("my.name", " myValue ");
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName(), equalTo(" myValue "));
getModifiableSystemEnvironment().remove("my.name");
System.clearProperty("my.name");
}
@Test
public void trimValuesIsApplied() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setTrimValues(true);
getModifiableSystemEnvironment().put("my.name", " myValue ");
System.setProperty("my.name", " myValue ");
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class)
.addPropertyValue("name", "${my.name}")
.getBeanDefinition());
ppc.postProcessBeanFactory(bf);
assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue"));
getModifiableSystemEnvironment().remove("my.name");
System.clearProperty("my.name");
}
@SuppressWarnings("unchecked")
private static Map<String, String> getModifiableSystemEnvironment() {
// for os x / linux
Class<?>[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class<?> cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
try {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
if (obj != null && obj.getClass().getName().equals("java.lang.ProcessEnvironment$StringEnvironment")) {
return (Map<String, String>) obj;
}
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
// for windows
Class<?> processEnvironmentClass;
try {
processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
try {
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Object obj = theCaseInsensitiveEnvironmentField.get(null);
return (Map<String, String>) obj;
}
catch (NoSuchFieldException ex) {
// do nothing
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
try {
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Object obj = theEnvironmentField.get(null);
return (Map<String, String>) obj;
}
catch (NoSuchFieldException ex) {
// do nothing
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
throw new IllegalStateException();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Test;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.ByteArrayResource;
@@ -41,27 +42,27 @@ public class YamlMapFactoryBeanTests {
@Test
public void testSetIgnoreResourceNotFound() throws Exception {
public void testSetIgnoreResourceNotFound() {
this.factory.setResolutionMethod(YamlMapFactoryBean.ResolutionMethod.OVERRIDE_AND_IGNORE);
this.factory.setResources(new FileSystemResource("non-exsitent-file.yml"));
assertEquals(0, this.factory.getObject().size());
}
@Test(expected = IllegalStateException.class)
public void testSetBarfOnResourceNotFound() throws Exception {
public void testSetBarfOnResourceNotFound() {
this.factory.setResources(new FileSystemResource("non-exsitent-file.yml"));
assertEquals(0, this.factory.getObject().size());
}
@Test
public void testGetObject() throws Exception {
public void testGetObject() {
this.factory.setResources(new ByteArrayResource("foo: bar".getBytes()));
assertEquals(1, this.factory.getObject().size());
}
@SuppressWarnings("unchecked")
@Test
public void testOverrideAndRemoveDefaults() throws Exception {
public void testOverrideAndRemoveDefaults() {
this.factory.setResources(new ByteArrayResource("foo:\n bar: spam".getBytes()),
new ByteArrayResource("foo:\n spam: bar".getBytes()));
@@ -70,7 +71,7 @@ public class YamlMapFactoryBeanTests {
}
@Test
public void testFirstFound() throws Exception {
public void testFirstFound() {
this.factory.setResolutionMethod(YamlProcessor.ResolutionMethod.FIRST_FOUND);
this.factory.setResources(new AbstractResource() {
@Override
@@ -87,7 +88,7 @@ public class YamlMapFactoryBeanTests {
}
@Test
public void testMapWithPeriodsInKey() throws Exception {
public void testMapWithPeriodsInKey() {
this.factory.setResources(new ByteArrayResource("foo:\n ? key1.key2\n : value".getBytes()));
Map<String, Object> map = this.factory.getObject();
@@ -102,7 +103,7 @@ public class YamlMapFactoryBeanTests {
}
@Test
public void testMapWithIntegerValue() throws Exception {
public void testMapWithIntegerValue() {
this.factory.setResources(new ByteArrayResource("foo:\n ? key1.key2\n : 3".getBytes()));
Map<String, Object> map = this.factory.getObject();
@@ -116,19 +117,10 @@ public class YamlMapFactoryBeanTests {
assertEquals(Integer.valueOf(3), sub.get("key1.key2"));
}
@Test
public void testDuplicateKey() throws Exception {
@Test(expected = DuplicateKeyException.class)
public void testDuplicateKey() {
this.factory.setResources(new ByteArrayResource("mymap:\n foo: bar\nmymap:\n bar: foo".getBytes()));
Map<String, Object> map = this.factory.getObject();
assertEquals(1, map.size());
assertTrue(map.containsKey("mymap"));
Object object = map.get("mymap");
assertTrue(object instanceof LinkedHashMap);
@SuppressWarnings("unchecked")
Map<String, Object> sub = (Map<String, Object>) object;
assertEquals(1, sub.size());
assertEquals("foo", sub.get("bar"));
this.factory.getObject().get("mymap");
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package org.springframework.beans.factory.config;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import org.junit.Rule;
import org.junit.Test;
@@ -29,7 +28,6 @@ import org.yaml.snakeyaml.scanner.ScannerException;
import org.springframework.core.io.ByteArrayResource;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.config.YamlProcessor.*;
/**
* Tests for {@link YamlProcessor}.
@@ -48,91 +46,65 @@ public class YamlProcessorTests {
@Test
public void arrayConvertedToIndexedBeanReference() {
this.processor.setResources(new ByteArrayResource("foo: bar\nbar: [1,2,3]".getBytes()));
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
assertEquals(4, properties.size());
assertEquals("bar", properties.get("foo"));
assertEquals("bar", properties.getProperty("foo"));
assertEquals(1, properties.get("bar[0]"));
assertEquals("1", properties.getProperty("bar[0]"));
assertEquals(2, properties.get("bar[1]"));
assertEquals("2", properties.getProperty("bar[1]"));
assertEquals(3, properties.get("bar[2]"));
assertEquals("3", properties.getProperty("bar[2]"));
}
this.processor.process((properties, map) -> {
assertEquals(4, properties.size());
assertEquals("bar", properties.get("foo"));
assertEquals("bar", properties.getProperty("foo"));
assertEquals(1, properties.get("bar[0]"));
assertEquals("1", properties.getProperty("bar[0]"));
assertEquals(2, properties.get("bar[1]"));
assertEquals("2", properties.getProperty("bar[1]"));
assertEquals(3, properties.get("bar[2]"));
assertEquals("3", properties.getProperty("bar[2]"));
});
}
@Test
public void testStringResource() throws Exception {
public void testStringResource() {
this.processor.setResources(new ByteArrayResource("foo # a document that is a literal".getBytes()));
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
assertEquals("foo", map.get("document"));
}
});
this.processor.process((properties, map) -> assertEquals("foo", map.get("document")));
}
@Test
public void testBadDocumentStart() throws Exception {
public void testBadDocumentStart() {
this.processor.setResources(new ByteArrayResource("foo # a document\nbar: baz".getBytes()));
this.exception.expect(ParserException.class);
this.exception.expectMessage("line 2, column 1");
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
}
});
this.processor.process((properties, map) -> {});
}
@Test
public void testBadResource() throws Exception {
public void testBadResource() {
this.processor.setResources(new ByteArrayResource("foo: bar\ncd\nspam:\n foo: baz".getBytes()));
this.exception.expect(ScannerException.class);
this.exception.expectMessage("line 3, column 1");
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
}
});
this.processor.process((properties, map) -> {});
}
@Test
public void mapConvertedToIndexedBeanReference() {
this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes()));
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
// System.err.println(properties);
assertEquals("bucket", properties.get("bar.spam"));
assertEquals(2, properties.size());
}
this.processor.process((properties, map) -> {
assertEquals("bucket", properties.get("bar.spam"));
assertEquals(2, properties.size());
});
}
@Test
public void integerKeyBehaves() {
this.processor.setResources(new ByteArrayResource("foo: bar\n1: bar".getBytes()));
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
assertEquals("bar", properties.get("[1]"));
assertEquals(2, properties.size());
}
this.processor.process((properties, map) -> {
assertEquals("bar", properties.get("[1]"));
assertEquals(2, properties.size());
});
}
@Test
public void integerDeepKeyBehaves() {
this.processor.setResources(new ByteArrayResource("foo:\n 1: bar".getBytes()));
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
assertEquals("bar", properties.get("foo[1]"));
assertEquals(1, properties.size());
}
this.processor.process((properties, map) -> {
assertEquals("bar", properties.get("foo[1]"));
assertEquals(1, properties.size());
});
}
@@ -140,18 +112,15 @@ public class YamlProcessorTests {
@SuppressWarnings("unchecked")
public void flattenedMapIsSameAsPropertiesButOrdered() {
this.processor.setResources(new ByteArrayResource("foo: bar\nbar:\n spam: bucket".getBytes()));
this.processor.process(new MatchCallback() {
@Override
public void process(Properties properties, Map<String, Object> map) {
assertEquals("bucket", properties.get("bar.spam"));
assertEquals(2, properties.size());
Map<String, Object> flattenedMap = processor.getFlattenedMap(map);
assertEquals("bucket", flattenedMap.get("bar.spam"));
assertEquals(2, flattenedMap.size());
assertTrue(flattenedMap instanceof LinkedHashMap);
Map<String, Object> bar = (Map<String, Object>) map.get("bar");
assertEquals("bucket", bar.get("spam"));
}
this.processor.process((properties, map) -> {
assertEquals("bucket", properties.get("bar.spam"));
assertEquals(2, properties.size());
Map<String, Object> flattenedMap = processor.getFlattenedMap(map);
assertEquals("bucket", flattenedMap.get("bar.spam"));
assertEquals(2, flattenedMap.size());
assertTrue(flattenedMap instanceof LinkedHashMap);
Map<String, Object> bar = (Map<String, Object>) map.get("bar");
assertEquals("bucket", bar.get("spam"));
});
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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,11 +19,11 @@ package org.springframework.beans.factory.config;
import java.util.Map;
import java.util.Properties;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;
import org.yaml.snakeyaml.scanner.ScannerException;
import org.springframework.core.io.ByteArrayResource;
@@ -46,17 +46,16 @@ public class YamlPropertiesFactoryBeanTests {
@Test
public void testLoadResource() throws Exception {
public void testLoadResource() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo: bar\nspam:\n foo: baz".getBytes()));
factory.setResources(new ByteArrayResource("foo: bar\nspam:\n foo: baz".getBytes()));
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo"), equalTo("bar"));
assertThat(properties.getProperty("spam.foo"), equalTo("baz"));
}
@Test
public void testBadResource() throws Exception {
public void testBadResource() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo: bar\ncd\nspam:\n foo: baz".getBytes()));
@@ -66,7 +65,7 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadResourcesWithOverride() throws Exception {
public void testLoadResourcesWithOverride() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(
new ByteArrayResource("foo: bar\nspam:\n foo: baz".getBytes()),
@@ -77,27 +76,24 @@ public class YamlPropertiesFactoryBeanTests {
assertThat(properties.getProperty("foo.bar"), equalTo("spam"));
}
@Test
public void testLoadResourcesWithInternalOverride() throws Exception {
@Test(expected = DuplicateKeyException.class)
public void testLoadResourcesWithInternalOverride() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo: bar\nspam:\n foo: baz\nfoo: bucket".getBytes()));
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo"), equalTo("bucket"));
factory.getObject();
}
@Test
@Ignore("We can't fail on duplicate keys because the Map is created by the YAML library")
public void testLoadResourcesWithNestedInternalOverride() throws Exception {
@Test(expected = DuplicateKeyException.class)
public void testLoadResourcesWithNestedInternalOverride() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo:\n bar: spam\n foo: baz\nbreak: it\nfoo: bucket".getBytes()));
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo.bar"), equalTo("spam"));
factory.getObject();
}
@Test
public void testLoadResourceWithMultipleDocuments() throws Exception {
public void testLoadResourceWithMultipleDocuments() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo: bar\nspam: baz\n---\nfoo: bag".getBytes()));
@@ -107,37 +103,29 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadResourceWithSelectedDocuments() throws Exception {
public void testLoadResourceWithSelectedDocuments() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo: bar\nspam: baz\n---\nfoo: bag\nspam: bad".getBytes()));
factory.setDocumentMatchers(new DocumentMatcher() {
@Override
public MatchStatus matches(Properties properties) {
return ("bag".equals(properties.getProperty("foo")) ?
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
}
});
factory.setDocumentMatchers((DocumentMatcher) properties -> ("bag".equals(properties.getProperty("foo")) ?
MatchStatus.FOUND : MatchStatus.NOT_FOUND));
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo"), equalTo("bag"));
assertThat(properties.getProperty("spam"), equalTo("bad"));
}
@Test
public void testLoadResourceWithDefaultMatch() throws Exception {
public void testLoadResourceWithDefaultMatch() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setMatchDefault(true);
factory.setResources(new ByteArrayResource(
"one: two\n---\nfoo: bar\nspam: baz\n---\nfoo: bag\nspam: bad".getBytes()));
factory.setDocumentMatchers(new DocumentMatcher() {
@Override
public MatchStatus matches(Properties properties) {
if (!properties.containsKey("foo")) {
return MatchStatus.ABSTAIN;
}
return ("bag".equals(properties.getProperty("foo")) ?
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
factory.setDocumentMatchers((DocumentMatcher) properties -> {
if (!properties.containsKey("foo")) {
return MatchStatus.ABSTAIN;
}
return ("bag".equals(properties.getProperty("foo")) ?
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
});
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo"), equalTo("bag"));
@@ -146,7 +134,7 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadResourceWithoutDefaultMatch() throws Exception {
public void testLoadResourceWithoutDefaultMatch() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setMatchDefault(false);
factory.setResources(new ByteArrayResource(
@@ -168,20 +156,17 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadResourceWithDefaultMatchSkippingMissedMatch() throws Exception {
public void testLoadResourceWithDefaultMatchSkippingMissedMatch() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setMatchDefault(true);
factory.setResources(new ByteArrayResource(
"one: two\n---\nfoo: bag\nspam: bad\n---\nfoo: bar\nspam: baz".getBytes()));
factory.setDocumentMatchers(new DocumentMatcher() {
@Override
public MatchStatus matches(Properties properties) {
if (!properties.containsKey("foo")) {
return MatchStatus.ABSTAIN;
}
return ("bag".equals(properties.getProperty("foo")) ?
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
factory.setDocumentMatchers((DocumentMatcher) properties -> {
if (!properties.containsKey("foo")) {
return MatchStatus.ABSTAIN;
}
return ("bag".equals(properties.getProperty("foo")) ?
MatchStatus.FOUND : MatchStatus.NOT_FOUND);
});
Properties properties = factory.getObject();
assertThat(properties.getProperty("foo"), equalTo("bag"));
@@ -190,7 +175,7 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadNonExistentResource() throws Exception {
public void testLoadNonExistentResource() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResolutionMethod(ResolutionMethod.OVERRIDE_AND_IGNORE);
factory.setResources(new ClassPathResource("no-such-file.yml"));
@@ -199,7 +184,7 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadNull() throws Exception {
public void testLoadNull() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource("foo: bar\nspam:".getBytes()));
Properties properties = factory.getObject();
@@ -208,7 +193,16 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadArrayOfString() throws Exception {
public void testLoadEmptyArrayValue() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource("a: alpha\ntest: []".getBytes()));
Properties properties = factory.getObject();
assertThat(properties.getProperty("a"), equalTo("alpha"));
assertThat(properties.getProperty("test"), equalTo(""));
}
@Test
public void testLoadArrayOfString() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource("foo:\n- bar\n- baz".getBytes()));
Properties properties = factory.getObject();
@@ -218,7 +212,7 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadArrayOfInteger() throws Exception {
public void testLoadArrayOfInteger() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource("foo:\n- 1\n- 2".getBytes()));
Properties properties = factory.getObject();
@@ -228,7 +222,7 @@ public class YamlPropertiesFactoryBeanTests {
}
@Test
public void testLoadArrayOfObject() throws Exception {
public void testLoadArrayOfObject() {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(new ByteArrayResource(
"foo:\n- bar:\n spam: crap\n- baz\n- one: two\n three: four".getBytes()
@@ -246,8 +240,8 @@ public class YamlPropertiesFactoryBeanTests {
public void testYaml() {
Yaml yaml = new Yaml();
Map<String, ?> map = yaml.loadAs("foo: bar\nspam:\n foo: baz", Map.class);
assertThat(map.get("foo"), equalTo((Object) "bar"));
assertThat(((Map<String, Object>) map.get("spam")).get("foo"), equalTo((Object) "baz"));
assertThat(map.get("foo"), equalTo("bar"));
assertThat(((Map<String, Object>) map.get("spam")).get("foo"), equalTo("baz"));
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author 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,6 +40,7 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.core.OverridingClassLoader;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.UrlResource;
@@ -672,6 +673,8 @@ public class BeanFactoryGenericsTests {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("mock", rbd);
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@@ -700,6 +703,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@@ -717,6 +724,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@@ -732,6 +743,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName()));
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@@ -749,6 +764,10 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addGenericArgumentValue("x");
bf.registerBeanDefinition("mock", rbd);
assertFalse(bf.isTypeMatch("mock", Runnable.class));
assertFalse(bf.isTypeMatch("mock", Runnable.class));
assertNull(bf.getType("mock"));
assertNull(bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(0, beans.size());
}
@@ -766,6 +785,32 @@ public class BeanFactoryGenericsTests {
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@Test // SPR-16720
public void parameterizedInstanceFactoryMethodWithTempClassLoader() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setTempClassLoader(new OverridingClassLoader(getClass().getClassLoader()));
RootBeanDefinition rbd = new RootBeanDefinition(MocksControl.class);
bf.registerBeanDefinition("mocksControl", rbd);
rbd = new RootBeanDefinition();
rbd.setFactoryBeanName("mocksControl");
rbd.setFactoryMethodName("createMock");
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
bf.registerBeanDefinition("mock", rbd);
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertTrue(bf.isTypeMatch("mock", Runnable.class));
assertEquals(Runnable.class, bf.getType("mock"));
assertEquals(Runnable.class, bf.getType("mock"));
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@@ -0,0 +1,29 @@
/*
* Copyright 2002-2018 the original author 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.tests.sample.beans;
public interface AgeHolder {
default int age() {
return getAge();
}
int getAge();
void setAge(int age);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2018 the original author 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,11 +27,7 @@ import java.io.IOException;
* @author Rod Johnson
* @author Juergen Hoeller
*/
public interface ITestBean {
int getAge();
void setAge(int age);
public interface ITestBean extends AgeHolder {
String getName();
@@ -17,6 +17,7 @@
package org.springframework.cache.interceptor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -30,6 +31,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
@@ -40,6 +42,7 @@ import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -624,6 +627,10 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
private final Class<?> targetClass;
private final Method targetMethod;
private final AnnotatedElementKey methodKey;
private final KeyGenerator keyGenerator;
private final CacheResolver cacheResolver;
@@ -632,8 +639,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
KeyGenerator keyGenerator, CacheResolver cacheResolver) {
this.operation = operation;
this.method = method;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.targetClass = targetClass;
this.targetMethod = (!Proxy.isProxyClass(targetClass) ?
AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
this.keyGenerator = keyGenerator;
this.cacheResolver = cacheResolver;
}
@@ -652,15 +662,12 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
private final Collection<String> cacheNames;
private final AnnotatedElementKey methodCacheKey;
public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
this.metadata = metadata;
this.args = extractArgs(metadata.method, args);
this.target = target;
this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
this.cacheNames = createCacheNames(this.caches);
this.methodCacheKey = new AnnotatedElementKey(metadata.method, metadata.targetClass);
}
@Override
@@ -698,7 +705,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.condition(this.metadata.operation.getCondition(),
this.methodCacheKey, evaluationContext);
this.metadata.methodKey, evaluationContext);
}
return true;
}
@@ -713,7 +720,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
if (StringUtils.hasText(unless)) {
EvaluationContext evaluationContext = createEvaluationContext(value);
return !evaluator.unless(unless, this.methodCacheKey, evaluationContext);
return !evaluator.unless(unless, this.metadata.methodKey, evaluationContext);
}
return true;
}
@@ -725,14 +732,14 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
protected Object generateKey(@Nullable Object result) {
if (StringUtils.hasText(this.metadata.operation.getKey())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.key(this.metadata.operation.getKey(), this.methodCacheKey, evaluationContext);
return evaluator.key(this.metadata.operation.getKey(), this.metadata.methodKey, evaluationContext);
}
return this.metadata.keyGenerator.generate(this.target, this.metadata.method, this.args);
}
private EvaluationContext createEvaluationContext(@Nullable Object result) {
return evaluator.createEvaluationContext(this.caches, this.metadata.method, this.args,
this.target, this.metadata.targetClass, result, beanFactory);
this.target, this.metadata.targetClass, this.metadata.targetMethod, result, beanFactory);
}
protected Collection<? extends Cache> getCaches() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 the original author 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.lang.reflect.Method;
import java.util.Collection;
import org.springframework.cache.Cache;
import org.springframework.util.Assert;
/**
* Class describing the root object used during the expression evaluation.
@@ -45,8 +44,6 @@ class CacheExpressionRootObject {
public CacheExpressionRootObject(
Collection<? extends Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
Assert.notNull(method, "Method is required");
Assert.notNull(targetClass, "targetClass is required");
this.method = method;
this.target = target;
this.targetClass = targetClass;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cache.Cache;
import org.springframework.context.expression.AnnotatedElementKey;
@@ -68,18 +67,6 @@ class CacheOperationExpressionEvaluator extends CachedExpressionEvaluator {
private final Map<ExpressionKey, Expression> unlessCache = new ConcurrentHashMap<>(64);
private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);
/**
* Create an {@link EvaluationContext} without a return value.
* @see #createEvaluationContext(Collection, Method, Object[], Object, Class, Object, BeanFactory)
*/
public EvaluationContext createEvaluationContext(Collection<? extends Cache> caches,
Method method, Object[] args, Object target, Class<?> targetClass, BeanFactory beanFactory) {
return createEvaluationContext(caches, method, args, target, targetClass, NO_RESULT, beanFactory);
}
/**
* Create an {@link EvaluationContext}.
@@ -93,12 +80,11 @@ class CacheOperationExpressionEvaluator extends CachedExpressionEvaluator {
* @return the evaluation context
*/
public EvaluationContext createEvaluationContext(Collection<? extends Cache> caches,
Method method, Object[] args, Object target, Class<?> targetClass, @Nullable Object result,
@Nullable BeanFactory beanFactory) {
Method method, Object[] args, Object target, Class<?> targetClass, Method targetMethod,
@Nullable Object result, @Nullable BeanFactory beanFactory) {
CacheExpressionRootObject rootObject = new CacheExpressionRootObject(
caches, method, args, target, targetClass);
Method targetMethod = getTargetMethod(targetClass, method);
CacheEvaluationContext evaluationContext = new CacheEvaluationContext(
rootObject, targetMethod, args, getParameterNameDiscoverer());
if (result == RESULT_UNAVAILABLE) {
@@ -135,18 +121,6 @@ class CacheOperationExpressionEvaluator extends CachedExpressionEvaluator {
this.keyCache.clear();
this.conditionCache.clear();
this.unlessCache.clear();
this.targetMethodCache.clear();
}
private Method getTargetMethod(Class<?> targetClass, Method method) {
AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
Method targetMethod = this.targetMethodCache.get(methodKey);
if (targetMethod == null) {
targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
this.targetMethodCache.put(methodKey, targetMethod);
}
return targetMethod;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author 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,15 @@ class VariableNotAvailableException extends EvaluationException {
private final String name;
public VariableNotAvailableException(String name) {
super("Variable '" + name + "' is not available");
super("Variable not available");
this.name = name;
}
public String getName() {
public final String getName() {
return this.name;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -122,8 +122,8 @@ class ConfigurationClassBeanDefinitionReader {
* Read a particular {@link ConfigurationClass}, registering bean definitions
* for the class itself and all of its {@link Bean} methods.
*/
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
@@ -140,6 +140,7 @@ class ConfigurationClassBeanDefinitionReader {
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
@@ -118,9 +118,9 @@ class ConfigurationClassEnhancer {
/**
* Creates a new CGLIB {@link Enhancer} instance.
*/
private Enhancer newEnhancer(Class<?> superclass, @Nullable ClassLoader classLoader) {
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(superclass);
enhancer.setSuperclass(configSuperClass);
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
@@ -288,9 +288,12 @@ class ConfigurationClassParser {
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
if (ConfigurationClassUtils.checkConfigurationClassCandidate(
holder.getBeanDefinition(), this.metadataReaderFactory)) {
parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
/**
* Utilities for processing @{@link Configuration} classes.
* Utilities for identifying @{@link Configuration} classes.
*
* @author Chris Beams
* @author Juergen Hoeller
@@ -60,7 +60,7 @@ abstract class ConfigurationClassUtils {
private static final Log logger = LogFactory.getLog(ConfigurationClassUtils.class);
private static final Set<String> candidateIndicators = new HashSet<>(4);
private static final Set<String> candidateIndicators = new HashSet<>(8);
static {
candidateIndicators.add(Component.class.getName());
@@ -18,6 +18,7 @@ package org.springframework.context.event;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Collection;
@@ -27,6 +28,7 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.PayloadApplicationEvent;
@@ -35,10 +37,8 @@ import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
@@ -66,9 +66,9 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
private final Method method;
private final Class<?> targetClass;
private final Method targetMethod;
private final Method bridgedMethod;
private final AnnotatedElementKey methodKey;
private final List<ResolvableType> declaredEventTypes;
@@ -77,8 +77,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
private final int order;
private final AnnotatedElementKey methodKey;
@Nullable
private ApplicationContext applicationContext;
@@ -88,18 +86,15 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
this.beanName = beanName;
this.method = method;
this.targetClass = targetClass;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
Method targetMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
EventListener ann = AnnotatedElementUtils.findMergedAnnotation(targetMethod, EventListener.class);
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.targetMethod = (!Proxy.isProxyClass(targetClass) ?
AopUtils.getMostSpecificMethod(method, targetClass) : this.method);
this.methodKey = new AnnotatedElementKey(this.targetMethod, targetClass);
EventListener ann = AnnotatedElementUtils.findMergedAnnotation(this.targetMethod, EventListener.class);
this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
this.condition = (ann != null ? ann.condition() : null);
this.order = resolveOrder(method);
this.methodKey = new AnnotatedElementKey(method, targetClass);
}
@@ -109,20 +104,23 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
throw new IllegalStateException(
"Maximum one parameter is allowed for event listener method: " + method);
}
if (ann != null && ann.classes().length > 0) {
List<ResolvableType> types = new ArrayList<>(ann.classes().length);
for (Class<?> eventType : ann.classes()) {
types.add(ResolvableType.forClass(eventType));
if (ann != null) {
Class<?>[] classes = ann.classes();
if (classes.length > 0) {
List<ResolvableType> types = new ArrayList<>(classes.length);
for (Class<?> eventType : classes) {
types.add(ResolvableType.forClass(eventType));
}
return types;
}
return types;
}
else {
if (count == 0) {
throw new IllegalStateException(
"Event parameter is mandatory for event listener method: " + method);
}
return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
if (count == 0) {
throw new IllegalStateException(
"Event parameter is mandatory for event listener method: " + method);
}
return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
}
private int resolveOrder(Method method) {
@@ -245,10 +243,9 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
}
String condition = getCondition();
if (StringUtils.hasText(condition)) {
Assert.notNull(this.evaluator, "EventExpressionEvaluator must no be null");
EvaluationContext evaluationContext = this.evaluator.createEvaluationContext(
event, this.targetClass, this.method, args, this.applicationContext);
return this.evaluator.condition(condition, this.methodKey, evaluationContext);
Assert.notNull(this.evaluator, "EventExpressionEvaluator must not be null");
return this.evaluator.condition(
condition, event, this.targetMethod, this.methodKey, args, this.applicationContext);
}
return true;
}
@@ -259,12 +256,12 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
@Nullable
protected Object doInvoke(Object... args) {
Object bean = getTargetBean();
ReflectionUtils.makeAccessible(this.bridgedMethod);
ReflectionUtils.makeAccessible(this.method);
try {
return this.bridgedMethod.invoke(bean, args);
return this.method.invoke(bean, args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(this.bridgedMethod, bean, args);
assertTargetBean(this.method, bean, args);
throw new IllegalStateException(getInvocationErrorMessage(bean, ex.getMessage(), args), ex);
}
catch (IllegalAccessException ex) {
@@ -311,7 +308,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
StringBuilder sb = new StringBuilder(message).append("\n");
sb.append("HandlerMethod details: \n");
sb.append("Bean [").append(bean.getClass().getName()).append("]\n");
sb.append("Method [").append(this.bridgedMethod.toGenericString()).append("]\n");
sb.append("Method [").append(this.method.toGenericString()).append("]\n");
return sb.toString();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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,14 +20,12 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.CachedExpressionEvaluator;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.lang.Nullable;
@@ -43,42 +41,22 @@ class EventExpressionEvaluator extends CachedExpressionEvaluator {
private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);
/**
* Create the suitable {@link EvaluationContext} for the specified event handling
* on the specified method.
* Specify if the condition defined by the specified expression matches.
*/
public EvaluationContext createEvaluationContext(ApplicationEvent event, Class<?> targetClass,
Method method, Object[] args, @Nullable BeanFactory beanFactory) {
public boolean condition(String conditionExpression, ApplicationEvent event, Method targetMethod,
AnnotatedElementKey methodKey, Object[] args, @Nullable BeanFactory beanFactory) {
Method targetMethod = getTargetMethod(targetClass, method);
EventExpressionRootObject root = new EventExpressionRootObject(event, args);
MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(
root, targetMethod, args, getParameterNameDiscoverer());
if (beanFactory != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return evaluationContext;
}
/**
* Specify if the condition defined by the specified expression matches.
*/
public boolean condition(String conditionExpression, AnnotatedElementKey elementKey, EvaluationContext evalContext) {
return (Boolean.TRUE.equals(getExpression(this.conditionCache, elementKey, conditionExpression).getValue(
evalContext, Boolean.class)));
}
private Method getTargetMethod(Class<?> targetClass, Method method) {
AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
Method targetMethod = this.targetMethodCache.get(methodKey);
if (targetMethod == null) {
targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
this.targetMethodCache.put(methodKey, targetMethod);
}
return targetMethod;
return (Boolean.TRUE.equals(getExpression(this.conditionCache, methodKey, conditionExpression).getValue(
evaluationContext, Boolean.class)));
}
}
@@ -80,7 +80,8 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
* This allows for very efficient hash lookups, significantly faster
* than the ResourceBundle class's own cache.
*/
private final Map<String, Map<Locale, ResourceBundle>> cachedResourceBundles = new ConcurrentHashMap<>();
private final Map<String, Map<Locale, ResourceBundle>> cachedResourceBundles =
new ConcurrentHashMap<>();
/**
* Cache to hold already generated MessageFormats.
@@ -90,7 +91,11 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
* very efficient hash lookups without concatenated keys.
* @see #getMessageFormat
*/
private final Map<ResourceBundle, Map<String, Map<Locale, MessageFormat>>> cachedBundleMessageFormats = new ConcurrentHashMap<>();
private final Map<ResourceBundle, Map<String, Map<Locale, MessageFormat>>> cachedBundleMessageFormats =
new ConcurrentHashMap<>();
@Nullable
private volatile MessageSourceControl control = new MessageSourceControl();
/**
@@ -220,7 +225,24 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
protected ResourceBundle doGetBundle(String basename, Locale locale) throws MissingResourceException {
ClassLoader classLoader = getBundleClassLoader();
Assert.state(classLoader != null, "No bundle ClassLoader set");
return ResourceBundle.getBundle(basename, locale, classLoader, new MessageSourceControl());
MessageSourceControl control = this.control;
if (control != null) {
try {
return ResourceBundle.getBundle(basename, locale, classLoader, control);
}
catch (UnsupportedOperationException ex) {
// Probably in a Jigsaw environment on JDK 9+
this.control = null;
if (logger.isInfoEnabled()) {
logger.info("ResourceBundle.Control not supported in current system environment: " +
ex.getMessage() + " - falling back to plain ResourceBundle.getBundle retrieval.");
}
}
}
// Fallback: plain getBundle lookup without Control handle
return ResourceBundle.getBundle(basename, locale, classLoader);
}
/**
@@ -266,7 +288,8 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
if (msg != null) {
if (codeMap == null) {
codeMap = new ConcurrentHashMap<>();
Map<String, Map<Locale, MessageFormat>> existing = this.cachedBundleMessageFormats.putIfAbsent(bundle, codeMap);
Map<String, Map<Locale, MessageFormat>> existing =
this.cachedBundleMessageFormats.putIfAbsent(bundle, codeMap);
if (existing != null) {
codeMap = existing;
}
@@ -341,9 +364,9 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
final String resourceName = toResourceName(bundleName, "properties");
final ClassLoader classLoader = loader;
final boolean reloadFlag = reload;
InputStream stream;
InputStream inputStream;
try {
stream = AccessController.doPrivileged((PrivilegedExceptionAction<InputStream>) () -> {
inputStream = AccessController.doPrivileged((PrivilegedExceptionAction<InputStream>) () -> {
InputStream is = null;
if (reloadFlag) {
URL url = classLoader.getResource(resourceName);
@@ -364,12 +387,12 @@ public class ResourceBundleMessageSource extends AbstractResourceBasedMessageSou
catch (PrivilegedActionException ex) {
throw (IOException) ex.getException();
}
if (stream != null) {
if (inputStream != null) {
String encoding = getDefaultEncoding();
if (encoding == null) {
encoding = "ISO-8859-1";
}
try (InputStreamReader bundleReader = new InputStreamReader(stream, encoding)) {
try (InputStreamReader bundleReader = new InputStreamReader(inputStream, encoding)) {
return loadBundle(bundleReader);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 the original author 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,23 +18,6 @@ package org.springframework.aop.aspectj;
import org.aspectj.lang.JoinPoint;
/**
* Definitions of testing types for use in within this package.
* Wherever possible, test types should be defined local to the java
* file that makes use of them. In some cases however, a test type may
* need to be shared across tests. Such types reside here, with the
* intention of reducing the surface area of java files within this
* package. This allows developers to think about tests first, and deal
* with these second class testing artifacts on an as-needed basis.
*
* Types here should be defined as package-private top level classes in
* order to avoid needing to fully qualify, e.g.: _TestTypes$Foo.
*
* @author Chris Beams
*/
final class _TestTypes { }
/**
* Aspect used as part of before advice binding tests and
* serves as base class for a number of more specialized test aspects.
@@ -44,13 +27,16 @@ final class _TestTypes { }
*/
class AdviceBindingTestAspect {
protected AdviceBindingCollaborator collaborator = null;
protected AdviceBindingCollaborator collaborator;
public void setCollaborator(AdviceBindingCollaborator aCollaborator) {
this.collaborator = aCollaborator;
}
// "advice" methods
public void oneIntArg(int age) {
this.collaborator.oneIntArg(age);
}
@@ -79,67 +65,14 @@ class AdviceBindingTestAspect {
public interface AdviceBindingCollaborator {
void oneIntArg(int x);
void oneObjectArg(Object o);
void oneIntAndOneObject(int x, Object o);
void needsJoinPoint(String s);
void needsJoinPointStaticPart(String s);
}
}
/**
* @author Ramnivas Laddad
*/
interface ICounter {
void increment();
void decrement();
int getCount();
void setCount(int counter);
void reset();
}
/**
* A simple counter for use in simple tests (for example, how many times an advice was executed)
*
* @author Ramnivas Laddad
*/
final class Counter implements ICounter {
private int count;
public Counter() {
}
@Override
public void increment() {
count++;
}
@Override
public void decrement() {
count--;
}
@Override
public int getCount() {
return count;
}
@Override
public void setCount(int counter) {
this.count = counter;
}
@Override
public void reset() {
this.count = 0;
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
/**
* A simple counter for use in simple tests (for example, how many times an advice was executed)
*
* @author Ramnivas Laddad
*/
final class Counter implements ICounter {
private int count;
public Counter() {
}
@Override
public void increment() {
count++;
}
@Override
public void decrement() {
count--;
}
@Override
public int getCount() {
return count;
}
@Override
public void setCount(int counter) {
this.count = counter;
}
@Override
public void reset() {
this.count = 0;
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
/**
* @author Ramnivas Laddad
*/
interface ICounter {
void increment();
void decrement();
int getCount();
void setCount(int counter);
void reset();
}
@@ -0,0 +1,33 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
/**
* @author Adrian Colyer
* @since 2.0
*/
interface AnnotatedTestBean {
String doThis();
String doThat();
String doTheOther();
String[] doArray();
}
@@ -0,0 +1,49 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
/**
* @author Adrian Colyer
* @since 2.0
*/
class AnnotatedTestBeanImpl implements AnnotatedTestBean {
@Override
@TestAnnotation("this value")
public String doThis() {
return "doThis";
}
@Override
@TestAnnotation("that value")
public String doThat() {
return "doThat";
}
@Override
@TestAnnotation("array value")
public String[] doArray() {
return new String[] {"doThis", "doThat"};
}
// not annotated
@Override
public String doTheOther() {
return "doTheOther";
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @author Adrian Colyer
*/
class AnnotationBindingTestAspect {
public String doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnnotation) throws Throwable {
return testAnnotation.value();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2018 the original author 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,14 +33,16 @@ public class AnnotationPointcutTests {
private AnnotatedTestBean testBean;
@Before
public void setUp() {
public void setup() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
testBean = (AnnotatedTestBean) ctx.getBean("testBean");
}
@Test
public void testAnnotationBindingInAroundAdvice() {
assertEquals("this value", testBean.doThis());
@@ -61,4 +63,3 @@ class TestMethodInterceptor implements MethodInterceptor {
return "this value";
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -185,7 +185,7 @@ public class AspectJAutoProxyCreatorTests {
// Create a child factory with a bean that should be woven
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.getPropertyValues().addPropertyValue(new PropertyValue("name", "Adrian"))
.addPropertyValue(new PropertyValue("age", new Integer(34)));
.addPropertyValue(new PropertyValue("age", 34));
childAc.registerBeanDefinition("adrian2", bd);
// Register the advisor auto proxy creator with subclass
childAc.registerBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class.getName(), new RootBeanDefinition(
@@ -270,25 +270,45 @@ public class AspectJAutoProxyCreatorTests {
assertEquals(3, adrian1.getAge());
}
@Test
public void testTwoAdviceAspect() {
ClassPathXmlApplicationContext bf = newContext("twoAdviceAspect.xml");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
testAgeAspect(adrian1, 0, 2);
}
@Test
public void testTwoAdviceAspectSingleton() {
doTestTwoAdviceAspectWith("twoAdviceAspect.xml");
ClassPathXmlApplicationContext bf = newContext("twoAdviceAspectSingleton.xml");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
testAgeAspect(adrian1, 0, 1);
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
assertNotSame(adrian1, adrian2);
testAgeAspect(adrian2, 2, 1);
}
@Test
public void testTwoAdviceAspectPrototype() {
doTestTwoAdviceAspectWith("twoAdviceAspectPrototype.xml");
}
ClassPathXmlApplicationContext bf = newContext("twoAdviceAspectPrototype.xml");
private void doTestTwoAdviceAspectWith(String location) {
ClassPathXmlApplicationContext bf = newContext(location);
boolean aspectSingleton = bf.isSingleton("aspect");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
testPrototype(adrian1, 0);
testAgeAspect(adrian1, 0, 1);
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
assertNotSame(adrian1, adrian2);
testPrototype(adrian2, aspectSingleton ? 2 : 0);
testAgeAspect(adrian2, 0, 1);
}
private void testAgeAspect(ITestBean adrian, int start, int increment) {
assertTrue(AopUtils.isAopProxy(adrian));
adrian.setName("");
assertEquals(start, adrian.age());
int newAge = 32;
adrian.setAge(newAge);
assertEquals(start + increment, adrian.age());
adrian.setAge(0);
assertEquals(start + increment * 2, adrian.age());
}
@Test
@@ -312,18 +332,6 @@ public class AspectJAutoProxyCreatorTests {
assertEquals(68, adrian.getAge());
}
private void testPrototype(ITestBean adrian1, int start) {
assertTrue(AopUtils.isAopProxy(adrian1));
//TwoAdviceAspect twoAdviceAspect = (TwoAdviceAspect) bf.getBean(TwoAdviceAspect.class.getName());
adrian1.setName("");
assertEquals(start++, adrian1.getAge());
int newAge = 32;
adrian1.setAge(newAge);
assertEquals(start++, adrian1.getAge());
adrian1.setAge(0);
assertEquals(start++, adrian1.getAge());
}
@Test
public void testForceProxyTargetClass() {
ClassPathXmlApplicationContext bf = newContext("aspectsWithCGLIB.xml");
@@ -0,0 +1,29 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author Adrian Colyer
* @since 2.0
*/
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
String value() ;
}
@@ -1,110 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* Definitions of testing types for use in within this package.
* Wherever possible, test types should be defined local to the java
* file that makes use of them. In some cases however, a test type may
* need to be shared across tests. Such types reside here, with the
* intention of reducing the surface area of java files within this
* package. This allows developers to think about tests first, and deal
* with these second class testing artifacts on an as-needed basis.
*
* Types here should be defined as package-private top level classes in
* order to avoid needing to fully qualify, e.g.: _TestTypes$Foo.
*
* @author Chris Beams
*/
final class _TestTypes { }
/**
* @author Adrian Colyer
* @since 2.0
*/
interface AnnotatedTestBean {
String doThis();
String doThat();
String doTheOther();
String[] doArray();
}
/**
* @author Adrian Colyer
* @since 2.0
*/
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
String value() ;
}
/**
* @author Adrian Colyer
* @since 2.0
*/
class AnnotatedTestBeanImpl implements AnnotatedTestBean {
@Override
@TestAnnotation("this value")
public String doThis() {
return "doThis";
}
@Override
@TestAnnotation("that value")
public String doThat() {
return "doThat";
}
@Override
@TestAnnotation("array value")
public String[] doArray() {
return new String[] {"doThis", "doThat"};
}
// not annotated
@Override
public String doTheOther() {
return "doTheOther";
}
}
/**
* @author Adrian Colyer
*/
class AnnotationBindingTestAspect {
public String doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnnotation) throws Throwable {
return testAnnotation.value();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -212,7 +212,7 @@ public abstract class AbstractAopProxyTests {
}
@Test
public void testSerializationSerializableTargetAndAdvice() throws Throwable {
public void testSerializableTargetAndAdvice() throws Throwable {
SerializablePerson personTarget = new SerializablePerson();
personTarget.setName("jim");
personTarget.setAge(26);
@@ -435,7 +435,7 @@ public abstract class AbstractAopProxyTests {
TestBean raw = new OwnSpouse();
ProxyCreatorSupport pc = new ProxyCreatorSupport();
pc.setInterfaces(new Class<?>[] {ITestBean.class});
pc.setInterfaces(ITestBean.class);
pc.setTarget(raw);
ITestBean tb = (ITestBean) createProxy(pc);
@@ -457,7 +457,7 @@ public abstract class AbstractAopProxyTests {
pc.addAdvice(mi);
// We don't care about the object
mockTargetSource.setTarget(new Object());
mockTargetSource.setTarget(new TestBean());
pc.setTargetSource(mockTargetSource);
AopProxy aop = createAopProxy(pc);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -174,7 +174,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
}
@Test
public void testUnadvisedProxyCreationWithCallDuringConstructor() throws Exception {
public void testUnadvisedProxyCreationWithCallDuringConstructor() {
CglibTestBean target = new CglibTestBean();
target.setName("Rob Harrop");
@@ -370,7 +370,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
}
@Test
public void testProxyProtectedMethod() throws Exception {
public void testProxyProtectedMethod() {
CountingBeforeAdvice advice = new CountingBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
proxyFactory.addAdvice(advice);
@@ -382,14 +382,14 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab
}
@Test
public void testProxyTargetClassInCaseOfNoInterfaces() throws Exception {
public void testProxyTargetClassInCaseOfNoInterfaces() {
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
MyBean proxy = (MyBean) proxyFactory.getProxy();
assertEquals(4, proxy.add(1, 3));
}
@Test // SPR-13328
public void testVarargsWithEnumArray() throws Exception {
public void testVarargsWithEnumArray() {
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
MyBean proxy = (MyBean) proxyFactory.getProxy();
assertTrue(proxy.doWithVarargs(MyEnum.A, MyOtherEnum.C));
@@ -0,0 +1,41 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework;
public class Echo implements IEcho {
private int a;
@Override
public int echoException(int i, Throwable t) throws Throwable {
if (t != null) {
throw t;
}
return i;
}
@Override
public void setA(int a) {
this.a = a;
}
@Override
public int getA() {
return a;
}
}
@@ -0,0 +1,27 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework;
public interface IEcho {
int echoException(int i, Throwable t) throws Throwable;
int getA();
void setA(int a);
}
@@ -260,22 +260,22 @@ public class ProxyFactoryBeanTests {
// Check it works without AOP
SideEffectBean raw = (SideEffectBean) bf.getBean("prototypeTarget");
assertEquals(INITIAL_COUNT, raw.getCount() );
assertEquals(INITIAL_COUNT, raw.getCount());
raw.doWork();
assertEquals(INITIAL_COUNT+1, raw.getCount() );
assertEquals(INITIAL_COUNT+1, raw.getCount());
raw = (SideEffectBean) bf.getBean("prototypeTarget");
assertEquals(INITIAL_COUNT, raw.getCount() );
assertEquals(INITIAL_COUNT, raw.getCount());
// Now try with advised instances
SideEffectBean prototype2FirstInstance = (SideEffectBean) bf.getBean(beanName);
assertEquals(INITIAL_COUNT, prototype2FirstInstance.getCount() );
assertEquals(INITIAL_COUNT, prototype2FirstInstance.getCount());
prototype2FirstInstance.doWork();
assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount() );
assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount());
SideEffectBean prototype2SecondInstance = (SideEffectBean) bf.getBean(beanName);
assertFalse("Prototypes are not ==", prototype2FirstInstance == prototype2SecondInstance);
assertEquals(INITIAL_COUNT, prototype2SecondInstance.getCount() );
assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount() );
assertEquals(INITIAL_COUNT, prototype2SecondInstance.getCount());
assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount());
return prototype2FirstInstance;
}
@@ -1,44 +0,0 @@
package org.springframework.aop.framework;
/**
* Definitions of testing types for use in within this package.
* Wherever possible, test types should be defined local to the java
* file that makes use of them. In some cases however, a test type may
* need to be shared across tests. Such types reside here, with the
* intention of reducing the surface area of java files within this
* package. This allows developers to think about tests first, and deal
* with these second class testing artifacts on an as-needed basis.
*
* Types here should be defined as package-private top level classes in
* order to avoid needing to fully qualify, e.g.: _TestTypes$Foo.
*
* @author Chris Beams
*/
final class _TestTypes { }
interface IEcho {
int echoException(int i, Throwable t) throws Throwable;
int getA();
void setA(int a);
}
class Echo implements IEcho {
private int a;
@Override
public int echoException(int i, Throwable t) throws Throwable {
if (t != null)
throw t;
return i;
}
@Override
public void setA(int a) {
this.a = a;
}
@Override
public int getA() {
return a;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,13 +35,13 @@ import static org.junit.Assert.*;
public class BeanNameAutoProxyCreatorInitTests {
@Test(expected = IllegalArgumentException.class)
public void testIgnoreAdvisorThatIsCurrentlyCreation() {
public void testIgnoreAdvisorThatIsCurrentlyInCreation() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
TestBean bean = (TestBean) ctx.getBean("bean");
bean.setName("foo");
assertEquals("foo", bean.getName());
bean.setName(null); // should throw
bean.setName(null); // should throw
}
}
@@ -84,7 +84,7 @@ public class CommonsPool2TargetSourceTests {
// Just check that it works--we can't make assumptions
// about the count
pooled.doWork();
//assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
//assertEquals(INITIAL_COUNT + 1, apartment.getCount());
}
@Test
@@ -132,7 +132,7 @@ public abstract class AbstractCacheTests<T extends Cache> {
String key = createRandomKey();
assertNull(cache.get(key));
Object value = cache.get(key, () -> returnValue );
Object value = cache.get(key, () -> returnValue);
assertEquals(returnValue, value);
assertEquals(value, cache.get(key).get());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@ public class ExpressionEvaluatorTests {
@Test
public void testMultipleCachingSource() throws Exception {
public void testMultipleCachingSource() {
Collection<CacheOperation> ops = getOps("multipleCaching");
assertEquals(2, ops.size());
Iterator<CacheOperation> it = ops.iterator();
@@ -74,19 +74,18 @@ public class ExpressionEvaluatorTests {
}
@Test
public void testMultipleCachingEval() throws Exception {
public void testMultipleCachingEval() {
AnnotatedClass target = new AnnotatedClass();
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, "multipleCaching", Object.class,
Object.class);
Object[] args = new Object[] { new Object(), new Object() };
Method method = ReflectionUtils.findMethod(
AnnotatedClass.class, "multipleCaching", Object.class, Object.class);
Object[] args = new Object[] {new Object(), new Object()};
Collection<ConcurrentMapCache> caches = Collections.singleton(new ConcurrentMapCache("test"));
EvaluationContext evalCtx = this.eval.createEvaluationContext(caches, method, args,
target, target.getClass(), null);
target, target.getClass(), method, CacheOperationExpressionEvaluator.NO_RESULT, null);
Collection<CacheOperation> ops = getOps("multipleCaching");
Iterator<CacheOperation> it = ops.iterator();
AnnotatedElementKey key = new AnnotatedElementKey(method, AnnotatedClass.class);
Object keyA = this.eval.key(it.next().getKey(), key, evalCtx);
@@ -97,28 +96,28 @@ public class ExpressionEvaluatorTests {
}
@Test
public void withReturnValue() throws Exception {
public void withReturnValue() {
EvaluationContext context = createEvaluationContext("theResult");
Object value = new SpelExpressionParser().parseExpression("#result").getValue(context);
assertThat(value, equalTo("theResult"));
}
@Test
public void withNullReturn() throws Exception {
public void withNullReturn() {
EvaluationContext context = createEvaluationContext(null);
Object value = new SpelExpressionParser().parseExpression("#result").getValue(context);
assertThat(value, nullValue());
}
@Test
public void withoutReturnValue() throws Exception {
public void withoutReturnValue() {
EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.NO_RESULT);
Object value = new SpelExpressionParser().parseExpression("#result").getValue(context);
assertThat(value, nullValue());
}
@Test
public void unavailableReturnValue() throws Exception {
public void unavailableReturnValue() {
EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE);
try {
new SpelExpressionParser().parseExpression("#result").getValue(context);
@@ -130,7 +129,7 @@ public class ExpressionEvaluatorTests {
}
@Test
public void resolveBeanReference() throws Exception {
public void resolveBeanReference() {
StaticApplicationContext applicationContext = new StaticApplicationContext();
BeanDefinition beanDefinition = new RootBeanDefinition(String.class);
applicationContext.registerBeanDefinition("myBean", beanDefinition);
@@ -147,11 +146,12 @@ public class ExpressionEvaluatorTests {
private EvaluationContext createEvaluationContext(Object result, BeanFactory beanFactory) {
AnnotatedClass target = new AnnotatedClass();
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, "multipleCaching", Object.class,
Object.class);
Object[] args = new Object[] { new Object(), new Object() };
Method method = ReflectionUtils.findMethod(
AnnotatedClass.class, "multipleCaching", Object.class, Object.class);
Object[] args = new Object[] {new Object(), new Object()};
Collection<ConcurrentMapCache> caches = Collections.singleton(new ConcurrentMapCache("test"));
return this.eval.createEvaluationContext(caches, method, args, target, target.getClass(), result, beanFactory);
return this.eval.createEvaluationContext(
caches, method, args, target, target.getClass(), method, result, beanFactory);
}
@@ -37,6 +37,7 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Lookup;
@@ -351,7 +352,7 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Test
@Test // SPR-15384
public void nestedConfigurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedNestedClasses.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
@@ -363,6 +364,19 @@ public class ConfigurationClassPostProcessorTests {
assertSame(foo, bar.foo);
}
@Test // SPR-16734
public void innerConfigurationClassesProcessedInCorrectOrder() {
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithOrderedInnerClasses.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
Foo foo = beanFactory.getBean(Foo.class);
assertTrue(foo instanceof ExtendedFoo);
Bar bar = beanFactory.getBean(Bar.class);
assertSame(foo, bar.foo);
}
@Test
public void scopedProxyTargetMarkedAsNonAutowireCandidate() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
@@ -890,6 +904,43 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Configuration
static class ConfigWithOrderedInnerClasses {
@Configuration
@Order(1)
class SingletonBeanConfig {
public SingletonBeanConfig(ConfigWithOrderedInnerClasses other) {
}
public @Bean Foo foo() {
return new Foo();
}
public @Bean Bar bar() {
return new Bar(foo());
}
}
@Configuration
@Order(2)
class OverridingSingletonBeanConfig {
public OverridingSingletonBeanConfig(ObjectProvider<SingletonBeanConfig> other) {
other.getObject();
}
public @Bean ExtendedFoo foo() {
return new ExtendedFoo();
}
public @Bean Bar bar() {
return new Bar(foo());
}
}
}
static class Foo {
}
@@ -0,0 +1,138 @@
/*
* Copyright 2002-2018 the original author 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.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
* @author Andy Wilkinson
* @author Juergen Hoeller
*/
public class DuplicatePostProcessingTests {
@Test
public void testWithFactoryBeanAndEventListener() {
new AnnotationConfigApplicationContext(Config.class).getBean(ExampleBean.class);
}
static class Config {
@Bean
public ExampleFactoryBean exampleFactory() {
return new ExampleFactoryBean();
}
@Bean
public static ExampleBeanPostProcessor exampleBeanPostProcessor() {
return new ExampleBeanPostProcessor();
}
@Bean
public ExampleApplicationEventListener exampleApplicationEventListener() {
return new ExampleApplicationEventListener();
}
}
static class ExampleFactoryBean implements FactoryBean<ExampleBean> {
private final ExampleBean exampleBean = new ExampleBean();
@Override
public ExampleBean getObject() throws Exception {
return this.exampleBean;
}
@Override
public Class<?> getObjectType() {
return ExampleBean.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
static class ExampleBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof ExampleBean) {
this.applicationContext.publishEvent(new ExampleApplicationEvent(this));
}
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
static class ExampleApplicationEvent extends ApplicationEvent {
public ExampleApplicationEvent(Object source) {
super(source);
}
}
static class ExampleApplicationEventListener implements ApplicationListener<ExampleApplicationEvent>, BeanFactoryAware {
private BeanFactory beanFactory;
@Override
public void onApplicationEvent(ExampleApplicationEvent event) {
this.beanFactory.getBean(ExampleBean.class);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
static class ExampleBean {
}
}
@@ -0,0 +1,50 @@
/*
* Copyright 2002-2018 the original author 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.spr16756;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Component
public class ScannedComponent {
@Autowired
private State state;
public String iDoAnything() {
return state.anyMethod();
}
public interface State {
String anyMethod();
}
@Component
@Scope(proxyMode = ScopedProxyMode.INTERFACES, value = "prototype")
public static class StateImpl implements State {
public String anyMethod() {
return "anyMethod called";
}
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2002-2018 the original author 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.spr16756;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class ScanningConfiguration {
}
@@ -0,0 +1,37 @@
/*
* Copyright 2002-2018 the original author 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.spr16756;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author Juergen Hoeller
*/
public class Spr16756Tests {
@Test
public void shouldNotFailOnNestedScopedComponent() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(ScanningConfiguration.class);
context.refresh();
context.getBean(ScannedComponent.class);
context.getBean(ScannedComponent.State.class);
}
}
@@ -89,7 +89,7 @@ public class LocalSlsbInvokerInterceptorTests {
LocalSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
ProxyFactory pf = new ProxyFactory(new Class<?>[] { BusinessMethods.class } );
ProxyFactory pf = new ProxyFactory(new Class<?>[] { BusinessMethods.class });
pf.addAdvice(si);
BusinessMethods target = (BusinessMethods) pf.getProxy();
@@ -110,7 +110,7 @@ public class LocalSlsbInvokerInterceptorTests {
LocalSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
ProxyFactory pf = new ProxyFactory(new Class<?>[] { BusinessMethods.class } );
ProxyFactory pf = new ProxyFactory(new Class<?>[] { BusinessMethods.class });
pf.addAdvice(si);
BusinessMethods target = (BusinessMethods) pf.getProxy();
@@ -129,7 +129,7 @@ public class LocalSlsbInvokerInterceptorTests {
LocalSlsbInvokerInterceptor si = configuredInterceptor(mockContext, jndiName);
ProxyFactory pf = new ProxyFactory(new Class<?>[] { LocalInterfaceWithBusinessMethods.class } );
ProxyFactory pf = new ProxyFactory(new Class<?>[] { LocalInterfaceWithBusinessMethods.class });
pf.addAdvice(si);
LocalInterfaceWithBusinessMethods target = (LocalInterfaceWithBusinessMethods) pf.getProxy();
@@ -1,6 +1,19 @@
/**
/*
* Copyright 2002-2018 the original author 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 test.aspect;
import org.aspectj.lang.annotation.Around;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,15 +23,17 @@ import org.aspectj.lang.annotation.Before;
@Aspect
public class TwoAdviceAspect {
private int totalCalls;
@Around("execution(* getAge())")
@Around("execution(* org.springframework.tests.sample.beans.ITestBean.age())")
public int returnCallCount(ProceedingJoinPoint pjp) throws Exception {
return totalCalls;
}
@Before("execution(* setAge(int)) && args(newAge)")
@Before("execution(* org.springframework.tests.sample.beans.ITestBean.setAge(int)) && args(newAge)")
public void countSet(int newAge) throws Exception {
++totalCalls;
}
}
}
@@ -7,9 +7,13 @@
<bean id="aspect" class="test.aspect.TwoAdviceAspect"/>
<bean id="adrian" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
<bean id="adrian" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="org.springframework.tests.sample.beans.TestBean">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</property>
</bean>
</beans>
@@ -5,8 +5,7 @@
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean id="aspect" class="test.aspect.TwoAdviceAspect"
scope="prototype"/>
<bean id="aspect" class="test.aspect.TwoAdviceAspect" scope="prototype"/>
<bean id="adrian" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean id="aspect" class="test.aspect.TwoAdviceAspect"/>
<bean id="adrian" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>
+3 -2
View File
@@ -40,7 +40,7 @@ task cglibRepackJar(type: Jar) { repackJar ->
}
// Repackage net.sf.cglib => org.springframework.cglib
rule(pattern: "net.sf.cglib.**", result: "org.springframework.cglib.@1")
// As mentioned above, transform cglib"s internal asm dependencies from
// As mentioned above, transform cglib's internal asm dependencies from
// org.objectweb.asm => org.springframework.asm. Doing this counts on the
// the fact that Spring and cglib depend on the same version of asm!
rule(pattern: "org.objectweb.asm.**", result: "org.springframework.asm.@1")
@@ -86,8 +86,9 @@ dependencies {
optional("io.reactivex.rxjava2:rxjava:${rxjava2Version}")
optional("io.netty:netty-buffer")
testCompile("io.projectreactor:reactor-test")
testCompile("javax.xml.bind:jaxb-api:2.3.0")
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
testCompile("org.xmlunit:xmlunit-matchers:2.5.1")
testCompile("javax.xml.bind:jaxb-api:2.3.0")
testCompile("com.fasterxml.woodstox:woodstox-core:5.0.3") {
exclude group: "stax", module: "stax-api"
}
@@ -419,7 +419,18 @@ public class MethodParameter {
paramType = (method != null ? method.getGenericReturnType() : void.class);
}
else {
paramType = this.executable.getGenericParameterTypes()[this.parameterIndex];
Type[] genericParameterTypes = this.executable.getGenericParameterTypes();
int index = this.parameterIndex;
if (this.executable instanceof Constructor &&
ClassUtils.isInnerClass(this.executable.getDeclaringClass()) &&
genericParameterTypes.length == this.executable.getParameterCount() - 1) {
// Bug in javac: type array excludes enclosing instance parameter
// for inner classes with at least one generic constructor parameter,
// so access it with the actual parameter index lowered by 1
index = this.parameterIndex - 1;
}
paramType = (index >= 0 && index < genericParameterTypes.length ?
genericParameterTypes[index] : getParameterType());
}
this.genericParameterType = paramType;
}
@@ -525,12 +536,8 @@ public class MethodParameter {
// for inner classes, so access it with the actual parameter index lowered by 1
index = this.parameterIndex - 1;
}
if (index >= 0 && index < annotationArray.length) {
paramAnns = adaptAnnotationArray(annotationArray[index]);
}
else {
paramAnns = EMPTY_ANNOTATION_ARRAY;
}
paramAnns = (index >= 0 && index < annotationArray.length ?
adaptAnnotationArray(annotationArray[index]) : EMPTY_ANNOTATION_ARRAY);
this.parameterAnnotations = paramAnns;
}
return paramAnns;
@@ -770,7 +777,6 @@ public class MethodParameter {
}
return false;
}
}
}
@@ -107,7 +107,7 @@ public class AnnotationAwareOrderComparator extends OrderComparator {
}
Integer priority = OrderUtils.getPriority(obj.getClass());
if (priority == null && obj instanceof DecoratingProxy) {
priority = OrderUtils.getOrder(((DecoratingProxy) obj).getDecoratedClass());
priority = OrderUtils.getPriority(((DecoratingProxy) obj).getDecoratedClass());
}
return priority;
}
@@ -126,6 +126,7 @@ public abstract class AnnotationUtils {
private static final Map<Class<?>, Set<Method>> annotatedBaseTypeCache =
new ConcurrentReferenceHashMap<>(256);
@SuppressWarnings("unused")
@Deprecated // just here for older tool versions trying to reflectively clear the cache
private static final Map<Class<?>, ?> annotatedInterfaceCache = annotatedBaseTypeCache;
@@ -165,7 +166,8 @@ public abstract class AnnotationUtils {
}
Class<? extends Annotation> annotatedElement = annotation.annotationType();
try {
return synthesizeAnnotation(annotatedElement.getAnnotation(annotationType), annotatedElement);
A metaAnn = annotatedElement.getAnnotation(annotationType);
return (metaAnn != null ? synthesizeAnnotation(metaAnn, annotatedElement) : null);
}
catch (Throwable ex) {
handleIntrospectionFailure(annotatedElement, ex);
@@ -553,13 +555,18 @@ public abstract class AnnotationUtils {
if (clazz == null || Object.class == clazz) {
break;
}
try {
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
result = findAnnotation((AnnotatedElement) resolvedEquivalentMethod, annotationType);
}
catch (NoSuchMethodException ex) {
// No equivalent method found
Set<Method> annotatedMethods = getAnnotatedMethodsInBaseType(clazz);
if (!annotatedMethods.isEmpty()) {
for (Method annotatedMethod : annotatedMethods) {
if (annotatedMethod.getName().equals(method.getName()) &&
Arrays.equals(annotatedMethod.getParameterTypes(), method.getParameterTypes())) {
Method resolvedSuperMethod = BridgeMethodResolver.findBridgedMethod(annotatedMethod);
result = findAnnotation((AnnotatedElement) resolvedSuperMethod, annotationType);
if (result != null) {
break;
}
}
}
}
if (result == null) {
result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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,7 +33,7 @@ import javax.annotation.meta.When;
* <p>Should be used at parameter, return value, and field level. Methods override should
* repeat parent {@code @Nullable} annotations unless they behave differently.
*
* <p>Can be used in association with {@code NonNullApi} or {@code @NonNullFields} to
* <p>Can be used in association with {@code @NonNullApi} or {@code @NonNullFields} to
* override the default non-nullable semantic to nullable.
*
* @author Sebastien Deleuze
File diff suppressed because it is too large Load Diff
@@ -209,14 +209,18 @@ public abstract class StringUtils {
return str;
}
StringBuilder sb = new StringBuilder(str);
while (sb.length() > 0 && Character.isWhitespace(sb.charAt(0))) {
sb.deleteCharAt(0);
int beginIndex = 0;
int endIndex = str.length() - 1;
while (beginIndex <= endIndex && Character.isWhitespace(str.charAt(beginIndex))) {
beginIndex++;
}
while (sb.length() > 0 && Character.isWhitespace(sb.charAt(sb.length() - 1))) {
sb.deleteCharAt(sb.length() - 1);
while (endIndex > beginIndex && Character.isWhitespace(str.charAt(endIndex))) {
endIndex--;
}
return sb.toString();
return str.substring(beginIndex, endIndex + 1);
}
/**
@@ -22,6 +22,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import org.junit.Before;
import org.junit.Test;
@@ -114,7 +115,7 @@ public class MethodParameterTests {
@Test // SPR-16652
public void annotatedConstructorParameterInInnerClass() throws Exception {
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Integer.class);
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Callable.class);
MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 0);
assertEquals(getClass(), methodParameter.getParameterType());
@@ -125,10 +126,28 @@ public class MethodParameterTests {
assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class));
methodParameter = MethodParameter.forExecutable(constructor, 2);
assertEquals(Integer.class, methodParameter.getParameterType());
assertEquals(Callable.class, methodParameter.getParameterType());
assertNull(methodParameter.getParameterAnnotation(Param.class));
}
@Test // SPR-16734
public void genericConstructorParameterInInnerClass() throws Exception {
Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Callable.class);
MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 0);
assertEquals(getClass(), methodParameter.getParameterType());
assertEquals(getClass(), methodParameter.getGenericParameterType());
methodParameter = MethodParameter.forExecutable(constructor, 1);
assertEquals(String.class, methodParameter.getParameterType());
assertEquals(String.class, methodParameter.getGenericParameterType());
methodParameter = MethodParameter.forExecutable(constructor, 2);
assertEquals(Callable.class, methodParameter.getParameterType());
assertEquals(ResolvableType.forClassWithGenerics(Callable.class, Integer.class).getType(),
methodParameter.getGenericParameterType());
}
public int method(String p1, long p2) {
return 42;
@@ -144,7 +163,7 @@ public class MethodParameterTests {
@SuppressWarnings("unused")
private class InnerClass {
public InnerClass(@Param String s, Integer i) {
public InnerClass(@Param String s, Callable<Integer> i) {
}
}
@@ -16,6 +16,7 @@
package org.springframework.util;
import java.io.Externalizable;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -44,20 +45,21 @@ import static org.junit.Assert.*;
* @author Rob Harrop
* @author Rick Evans
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ClassUtilsTests {
private ClassLoader classLoader = getClass().getClassLoader();
@Before
public void setUp() {
public void clearStatics() {
InnerClass.noArgCalled = false;
InnerClass.argCalled = false;
InnerClass.overloadedCalled = false;
}
@Test
public void testIsPresent() throws Exception {
public void testIsPresent() {
assertTrue(ClassUtils.isPresent("java.lang.String", classLoader));
assertFalse(ClassUtils.isPresent("java.lang.MySpecialString", classLoader));
}
@@ -114,6 +116,36 @@ public class ClassUtilsTests {
assertEquals(double[].class, ClassUtils.forName(double[].class.getName(), classLoader));
}
@Test
public void testIsCacheSafe() {
ClassLoader childLoader1 = new ClassLoader(classLoader) {};
ClassLoader childLoader2 = new ClassLoader(classLoader) {};
ClassLoader childLoader3 = new ClassLoader(classLoader) {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return childLoader1.loadClass(name);
}
};
Class<?> composite = ClassUtils.createCompositeInterface(
new Class<?>[] {Serializable.class, Externalizable.class}, childLoader1);
assertTrue(ClassUtils.isCacheSafe(String.class, null));
assertTrue(ClassUtils.isCacheSafe(String.class, classLoader));
assertTrue(ClassUtils.isCacheSafe(String.class, childLoader1));
assertTrue(ClassUtils.isCacheSafe(String.class, childLoader2));
assertTrue(ClassUtils.isCacheSafe(String.class, childLoader3));
assertFalse(ClassUtils.isCacheSafe(InnerClass.class, null));
assertTrue(ClassUtils.isCacheSafe(InnerClass.class, classLoader));
assertTrue(ClassUtils.isCacheSafe(InnerClass.class, childLoader1));
assertTrue(ClassUtils.isCacheSafe(InnerClass.class, childLoader2));
assertTrue(ClassUtils.isCacheSafe(InnerClass.class, childLoader3));
assertFalse(ClassUtils.isCacheSafe(composite, null));
assertFalse(ClassUtils.isCacheSafe(composite, classLoader));
assertTrue(ClassUtils.isCacheSafe(composite, childLoader1));
assertFalse(ClassUtils.isCacheSafe(composite, childLoader2));
assertTrue(ClassUtils.isCacheSafe(composite, childLoader3));
}
@Test
public void testGetShortName() {
String className = ClassUtils.getShortName(getClass());
@@ -199,7 +231,7 @@ public class ClassUtilsTests {
}
@Test
public void testHasMethod() throws Exception {
public void testHasMethod() {
assertTrue(ClassUtils.hasMethod(Collection.class, "size"));
assertTrue(ClassUtils.hasMethod(Collection.class, "remove", Object.class));
assertFalse(ClassUtils.hasMethod(Collection.class, "remove"));
@@ -207,7 +239,7 @@ public class ClassUtilsTests {
}
@Test
public void testGetMethodIfAvailable() throws Exception {
public void testGetMethodIfAvailable() {
Method method = ClassUtils.getMethodIfAvailable(Collection.class, "size");
assertNotNull(method);
assertEquals("size", method.getName());
@@ -278,7 +310,7 @@ public class ClassUtilsTests {
@Test
public void testClassPackageAsResourcePath() {
String result = ClassUtils.classPackageAsResourcePath(Proxy.class);
assertTrue(result.equals("java/lang/reflect"));
assertEquals("java/lang/reflect", result);
}
@Test
@@ -294,7 +326,7 @@ public class ClassUtilsTests {
@Test
public void testGetAllInterfaces() {
DerivedTestObject testBean = new DerivedTestObject();
List ifcs = Arrays.asList(ClassUtils.getAllInterfaces(testBean));
List<Class<?>> ifcs = Arrays.asList(ClassUtils.getAllInterfaces(testBean));
assertEquals("Correct number of interfaces", 4, ifcs.size());
assertTrue("Contains Serializable", ifcs.contains(Serializable.class));
assertTrue("Contains ITestBean", ifcs.contains(ITestObject.class));
@@ -303,13 +335,13 @@ public class ClassUtilsTests {
@Test
public void testClassNamesToString() {
List ifcs = new LinkedList();
List<Class<?>> ifcs = new LinkedList<>();
ifcs.add(Serializable.class);
ifcs.add(Runnable.class);
assertEquals("[interface java.io.Serializable, interface java.lang.Runnable]", ifcs.toString());
assertEquals("[java.io.Serializable, java.lang.Runnable]", ClassUtils.classNamesToString(ifcs));
List classes = new LinkedList();
List<Class<?>> classes = new LinkedList<>();
classes.add(LinkedList.class);
classes.add(Integer.class);
assertEquals("[class java.util.LinkedList, class java.lang.Integer]", classes.toString());
@@ -319,7 +351,7 @@ public class ClassUtilsTests {
assertEquals("[java.util.List]", ClassUtils.classNamesToString(List.class));
assertEquals("[]", Collections.EMPTY_LIST.toString());
assertEquals("[]", ClassUtils.classNamesToString(Collections.EMPTY_LIST));
assertEquals("[]", ClassUtils.classNamesToString(Collections.emptyList()));
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ public class SpelEvaluationException extends EvaluationException {
}
public SpelEvaluationException(int position, Throwable cause, SpelMessage message, Object... inserts) {
super(position, message.formatMessage(inserts),cause);
super(position, message.formatMessage(inserts), cause);
this.message = message;
this.inserts = inserts;
}
@@ -45,13 +45,13 @@ public enum SpelMessage {
"A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"),
METHOD_NOT_FOUND(Kind.ERROR, 1004,
"Method call: Method {0} cannot be found on {1} type"),
"Method call: Method {0} cannot be found on type {1}"),
TYPE_NOT_FOUND(Kind.ERROR, 1005,
"Type cannot be found ''{0}''"),
FUNCTION_NOT_DEFINED(Kind.ERROR, 1006,
"The function ''{0}'' could not be found"),
"Function ''{0}'' could not be found"),
PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007,
"Property or field ''{0}'' cannot be found on null"),
@@ -156,7 +156,7 @@ public enum SpelMessage {
NOT_A_REAL(Kind.ERROR, 1040,
"The value ''{0}'' cannot be parsed as a double"),
MORE_INPUT(Kind.ERROR,1041,
MORE_INPUT(Kind.ERROR, 1041,
"After parsing a valid expression, there is still more data in the expression: ''{0}''"),
RIGHT_OPERAND_PROBLEM(Kind.ERROR, 1042,
@@ -226,21 +226,22 @@ public enum SpelMessage {
"A required array dimension has not been specified"),
INITIALIZER_LENGTH_INCORRECT(Kind.ERROR, 1064,
"array initializer size does not match array dimensions"),
"Array initializer size does not match array dimensions"),
UNEXPECTED_ESCAPE_CHAR(Kind.ERROR, 1065, "unexpected escape character."),
UNEXPECTED_ESCAPE_CHAR(Kind.ERROR, 1065,
"Unexpected escape character"),
OPERAND_NOT_INCREMENTABLE(Kind.ERROR, 1066,
"the expression component ''{0}'' does not support increment"),
"The expression component ''{0}'' does not support increment"),
OPERAND_NOT_DECREMENTABLE(Kind.ERROR, 1067,
"the expression component ''{0}'' does not support decrement"),
"The expression component ''{0}'' does not support decrement"),
NOT_ASSIGNABLE(Kind.ERROR, 1068,
"the expression component ''{0}'' is not assignable"),
"The expression component ''{0}'' is not assignable"),
MISSING_CHARACTER(Kind.ERROR, 1069,
"missing expected character ''{0}''"),
"Missing expected character ''{0}''"),
LEFT_OPERAND_PROBLEM(Kind.ERROR, 1070,
"Problem parsing left operand"),
@@ -248,8 +249,13 @@ public enum SpelMessage {
MISSING_SELECTION_EXPRESSION(Kind.ERROR, 1071,
"A required selection expression has not been specified"),
EXCEPTION_RUNNING_COMPILED_EXPRESSION(Kind.ERROR,1072,
"An exception occurred whilst evaluating a compiled expression");
/** @since 4.1 */
EXCEPTION_RUNNING_COMPILED_EXPRESSION(Kind.ERROR, 1072,
"An exception occurred whilst evaluating a compiled expression"),
/** @since 4.3.17 */
FLAWED_PATTERN(Kind.ERROR, 1073,
"Failed to efficiently evaluate pattern ''{0}'': consider redesigning it");
private final Kind kind;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* Utility methods (formatters, etc) used during parsing and evaluation.
* Utility methods (formatters etc) used during parsing and evaluation.
*
* @author Andy Clement
*/
@@ -131,7 +131,7 @@ public class MethodReference extends SpelNodeImpl {
}
// either there was no accessor or it no longer existed
executorToUse = findAccessorForMethod(this.name, argumentTypes, value, evaluationContext);
executorToUse = findAccessorForMethod(argumentTypes, value, evaluationContext);
this.cachedExecutor = new CachedMethodExecutor(
executorToUse, (value instanceof Class ? (Class<?>) value : null), targetType, argumentTypes);
try {
@@ -196,33 +196,40 @@ public class MethodReference extends SpelNodeImpl {
return null;
}
private MethodExecutor findAccessorForMethod(String name, List<TypeDescriptor> argumentTypes,
Object targetObject, EvaluationContext evaluationContext) throws SpelEvaluationException {
private MethodExecutor findAccessorForMethod(List<TypeDescriptor> argumentTypes, Object targetObject,
EvaluationContext evaluationContext) throws SpelEvaluationException {
AccessException accessException = null;
List<MethodResolver> methodResolvers = evaluationContext.getMethodResolvers();
for (MethodResolver methodResolver : methodResolvers) {
try {
MethodExecutor methodExecutor = methodResolver.resolve(
evaluationContext, targetObject, name, argumentTypes);
evaluationContext, targetObject, this.name, argumentTypes);
if (methodExecutor != null) {
return methodExecutor;
}
}
catch (AccessException ex) {
throw new SpelEvaluationException(getStartPosition(), ex,
SpelMessage.PROBLEM_LOCATING_METHOD, name, targetObject.getClass());
accessException = ex;
break;
}
}
throw new SpelEvaluationException(getStartPosition(), SpelMessage.METHOD_NOT_FOUND,
FormatHelper.formatMethodForMessage(name, argumentTypes),
FormatHelper.formatClassNameForMessage(
targetObject instanceof Class ? ((Class<?>) targetObject) : targetObject.getClass()));
String method = FormatHelper.formatMethodForMessage(this.name, argumentTypes);
String className = FormatHelper.formatClassNameForMessage(
targetObject instanceof Class ? ((Class<?>) targetObject) : targetObject.getClass());
if (accessException != null) {
throw new SpelEvaluationException(
getStartPosition(), accessException, SpelMessage.PROBLEM_LOCATING_METHOD, method, className);
}
else {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.METHOD_NOT_FOUND, method, className);
}
}
/**
* Decode the AccessException, throwing a lightweight evaluation exception or, if the
* cause was a RuntimeException, throw the RuntimeException directly.
* Decode the AccessException, throwing a lightweight evaluation exception or,
* if the cause was a RuntimeException, throw the RuntimeException directly.
*/
private void throwSimpleExceptionIfPossible(Object value, AccessException ex) {
if (ex.getCause() instanceof InvocationTargetException) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author 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,6 +40,8 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/
public class OperatorMatches extends Operator {
private static final int PATTERN_ACCESS_THRESHOLD = 1000000;
private final ConcurrentMap<String, Pattern> patternCache = new ConcurrentHashMap<>();
@@ -79,11 +81,59 @@ public class OperatorMatches extends Operator {
pattern = Pattern.compile(rightString);
this.patternCache.putIfAbsent(rightString, pattern);
}
Matcher matcher = pattern.matcher(left);
Matcher matcher = pattern.matcher(new MatcherInput(left, new AccessCount()));
return BooleanTypedValue.forValue(matcher.matches());
}
catch (PatternSyntaxException ex) {
throw new SpelEvaluationException(rightOp.getStartPosition(), ex, SpelMessage.INVALID_PATTERN, right);
throw new SpelEvaluationException(
rightOp.getStartPosition(), ex, SpelMessage.INVALID_PATTERN, right);
}
catch (IllegalStateException ex) {
throw new SpelEvaluationException(
rightOp.getStartPosition(), ex, SpelMessage.FLAWED_PATTERN, right);
}
}
private static class AccessCount {
private int count;
public void check() throws IllegalStateException {
if (this.count++ > PATTERN_ACCESS_THRESHOLD) {
throw new IllegalStateException("Pattern access threshold exceeded");
}
}
}
private static class MatcherInput implements CharSequence {
private final CharSequence value;
private AccessCount access;
public MatcherInput(CharSequence value, AccessCount access) {
this.value = value;
this.access = access;
}
public char charAt(int index) {
this.access.check();
return this.value.charAt(index);
}
public CharSequence subSequence(int start, int end) {
return new MatcherInput(this.value.subSequence(start, end), this.access);
}
public int length() {
return this.value.length();
}
@Override
public String toString() {
return this.value.toString();
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -265,7 +265,7 @@ class Tokenizer {
raiseParseException(this.pos, SpelMessage.UNEXPECTED_ESCAPE_CHAR);
break;
default:
throw new IllegalStateException("Cannot handle (" + Integer.valueOf(ch) + ") '" + ch + "'");
throw new IllegalStateException("Cannot handle (" + (int) ch + ") '" + ch + "'");
}
}
}
@@ -194,6 +194,22 @@ public class EvaluationTests extends AbstractExpressionTests {
evaluate("27 matches '^.*2.*$'", true, Boolean.class); // conversion int>string
}
@Test // SPR-16731
public void testMatchesWithPatternAccessThreshold() {
String pattern = "^(?=[a-z0-9-]{1,47})([a-z0-9]+[-]{0,1}){1,47}[a-z0-9]{1}$";
String expression = "'abcde-fghijklmn-o42pasdfasdfasdf.qrstuvwxyz10x.xx.yyy.zasdfasfd' matches \'" + pattern + "\'";
Expression expr = parser.parseExpression(expression);
try {
expr.getValue();
fail("Should have exceeded threshold");
}
catch (EvaluationException ee) {
SpelEvaluationException see = (SpelEvaluationException) ee;
assertEquals(SpelMessage.FLAWED_PATTERN, see.getMessageCode());
assertTrue(see.getCause() instanceof IllegalStateException);
}
}
// mixing operators
@Test
public void testMixingOperators01() {
@@ -76,7 +76,7 @@ public class DatabaseStartupValidator implements InitializingBean {
/**
* Set the interval between validation runs (in seconds).
* Default is 1.
* Default is {@value #DEFAULT_INTERVAL}.
*/
public void setInterval(int interval) {
this.interval = interval;
@@ -84,7 +84,7 @@ public class DatabaseStartupValidator implements InitializingBean {
/**
* Set the timeout (in seconds) after which a fatal exception
* will be thrown. Default is 60.
* will be thrown. Default is {@value #DEFAULT_TIMEOUT}.
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
@@ -127,11 +127,15 @@ public class DatabaseStartupValidator implements InitializingBean {
}
catch (SQLException ex) {
latestEx = ex;
logger.debug("Validation query [" + this.validationQuery + "] threw exception", ex);
float rest = ((float) (deadLine - System.currentTimeMillis())) / 1000;
if (rest > this.interval) {
logger.warn("Database has not started up yet - retrying in " + this.interval +
" seconds (timeout in " + rest + " seconds)");
if (logger.isDebugEnabled()) {
logger.debug("Validation query [" + this.validationQuery + "] threw exception", ex);
}
if (logger.isWarnEnabled()) {
float rest = ((float) (deadLine - System.currentTimeMillis())) / 1000;
if (rest > this.interval) {
logger.warn("Database has not started up yet - retrying in " + this.interval +
" seconds (timeout in " + rest + " seconds)");
}
}
}
finally {
@@ -149,8 +153,8 @@ public class DatabaseStartupValidator implements InitializingBean {
"Database has not started up within " + this.timeout + " seconds", latestEx);
}
float duration = (System.currentTimeMillis() - beginTime)*1f / 1000;
if (logger.isInfoEnabled()) {
float duration = ((float) (System.currentTimeMillis() - beginTime)) / 1000;
logger.info("Database startup detected after " + duration + " seconds");
}
}
@@ -112,7 +112,7 @@ public class SqlLobValueTests {
lob.setTypeValue(preparedStatement, 1, Types.CLOB, "test");
verify(creator).setClobAsAsciiStream(eq(preparedStatement), eq(1), inputStreamCaptor.capture(), eq(3));
byte[] bytes = new byte[3];
inputStreamCaptor.getValue().read(bytes );
inputStreamCaptor.getValue().read(bytes);
assertThat(bytes, equalTo(testContent));
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@ public class DataSourceTransactionManagerTests {
@Before
public void setUp() throws Exception {
public void setup() throws Exception {
ds = mock(DataSource.class);
con = mock(Connection.class);
given(ds.getConnection()).willReturn(con);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -84,6 +84,7 @@ public class JmsMessageEndpointFactory extends AbstractMessageEndpointFactory {
@Override
public void onMessage(Message message) {
Throwable endpointEx = null;
boolean applyDeliveryCalls = !hasBeforeDeliveryBeenCalled();
if (applyDeliveryCalls) {
try {
@@ -97,6 +98,7 @@ public class JmsMessageEndpointFactory extends AbstractMessageEndpointFactory {
getMessageListener().onMessage(message);
}
catch (RuntimeException | Error ex) {
endpointEx = ex;
onEndpointException(ex);
throw ex;
}
@@ -106,7 +108,9 @@ public class JmsMessageEndpointFactory extends AbstractMessageEndpointFactory {
afterDelivery();
}
catch (ResourceException ex) {
throw new JmsResourceException(ex);
if (endpointEx == null) {
throw new JmsResourceException(ex);
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,7 +49,7 @@ import static org.mockito.BDDMockito.*;
public class JmsTransactionManagerTests {
@After
public void verifyTransactionSynchronizationManager() {
public void verifyTransactionSynchronizationManagerState() {
assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty());
assertFalse(TransactionSynchronizationManager.isSynchronizationActive());
}
+1
View File
@@ -41,6 +41,7 @@ dependencies {
testCompile("org.apache.tomcat.embed:tomcat-embed-websocket:${tomcatVersion}")
testCompile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
testCompile("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
testCompile("org.xmlunit:xmlunit-matchers:2.5.1")
testRuntime("com.sun.xml.bind:jaxb-core:2.3.0")
testRuntime("com.sun.xml.bind:jaxb-impl:2.3.0")
testRuntime("com.sun.activation:javax.activation:1.2.0")
@@ -73,7 +73,7 @@ public class HeaderMethodArgumentResolver extends AbstractNamedValueMethodArgume
logger.warn("Message headers contain two values for the same header '" + name + "', " +
"one in the top level header map and a second in the nested map with native headers. " +
"Using the value from top level map. " +
"Use 'nativeHeader.myHeader' to resolve to the value from the nested native header map." );
"Use 'nativeHeader.myHeader' to resolve to the value from the nested native header map.");
}
}

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