Compare commits

...

842 Commits

Author SHA1 Message Date
Spring Builds 8f4c172734 Release v5.2.22.RELEASE 2022-05-11 07:20:17 +00:00
Juergen Hoeller 9f238c997d Polishing 2022-05-11 08:47:46 +02:00
Juergen Hoeller 50177b1ad3 Refine CachedIntrospectionResults property introspection
Closes gh-28445
2022-05-11 08:42:43 +02:00
rstoyanchev 159a99bbaf Ignore invalid STOMP frame
Closes gh-28444
2022-05-11 07:26:26 +01:00
Spring Builds 41e158c93d Next development version (v5.2.22.BUILD-SNAPSHOT) 2022-04-13 10:32:09 +00:00
Sam Brannen 833e750175 Improve documentation and matching algorithm in data binders 2022-04-13 10:20:41 +02:00
Juergen Hoeller d70054d686 Upgrade to Log4j2 2.17.2 2022-04-08 14:00:06 +02:00
Juergen Hoeller 36e4951b5e Polishing 2022-04-08 13:58:10 +02:00
Juergen Hoeller 87b5080586 Consistent use of getLocalAddr() without DNS lookups in request adapters
Closes gh-28280
2022-04-08 13:57:09 +02:00
Juergen Hoeller 5cbf85a6f8 Avoid return value reference in potentially cached MethodParameter instance
Closes gh-28232

(cherry picked from commit eefdd2c768)
2022-04-08 13:32:12 +02:00
Juergen Hoeller 69c7eb9418 Restore ability to configure setClassLoader methods
Closes gh-28269

(cherry picked from commit 9f91168396)
2022-04-08 13:31:34 +02:00
Juergen Hoeller fb763dd0f4 Consistent fallback in case of fast-class generation failure
Closes gh-28138

(cherry picked from commit 7aed6279a2)
2022-04-08 13:29:07 +02:00
Spring Builds 1b75f393a9 Next development version (v5.2.21.BUILD-SNAPSHOT) 2022-03-31 10:01:20 +00:00
Brian Clozel 996f701a19 Refine PropertyDescriptor filtering
Restrict property paths under `Class` and properties of types
`ClassLoader` or `ProtectionDomain`.
2022-03-31 10:32:41 +02:00
Sam Brannen 90cfde985e Improve diagnostics in SpEL for large array creation
Attempting to create a large array in a SpEL expression can result in
an OutOfMemoryError. Although the JVM recovers from that, the error
message is not very helpful to the user.

This commit improves the diagnostics in SpEL for large array creation
by throwing a SpelEvaluationException with a meaningful error message
in order to improve diagnostics for the user.

Closes gh-28257
2022-03-31 10:25:27 +02:00
Stephane Nicoll 94f52bc94f Upgrade to Artifactory Resource 0.0.17 2022-03-30 13:13:31 +02:00
Stephane Nicoll d4478bafa4 Upgrade Java versions in CI image 2022-03-30 13:12:08 +02:00
Stephane Nicoll 136e6db822 Upgrade Ubuntu version in CI images 2022-03-30 13:11:18 +02:00
Stephane Nicoll 8f1f68377d Upgrade Java versions in CI image 2022-01-27 09:54:40 +01:00
Sam Brannen ce2367a76f Upgrade to Log4j2 2.17.1 2022-01-03 11:33:22 +01:00
Spring Builds acf782347f Next development version (v5.2.20.BUILD-SNAPSHOT) 2021-12-16 09:38:42 +00:00
Stephane Nicoll 1a03ffef62 Upgrade to Log4j2 2.16.0 2021-12-15 09:49:30 +01:00
Juergen Hoeller e954d7fc20 Upgrade to AspectJ 1.9.7, Groovy 2.5.15, BlockHound 1.0.6, SLF4J 1.7.32 2021-12-14 18:19:49 +01:00
Juergen Hoeller ec13a3f1ba Backported clarifications for SchedulerFactoryBean and cache annotations
See gh-27709
See gh-27726
2021-12-14 18:19:17 +01:00
Juergen Hoeller 842f5b354d Declare serialVersionUID on DefaultAopProxyFactory
Closes gh-27784
2021-12-14 18:17:03 +01:00
Juergen Hoeller 67a4b63d42 Avoid NPE against null value from toString call
Closes gh-27782
2021-12-14 18:16:52 +01:00
Juergen Hoeller 354dad615b Avoid early initialization of empty interceptor names
Closes gh-12238
2021-12-14 18:16:35 +01:00
Stephane Nicoll 0668323176 Upgrade to Log4j2 2.15.0 2021-12-10 15:12:57 +01:00
Sam Brannen e03e62c76a Test status quo for null in varargs in SpEL expressions
This commit also points out that `null` supplied as a single value for
a varargs array of type Optional will be kept as `null` instead of being
converted to Optional.empty(); whereas, if more than one value is passed
to such a varargs array a null value will be properly converted to
Optional.empty().

See gh-27719
2021-12-10 11:18:10 +01:00
Rossen Stoyanchev 96a7fc693b Apply LogFormatUtils in more places 2021-12-09 16:07:20 +00:00
Rossen Stoyanchev 50f6db2704 Replace both EOL and control characters 2021-12-08 13:41:45 +00:00
Arjen Poutsma 24ebb5ecd5 Use ByteArrayDecoder in DefaultClientResponse::createException
This commit changes DefaultClientResponse::createException to use
the ByteArrayDecoder, instead of converting to DataBuffers and
turning these into a byte array.

Closes gh-27666
2021-11-10 17:09:55 +01:00
Juergen Hoeller a439a83f34 Polishing 2021-11-09 23:01:46 +01:00
Juergen Hoeller f0de3a9924 Recommend ObjectProvider as alternative to @Lazy for optional dependencies
Closes gh-27649
2021-11-09 23:01:31 +01:00
Stephane Nicoll 17c3976bca Upgrade to Reactor Dysprosium-SR25
Closes gh-27635
2021-11-09 19:40:59 +01:00
Sam Brannen 9c4a33e64c Increase the likelihood that timed tests pass on CI server 2021-11-05 13:29:06 +01:00
Stephane Nicoll dd3ae4e63d Start building against Reactor Dysprosium-SR25 snapshots
See gh-27635
2021-11-04 14:51:52 +01:00
Sam Brannen dfc435d045 Return previous value in UndertowHeadersAdapter's remove() method
Prior to this commit, UndertowHeadersAdapter's remove() method violated
the java.util.Map contract by always returning null.

This commit fixes this by returning the previous list stored under the
specified key, and otherwise returning null if no previous value was
present.

Closes gh-27592
2021-10-22 14:59:57 +02:00
Sam Brannen 78a24c0dd1 Update "Reporting a Vulnerability" link 2021-10-20 14:50:19 +02:00
Sam Brannen 2bec54e7b3 Fix Javadoc in [NamedParameter]JdbcOperations.queryForObject methods
This commit fixes the Javadoc in all queryForObject(...) methods in
JdbcOperations and NamedParameterJdbcOperations regarding what kinds of
exceptions are thrown under which conditions.

Closes gh-27559

(cherry picked from commit 0853baaa3f)
2021-10-19 18:38:17 +02:00
Rossen Stoyanchev 52e2953de9 Fix checkstyle warning
See gh-27569
2021-10-18 17:09:46 +01:00
Rossen Stoyanchev 7b149a68c6 Fix assertion message in DefaultDataBuffer
Closes gh-27567
2021-10-18 16:57:12 +01:00
Smile d1b3b8eaf6 Update Javadoc in DefaultResponseErrorHandler
Closes gh-27569
2021-10-18 16:28:19 +01:00
Spring Builds f94794e5c0 Next development version (v5.2.19.BUILD-SNAPSHOT) 2021-10-14 10:25:19 +00:00
Rossen Stoyanchev 26af506441 DefaultResponseErrorHandler shows full error details
Closes gh-27552
2021-10-13 21:21:38 +01:00
Juergen Hoeller b14a940716 Polishing 2021-10-13 13:00:53 +02:00
Juergen Hoeller 4ecbf6511d Remove dead fallback code 2021-10-13 12:52:38 +02:00
Juergen Hoeller 5b6a32d1b9 Polishing 2021-10-12 16:18:41 +02:00
Juergen Hoeller 263244f637 Avoid expensive isReadable() check during classpath scan
Closes gh-27541
See gh-21372
2021-10-12 16:18:21 +02:00
Juergen Hoeller 3a166ea742 Add efficient existence check to ClassPathResource.isReadable()
Includes reduced isReadable() check in PathResourceLookupFunction, aligned with PathResourceResolver.

Closes gh-27538
See gh-21372
2021-10-12 16:18:09 +02:00
Sam Brannen 6d4dfed772 Introduce test for gh-27499 and polish contribution 2021-10-12 13:19:13 +02:00
Nick 09ef597836 Avoid duplicate JCacheOperationSource bean registration in <cache:annotation-driven />
In our application we use XML context and <cache:annotation-driven />
declaration. Also we disable bean definition duplication by setting
GenericApplicationContext.setAllowBeanDefinitionOverriding(false) in an
ApplicationContextInitializer. This combination leads to a
BeanDefinitionOverrideException because the
DefaultJCacheOperationSource bean is registered twice.

 - once for: parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
 - once for: parserContext.registerBeanComponent(new BeanComponentDefinition(sourceDef, sourceName));

This commit refactors JCacheCachingConfigurer.registerCacheAspect(...)
so that the JCacheOperationSource bean is registered only once.

Closes gh-27499
2021-10-12 13:19:13 +02:00
Sam Brannen 50920e1a96 Upgrade to Reactor Dysprosium-SR24
Closes gh-27526
2021-10-12 13:19:13 +02:00
Stephane Nicoll 8c4d1d4d29 Upgrade CI to github-release resource 1.5.5
Closes gh-27460
2021-10-11 16:20:35 +02:00
Rossen Stoyanchev 82f8d0dfd7 Apply value formatting to resolved exceptions 2021-10-11 11:15:59 +01:00
Stephane Nicoll 38f616a8e8 Start building against Reactor Dysprosium-SR23 snapshots
See gh-27526
2021-10-07 08:52:40 +02:00
Rossen Stoyanchev 441c4d5d5c Generalize formatValue
Provide an overload for additional control and compact output.
2021-10-06 21:31:02 +01:00
Sam Brannen 66f4d20fd4 Comment out unused fudgeFactor 2021-10-05 14:22:51 +02:00
Rossen Stoyanchev 2fa44d62b9 ResponseStatusExceptionHandler logs exception message only
No need to log the full exception for a resolved exception, and as the
comment suggests that it mirrors Spring MVC equivalent, which also
logs the message only.
2021-10-05 12:13:39 +01:00
Stephane Nicoll c86ac97267 Upgrade to GitHub Changelog Generator 0.0.7 in CI
Closes gh-27513
2021-10-03 07:10:06 +02:00
Juergen Hoeller fd916baf79 Skip all flaky StopWatch time assertions 2021-10-02 12:09:01 +02:00
Juergen Hoeller 790d56dd18 Backported tests for bean-derived (Auto)Closeable.close() method
See gh-27504
2021-10-01 13:47:58 +02:00
Sam Brannen 5a5f118efc Escape closing curly braces in regular expressions for Android support
PR gh-24470 introduced a regression for Android users by no longer
escaping closing curly braces in regular expressions.

This commit therefore partially reverts the changes made in 273812f9c5
for closing curly braces (`}`).

Closes gh27467
2021-10-01 10:56:00 +02:00
Juergen Hoeller edf664c1cf Defensively handle fast class generation failure for individual methods
Includes rethrowing of last actual defineClass exception encountered.

Closes gh-27490
2021-09-30 18:00:10 +02:00
Juergen Hoeller 137bca129f Skip flaky StopWatch time assertions 2021-09-27 17:43:25 +02:00
Juergen Hoeller b01a3aeb6b Fix invalid characters in source files
Closes gh-27475
2021-09-27 17:42:27 +02:00
Juergen Hoeller 195d375964 Polishing 2021-09-24 13:49:48 +02:00
Juergen Hoeller ebd351753f Fix contract violations in ConcurrentReferenceHashMap's EntrySet/Iterator
Closes gh-27454

(cherry picked from commit 208fafa4a3)
2021-09-24 13:41:35 +02:00
Juergen Hoeller 9524ecd5b0 Log rejected listener container tasks at warn level
Closes gh-27451
2021-09-24 13:30:50 +02:00
Spring Builds 9053613a65 Next development version (v5.2.18.BUILD-SNAPSHOT) 2021-09-15 08:10:53 +00:00
Stephane Nicoll 0aa7ba80e1 Migrate to Spring Builds account 2021-09-15 09:07:14 +02:00
Stephane Nicoll 9a05a8846b Fix GitHub credentials to use token rather than password
Closes gh-27403
2021-09-15 08:42:30 +02:00
Juergen Hoeller fb97a126a5 Defensive handling of dimensions nullability 2021-09-14 21:54:42 +02:00
Sam Brannen 1ad5b4fbd6 Support char primitive default values in BeanUtils.instantiateClass()
Closes gh-27390
2021-09-14 16:17:46 +02:00
Sam Brannen 4d1cdf6379 Introduce test for gh-27390 2021-09-14 16:17:36 +02:00
takeaction21 e1ba3e7dbb Support float and double primitive default values in BeanUtils.instantiateClass()
See gh-27390
2021-09-14 16:13:36 +02:00
Rossen Stoyanchev 2b55b9ccd5 Do not log request parameters for multipart requests
Closes gh-27350
2021-09-14 13:41:15 +01:00
Brian Clozel 90bcb2e375 Upgrade to Reactor Dysprosium-SR23
Closes gh-27378
2021-09-14 13:49:51 +02:00
Juergen Hoeller 9ad3464c80 Reduce log statement for non-unique JavaBean property to debug level
Closes gh-27372

(cherry picked from commit 6c17e9375b)
2021-09-13 18:47:27 +02:00
Stephane Nicoll 1954a22c23 Fix bug fix icon in changelog configuration
Closes gh-27385
2021-09-11 00:01:46 +02:00
Brian Clozel bd90c4d0f0 Switch to Reactor Dysprosium SNAPSHOTs
See gh-27378
2021-09-09 19:06:25 +02:00
Juergen Hoeller e31d66cd2b Polishing (backported from 5.3.x) 2021-09-02 23:18:36 +02:00
Juergen Hoeller eb349be1fc Fix Kotlin example for filtering handler functions
Closes gh-27337
2021-09-02 23:08:27 +02:00
Juergen Hoeller 4b3e8619ec Polishing 2021-09-02 22:53:30 +02:00
Juergen Hoeller 50d597eb41 Avoid unnecessary cause initialization in ResponseStatusException
Closes gh-27196
2021-09-02 22:52:14 +02:00
Juergen Hoeller 9c931f669c Convenient configuration of type permissions for XStream 1.4.18
Closes gh-27343

(cherry picked from commit 837301fdb3)
2021-09-02 22:49:09 +02:00
Sam Brannen b7e6169e12 Update copyright date 2021-08-31 09:46:29 +02:00
Inmord 9c204dc475 Polish AbstractAspectJAdvisorFactory
Closes gh-27340
2021-08-31 09:40:28 +02:00
Sam Brannen 21c0e50b33 Document when prepareTestInstance() is invoked by the SpringMethodRule
Closes gh-27305
2021-08-22 16:02:57 +02:00
Sam Brannen cecd2ee2e6 Polishing 2021-08-22 14:40:55 +02:00
Sam Brannen 97a89d6db9 Polish contribution
See gh-27303
2021-08-22 14:39:24 +02:00
Erik van Paassen 10a90d3204 Fix UrlPathHelper#shouldRemoveSemicolonContent() (#27303)
The checkReadOnly() method should only be called from
methods that modify properties to prevent modification
of read-only instances.

Fixes #27256
2021-08-22 14:30:46 +02:00
Sam Brannen ab2a861163 Fix and document CompositeUriComponentsContributor#hasContributors()
Prior to this commit, the hasContributors() method incorrectly returned
false if contributors had been configured.

This commit fixes the logic in hasContributors() and documents it.

Closes #27271
2021-08-18 17:35:50 +02:00
Sam Brannen f56d6ea1fb Avoid StringIndexOutOfBoundsException in WebSocketMessageBrokerStats
Prior to this commit, if the TaskExecutor configured in
WebSocketMessageBrokerStats for the inboundChannelExecutor or
outboundChannelExecutor was not a ThreadPoolTaskExecutor, a
StringIndexOutOfBoundsException was thrown when attempting to parse the
results of invoking toString() on the executor.

The reason is that ThreadPoolTaskExecutor delegates to a
ThreadPoolExecutor whose toString() implementation generates text
containing "pool size = ...", and WebSocketMessageBrokerStats'
getExecutorStatsInfo() method relied on the presence of "pool" in the
text returned from toString().

This commit fixes this bug by ensuring that the text returned from
toString() contains "pool" before parsing the text. If "pool" is not
present in the text, getExecutorStatsInfo() now returns "unknown"
instead of throwing a StringIndexOutOfBoundsException.

Closes gh-27209
2021-07-26 11:50:27 +02:00
Spring Buildmaster 420aa9bef0 Next development version (v5.2.17.BUILD-SNAPSHOT) 2021-07-14 08:00:09 +00:00
Stephane Nicoll 14adefa867 Remove coroutines links until the javadoc publication is fixed
See gh-27169
2021-07-14 07:48:42 +02:00
Juergen Hoeller fe3357d6b9 Polishing (backported) 2021-07-13 19:07:15 +02:00
Juergen Hoeller 11c51d8633 Upgrade to Reactor Dysprosium-SR21
Closes gh-27163
2021-07-13 19:06:22 +02:00
Juergen Hoeller bdbd999619 Make proxyTargetClass=true with introduction advice work for JDK proxy targets
Closes gh-27044

(cherry picked from commit c45c46dad7)
2021-07-13 18:34:49 +02:00
Juergen Hoeller bc4af15e9e BeanCreationException message includes declaring class of constructor/factory method
Closes gh-27139

(cherry picked from commit 74f91339e2)
2021-07-13 18:34:42 +02:00
Stephane Nicoll 348dc826f9 Fix CI build badge in README 2021-07-12 09:51:51 +02:00
Sam Brannen 43901b2c6a Fix bug in SimpleMethodMetadataReadingVisitor.Source.toString()
Prior to this commit, the toString() implementation did not separate
method argument types with a comma or any form of separator, leading
to results such as:

    org.example.MyClass.myMethod(java.lang.Stringjava.lang.Integer)

instead of:

    org.example.MyClass.myMethod(java.lang.String,java.lang.Integer)

Closes gh-27095
2021-06-24 16:46:52 +02:00
Arjen Poutsma 7b34bf2a6c Synchronoss should create temp directory lazily
The SynchronossPartHttpMessageReader should only create temp directory
when needed, not at startup.

Closes gh-27092
2021-06-23 16:04:08 +02:00
Sam Brannen c5a138a167 Ensure DefaultPathSegment does not allow parameters to be mutated
Prior to this commit, if a PathContainer was created using
Options.MESSAGE_ROUTE, DefaultPathSegment#parameters() returned a
mutable map which would allow the user to modify the contents of the
static, shared EMPTY_PARAMS map in DefaultPathContainer.

This commit prevents corruption of the shared EMPTY_PARAMS map by
ensuring that parameters stored in DefaultPathSegment are always
immutable.

Closes gh-27064
2021-06-15 15:57:35 +02:00
Sam Brannen 1f098e1f22 Polish DefaultPathContainerTests 2021-06-15 15:51:21 +02:00
Juergen Hoeller 67fccc3c7e Nullability refinements and related polishing (backported) 2021-06-08 14:58:58 +02:00
Sam Brannen 70e6606f0f Improve @Transactional docs regarding method visibility
Closes gh-27003
2021-05-30 17:16:08 +02:00
Sviatoslav Hryb 5b55cefd64 Fix @Transactional docs regarding method visibility
Closes gh-27001
2021-05-30 17:13:14 +02:00
Sam Brannen 911aca17ea Doc tx semantics for @TransactionalEventListener after completion phases
This commit improves the Javadoc regarding transactional semantics for
@TransactionalEventListener methods invoked in the AFTER_COMMIT,
AFTER_ROLLBACK, or AFTER_COMPLETION phase. Specifically, the
documentation now points out that interactions with the underlying
transactional resource will not be committed in those phases.

Closes gh-26974
2021-05-26 14:27:16 +02:00
Sam Brannen 90183568ba Deprecate internal APIs in ScriptUtils
Many of the utility methods in ScriptUtils are public only because they
were once invoked from JdbdTestUtils in spring-test, which is no longer
the case. Consequently, there should no longer be a need for any
external clients to invoke such methods.

To address, this commit formally deprecates the following methods in
ScriptUtils in spring-jdbc.

- readScript(...)
- containsSqlScriptDelimiters(...)
- splitSqlScript(...)

Closes gh-26947
2021-05-18 15:59:57 +02:00
Sam Brannen b5ce514b27 Logically reorganize methods in ScriptUtils
See gh-26947
2021-05-18 15:47:39 +02:00
Sam Brannen 9ae6268a1a Polish ScriptUtils implementation 2021-05-14 15:18:26 +02:00
Sam Brannen e4d843e41e Ignore comments when searching for statement delimiter in ScriptUtils
Prior to this commit, the implementation of
ScriptUtils.containsSqlScriptDelimiters() did not ignore comments when
searching for the statement delimiter within an SQL script. This
resulted in subtle bugs if a comment contained a single single-quote or
single double-quote, since the absence of the closing single-quote or
double-quote led the algorithm to believe that it was still "within a
text literal". Similar issues could arise if a comment contained the
sought statement delimiter but the rest of the script did not contain
the sought statement delimiter. In such cases, the algorithms in
ScriptUtils could erroneously choose an incorrect statement delimiter
-- for example, using the fallback statement delimiter instead of the
delimiter specified by the user.

This commit avoids such bugs by ignoring single-line comments and block
comments when searching for the statement delimiter within an SQL
script.

Closes gh-26911
2021-05-14 14:33:07 +02:00
Sam Brannen 22256966fb Ignore delimiter enclosed in double quotes in ScriptUtils
Prior to this commit, the containsSqlScriptDelimiters() method in
ScriptUtils ignored delimiters enclosed in single quotes but not those
enclosed within double quotes, which contradicts the algorithm in
splitSqlScript() and therefore constitutes a bug.

This commit fixes this bug in the ScriptUtils implementation in
spring-jdbc.

Closes gh-26935
2021-05-12 13:06:00 +02:00
Spring Buildmaster 7c74459cb0 Next development version (v5.2.16.BUILD-SNAPSHOT) 2021-05-12 06:16:21 +00:00
Arjen Poutsma 85ad63bd35 Ensure Synchronoss temp directories do not collide
This commit makes sure that Synchronoss uses a random temporary
directory to store uploaded files, so that two instances do not collide.

Closes gh-26931
2021-05-11 21:19:27 +02:00
Juergen Hoeller a2ff769bc1 Polishing (backported from master) 2021-05-11 17:32:23 +02:00
Juergen Hoeller 9523f1ffd6 Correct clientInboundChannel assertion (includes constructor javadoc)
Closes gh-26896
2021-05-11 17:31:04 +02:00
Juergen Hoeller cd0570ee39 Log resource path resolution failure at debug level (instead of warn)
Closes gh-26828
2021-05-11 17:30:57 +02:00
Juergen Hoeller 05d767b1cf Always propagate checked exceptions from Kotlin code behind CGLIB proxies
Closes gh-23844
2021-05-11 17:29:40 +02:00
Stephane Nicoll 30655555bd Remove .RELEASE suffix before querying GitHub
This commit removes the `.RELEASE` suffix of the released version, if
necessary. Such commit is not present on GitHub and the changelog
generation process fails to find the milestone to use to generate the
changelog.

Closes gh-26796
2021-05-11 16:20:28 +02:00
Stephane Nicoll 0ee8790a9a Upgrade to Reactor Dysprosium-SR20
Closes gh-26891
2021-05-11 15:35:50 +02:00
Sam Brannen bcd8896689 Polish contribution
See gh-25200
2021-05-10 12:50:13 +02:00
Vlad Kisel 53b8d73078 Support single-value request param resolution for data class constructors
Prior to this commit, when Web MVC attempted to resolve a constructor
argument for a data class constructor with @ModelAttribute binding,
ModelAttributeMethodProcessor failed to unwrap the array returned by
WebRequest.getParameter(String).

According to the Javadoc for WebRequest.getParameter(String), "a
single-value parameter will be exposed as an array with a single
element."

This commit fixes this issue by extracting the single value from such
an array and using that as the constructor argument (potentially
converted by the WebDataBinder).

Closes gh-25200
2021-05-10 12:47:47 +02:00
ShindongLee 3ab270e0f1 Fix parameter bug of handler inside the filterFunction DSL
Co-authored-by: hojongs <hojong.jjh@gmail.com>
Co-authored-by: bjh970913 <bjh970913@gmail.com>

Closes gh-26921
2021-05-10 10:22:13 +02:00
Rossen Stoyanchev ddb727bee8 Switch to Reactor Dysprosium snapshots
See gh-26891
2021-05-04 17:12:19 +01:00
Sam Brannen a33adac6c8 Support @ModelAttribute(binding=false) with WebFlux
Prior to this commit, @ModelAttribute(binding=false) was honored with
Spring Web MVC but not with WebFlux.

This commit adds support for disabling binding via @ModelAttribute with
WebFlux by adding a check to resolveArgument(...) in
ModelAttributeMethodArgumentResolver.

Closes gh-26856
2021-05-03 19:13:16 +02:00
Sam Brannen 08663d4792 Polish Javadoc 2021-05-03 18:58:12 +02:00
Stephane Nicoll 30b5a7b5c3 Backport "Remove leftover Javadoc from WebClient"
Closes gh-26809
2021-04-15 09:57:21 +02:00
Spring Buildmaster 620023cbc3 Next development version (v5.2.15.BUILD-SNAPSHOT) 2021-04-13 11:46:36 +00:00
Juergen Hoeller 19474e2d03 Nullability refinements
(cherry picked from commit f31933e67e)
2021-04-13 12:32:16 +02:00
Juergen Hoeller 43071109f7 Polishing (backported from master) 2021-04-13 11:48:55 +02:00
Juergen Hoeller bb530dca5b Polishing (backported from master) 2021-04-12 23:39:24 +02:00
Juergen Hoeller e4e2212817 Bypass root path resolution for "file:" prefix only
See gh-26702
2021-04-12 23:39:18 +02:00
Stephane Nicoll 34fcbfbcc5 Upgrade to Reactor Dysprosium-SR19
Closes gh-26768
2021-04-12 18:09:16 +02:00
Stephane Nicoll 20cbd684d4 Start building against Reactor Dysprosium SR19 snapshots
See gh-26768
2021-04-07 09:52:32 +02:00
Brian Clozel 5f9a6ce98e Upgrade to Concourse Release Scripts 0.3.2 2021-03-23 13:58:04 +01:00
Juergen Hoeller 07e18df0b9 Polishing 2021-03-22 23:14:20 +01:00
Sam Brannen 4a6fea353f Honor class-level @DirtiesContext if test class is disabled via SpEL
Prior to this commit, if a test class annotated with @DirtiesContext
and @EnabledIf/@DisabledIf with `loadContext = true` was disabled due
to the evaluated SpEL expression, the ApplicationContext would not be
marked as dirty and closed.

The reason is that @EnabledIf/@DisabledIf are implemented via JUnit
Jupiter's ExecutionCondition extension API which results in the entire
test class (as well as any associated extension callbacks) being
skipped if the condition evaluates to `disabled`. This effectively
prevents any of Spring's TestExecutionListener APIs from being invoked.
Consequently, the DirtiesContextTestExecutionListener does not get a
chance to honor the class-level @DirtiesContext declaration.

This commit fixes this by implementing part of the logic of
DirtiesContextTestExecutionListener in
AbstractExpressionEvaluatingCondition (i.e., the base class for
@EnabledIf/@DisabledIf support). Specifically, if the test class for an
eagerly loaded ApplicationContext is disabled,
AbstractExpressionEvaluatingCondition will now mark the test
ApplicationContext as dirty if the test class is annotated with
@DirtiesContext.

Closes gh-26694
2021-03-18 14:21:05 +01:00
Brian Clozel f76504512e Fix release pipeline for Maven Central publication
This commit fixes the missing pieces in our Maven Central publication
pipeline. Our first attempt at releasing with it showed a few problems:

* the promote task did not have the artifacts downladed with the
  artifactory repository
* we applied the wrong Sonatype credentials to the task
* the github changelog task would fail because of docker rate limiting
  since we were not using the right type of resource, which is
  configured with the proper caching mechanism

See gh-26654
2021-03-16 14:34:10 +01:00
Juergen Hoeller 215514f27b Polishing (backported from master) 2021-03-12 15:29:29 +01:00
Juergen Hoeller ae2711866a Polishing 2021-03-12 11:07:19 +01:00
Juergen Hoeller a6ab7164a3 Use getRawStatusCode() for custom status code support in value methods
Closes gh-26658
2021-03-12 10:50:55 +01:00
Brian Clozel a7db92b44e Use ".RELEASE" suffix for releases on 5.2.x branch
This commit ensures that the release scripts generate a ".RELEASE"
suffixed release version, since the 5.2.x branch is still using this
naming scheme.

See https://github.com/spring-io/concourse-java-scripts#get_next_release
See gh-26659
2021-03-11 10:04:22 +01:00
Stephane Nicoll 63912f802a Merge branch 'ci' into 5.2.x
Closes gh-26659
2021-03-10 15:10:49 +01:00
Stephane Nicoll 3fbf3a597a Backport CI build
See gh-26659
2021-03-10 14:57:06 +01:00
Stephane Nicoll 5291c5b233 Remove artifactory plugin from build
Backport of gh-22490

See gh-26659
2021-03-10 14:57:06 +01:00
Juergen Hoeller c978fb4466 Documentation fixes etc (backported from master) 2021-03-09 16:57:04 +01:00
Juergen Hoeller 0fc831e8bd Polishing (backported from master) 2021-03-09 00:05:55 +01:00
Rossen Stoyanchev dd967215fe Upgrade to RSocket 1.0.4 2021-03-04 22:18:11 +00:00
Sam Brannen 31c5fc6417 Polish contribution
See gh-26619
2021-03-02 14:28:01 +01:00
GungnirLaevatain e8f685ecc8 Ensure local @CrossOrigin maxAge overrides global value
Prior to this commit, a method-level @CrossOrigin maxAge value did not
override a class-level @CrossOrigin maxAge value. This contradicts the
Javadoc for @CrossOrgin which states the following.

    For those attributes where only a single value can be accepted such
    as allowCredentials and maxAge, the local overrides the global
    value.

This commit ensures that a method-level @CrossOrigin maxAge value
overrides a class-level @CrossOrigin maxAge value.

Closes gh-26619
2021-03-02 14:27:49 +01:00
Juergen Hoeller 428dbc43da Add missing nullable annotation to ResponseEntity ok convenience method
Closes gh-26613
2021-02-26 17:42:05 +01:00
Juergen Hoeller dd3262bfe3 Polishing (backported from master) 2021-02-25 19:08:53 +01:00
Juergen Hoeller fdafd38d2f Fix handling of file: paths to non-existent files
For setAsText, if the text argument is a file: URL for a path that does not exist, Paths.get(text) is called where text is a file: URL, which doesn't work - the result is an InvalidPathException.

To fix this issue, also check that the resource isn't a file before calling Paths.get(). That way, resources that are files skip to the other branch.

Closes gh-26575
2021-02-25 19:08:18 +01:00
Juergen Hoeller 74b248a6b3 getResource can throw IllegalArgumentException
Class.getResource, ClassLoader.getResource, and ClassLoader.getSystemResource will throw IllegalArgumentException if a malformed URL is provided to them.

According to its javadoc, resolveURL should return null if not resolvable, so catch the IllegalArgumentException and return null.

Closes gh-26574
2021-02-25 19:07:58 +01:00
Sam Brannen 60e418959a Polish contribution
See gh-26600
2021-02-25 11:43:10 +01:00
nullzl 4530e36867 Correctly set auto-growing array's element
Prior to this commit, the implementation of processKeyedProperty() in
AbstractNestablePropertyAccessor resulted in a
`java.lang.IllegalArgumentException: array element type mismatch` when
the property expression had more than one property key and the last key
should cause the array to grow automatically.

For example, given a property `int[][] multiArray` and property
expression `multiArray[1][3]`, the `processKeyedProperty()` method
created a new array object and assigned it to `multiArray`; whereas,
the new array object should have be assigned to `multiArray[1]`.

This commit fixes this issue.

Closes gh-26600
2021-02-25 11:42:56 +01:00
Sam Brannen 2ec7d5c785 Support load-time weaving for @Component classes again
Since Spring Framework 5.2, the LoadTimeWeaver no longer weaves bean
classes annotated with @Component. This is a regression caused by the
changes in 40c62139ae, stemming from the fact that any class annotated
or meta-annotated with @Component is considered to be a candidate
configuration class in 'configuration lite' mode (i.e., a class without
the @Configuration annotation and without any @Bean methods) and
therefore now has its class eagerly loaded. This results in the class
being loaded before the LoadTimeWeaver has a chance to weave it.

This commit fixes this regression by explicitly avoiding eager class
loading for any 'lite' @Configuration or @Component class without @Bean
methods.

Closes gh-26199
2021-02-22 10:28:58 +01:00
Brian Clozel 9f7c8aea94 Fix ResourceUrlProvider handler auto-detection
Prior to this commit, `ResourceUrlProvider` would listen and consider
all `ContextRefreshedEvent` and use the given context to detect
`SimpleUrlHandlerMapping`.

This could lead to situations where a `ResourceUrlProvider` uses another
application context than its own (in a parent/child context setup) and
detect the wrong set of handlers.

Because `ResourceUrlProvider` locks itself once the auto-detection is
done, we need to ensure that it considers only events sent by its
application context.

Fixes gh-26562
2021-02-17 22:10:29 +01:00
Sam Brannen 792656097a Polish MockHttpServletResponseTests
See gh-26558
2021-02-17 14:51:19 +01:00
Sam Brannen 33add3350b Sync changes in MockHttpServletResponse test fixture
See gh-26558
2021-02-17 14:51:09 +01:00
Koos Gadellaa 8f2010d669 Support cookie w/ only Expires attribute in MockHttpServletResponse
Prior to this commit, MockHttpServletResponse only included the Expires
attribute in the generated Cookie header if the Max-Age attribute had
also been set.

This commit supports including the Expires attribute in the generated
Cookie Header even when the Max-Age attribute has not been set.

Closes gh-26558
2021-02-17 14:50:59 +01:00
Sam Brannen 9d4bfb1769 Implement toString() in MockCookie 2021-02-17 14:50:39 +01:00
Spring Buildmaster da5f410af4 Next Development Version 2021-02-16 11:39:43 +00:00
Juergen Hoeller 940f57d023 Document ASM version as 7.x (effectively 7.3 at present) 2021-02-16 00:15:50 +01:00
Rossen Stoyanchev 29799be474 Upgrade to Dysprosium-SR17
Closes gh-26549
2021-02-15 17:33:30 +00:00
Juergen Hoeller 67979c93c3 Upgrade to Hibernate ORM 5.4.28 and OpenPDF 1.3.25 2021-02-15 17:34:29 +01:00
Juergen Hoeller 4ae3ab14ec Avoid unnecessary wrapping for SqlParameterValue
Closes gh-26471
2021-02-15 11:49:59 +01:00
Juergen Hoeller 81f0d76f3d Upgrade to Apache Johnzon 1.2.10, Joda-Time 2.10.10, RxJava 2.2.21 2021-02-14 18:49:33 +01:00
Juergen Hoeller 9f1e822f3e Polishing 2021-02-14 18:48:49 +01:00
Juergen Hoeller b4baa86bfa Close mapping streams after the ValidatorFactory has been built
Closes gh-26418
2021-02-14 18:48:31 +01:00
Juergen Hoeller 81be4c22d0 Re-resolve cached arguments in case of NoSuchBeanDefinitionException
Closes gh-26517

(cherry picked from commit 99a1388bbd)
2021-02-14 18:17:06 +01:00
Juergen Hoeller a17c2ccb4e Preserve resolved destroy method name in RootBeanDefinition
Closes gh-26498

(cherry picked from commit 809813dd52)
2021-02-14 18:16:11 +01:00
Juergen Hoeller 64df93168d Consider non-initialized holders as equal to empty holders
Closes gh-26433

(cherry picked from commit d5e5dcb7e1)
2021-02-14 18:08:20 +01:00
Juergen Hoeller 27c5480c82 Fail early FactoryBean instantiation for LinkageError
Closes gh-26425

(cherry picked from commit defc2466b0)
2021-02-14 18:08:15 +01:00
Sam Brannen 594ec8f8a9 Update copyright date in reference manual 2021-02-10 17:57:23 +01:00
Arjen Poutsma c09b2513e0 Ensure StringDecoder supports multiline delimiters
This commit makes sure the StringDecoder supports stripping off
multi-line delimiters, such as \r\n. Specifically, we ensure that the
delimiter is stripped from the joined buffer.

Closes gh-26511
2021-02-08 15:59:02 +01:00
Sam Brannen 6c22f7ef5e Fix StoredProcedure documentation in reference manual
This commit aligns the documentation in the reference manual with the
actual source code for StoredProcedure with regard to public execute()
methods.

Closes gh-26505
2021-02-04 11:12:31 +01:00
Sam Brannen 236623f630 Do not retain partial column metadata in SimpleJdbcInsert
Prior to this commit, if an SQLException was thrown while retrieving
column metadata from the database, SimpleJdbcInsert would generate an
INSERT statement that was syntactically valid but missing columns,
which could lead to data silently missing in the database (for nullable
columns).

This commit fixes this by clearing all collected column metadata if an
SQLException is thrown while processing the metadata. The result is
that an InvalidDataAccessApiUsageException will be thrown later while
generating the INSERT statement. The exception message now contains an
additional hint to make use of SimpleJdbcInsert#usingColumns() in order
to ensure that all required columns are included in the generated
INSERT statement.

SimpleJdbcCall can also encounter an SQLException while retrieving
column metadata for a stored procedure/function, but an exception is
not thrown since a later invocation of the stored procedure/function
will likely fail anyway due to missing arguments. Consequently, this
commit only improves the warning level log message by including a hint
to make use of SimpleJdbcCall#addDeclaredParameter().

Closes gh-26486
2021-02-03 18:53:32 +01:00
Sam Brannen e18fba1626 Polishing 2021-02-03 18:52:15 +01:00
Sam Brannen 070c596a66 Use api-spring-framework attribute for links to SpringProperties
See gh-26492
2021-02-02 14:04:20 +01:00
Sam Brannen 7a9bf1578e Link to SpringProperties Javadoc from the Testing chapter
Closes gh-26492
2021-02-02 13:52:08 +01:00
Rossen Stoyanchev 8a150ee3a4 Fix order of headers in DefaultHandlerExceptionResolver
Closes gh-26470
2021-01-29 20:49:19 +00:00
Rossen Stoyanchev 6051f4ecbd Handle forwarded header parse issues
Closes gh-26459
2021-01-29 20:48:51 +00:00
Rossen Stoyanchev 698e74f7cd WebSocketExtension#equals matches sub-classes too
Closes gh-26449
2021-01-29 20:48:51 +00:00
Sam Brannen 51079a40ae Upgrade io.spring.ge.conventions plugin to version 0.0.7
This will hopefully allow the build to pass again on the CI server.
2021-01-27 18:09:13 +01:00
Sam Brannen 94ac2e4de7 Fix UriComponentsBuilder examples in ref docs
Closes gh-26453
2021-01-27 15:17:32 +01:00
Stephane Nicoll 271a9097ac Clarify behaviour of condition attribute of CachePut
Closes gh-26404
2021-01-19 15:15:38 +01:00
Juergen Hoeller 3c030edbf2 Upgrade to RxJava 2.2.20, OpenPDF 1.3.24, Hibernate ORM 5.4.27, Joda-Time 2.10.9, Apache Johnzon 1.2.9 2021-01-14 18:30:52 +01:00
Sam Brannen 059cff52b7 Remove obsolete commandName attribute in spring-form.tld
Since support for the commandName attribute was removed from the
implementation of FormTag in Spring Framework 5.0, the presence of the
commandName attribute in the spring-form.tld file is no longer valid
and can lead one to assume that the commandName attribute is still
supported -- for example when using code completion in a JSP editor.

This commit therefore removes the obsolete commandName attribute in
spring-form.tld.

Closes gh-26337
2021-01-03 17:50:15 +01:00
Sam Brannen 619a3edae5 Fix syntax in Kotlin example 2020-12-19 15:30:42 +01:00
Juergen Hoeller eb3811e590 Upgrade to Hibernate Validator 6.1.7, Caffeine 2.8.8, Joda-Time 2.10.8 2020-12-17 11:06:16 +01:00
Juergen Hoeller f011e58f90 Polishing 2020-12-17 11:05:58 +01:00
Juergen Hoeller 7325a863bb Consistent declarations and assertions in MockMultipartFile
See gh-26261

(cherry picked from commit fbd2ffdd23)
2020-12-17 10:50:47 +01:00
Brian Clozel fe26b7d3fd Fix NPE when calling NettyHeadersAdapter.add()
Prior to this commit, the `NettyHeadersAdapter` would directly delegate
the `add()` and `set()` calls to the adapted
`io.netty.handler.codec.http.HttpHeaders`. This implementation rejects
`null` values with exceptions.

This commit aligns the behavior here with other implementations, by not
rejecting null values but simply ignoring them.

Fixes gh-26277
(cherry-picked from commit 83c19cd60e)
2020-12-15 13:36:03 +01:00
Juergen Hoeller cfdceae70f Defensively handle loadClass null result in BeanUtils.findEditorByConvention
Closes gh-26252

(cherry picked from commit 2a47751fcd)
2020-12-10 16:26:47 +01:00
Spring Buildmaster 17647801aa Next Development Version 2020-12-09 06:34:43 +00:00
Rossen Stoyanchev 33476a2eae Backport fixes for discarding data buffers
Closes gh-26232
2020-12-08 22:00:28 +00:00
Brian Clozel a8091b916b Avoid closing Jackson JsonGenerator for error cases
Prior to this commit, a change introduced in gh-25910 would close the
`JsonGenerator` after it's been used for JSON serialization. This would
not only close it and recycle resources, but also flush the underlyning
buffer to the output.
In a case where the JSON serialization process would throw an exception,
the buffer would be still flushed to the response output. Before the
change introduced in gh-25910, the response body could be still empty at
that point and error handling could write an error body instead.

This commits only closes the `JsonGenerator` when serialization has been
successful.

Note that we're changing this in the spirit of backwards compatibility
in the 5.2.x line, but change this won't be merged forward on the 5.3.x
line, for several reasons:

* this behavior is not consistent. If the JSON output exceeds a
certain size, or if Jackson has been configured to flush after each
write, the response output might still contain an incomplete JSON
payload (just like before this change)

* this behavior is not consistent with the WebFlux and Messaging codecs,
which are flushing or closing the generator

* not closing the generator for error cases prevents resources from
being recycled as expected by Jackson

Fixes gh-26246
2020-12-08 20:50:26 +01:00
Juergen Hoeller 396fdf125f Remove duplicate "property" in PropertyCacheKey.toString()
Closes gh-26237
2020-12-08 15:03:33 +01:00
Stephane Nicoll 085825fbc0 Upgrade to Reactor Dysprosium-SR15
Closes gh-26175
2020-12-08 05:50:48 +01:00
Juergen Hoeller b0c6e5e322 Polishing
(cherry picked from commit c970c318f4)
2020-12-07 22:09:43 +01:00
Juergen Hoeller a7efa9659a Clarify intended advice execution behavior (includes related polishing)
Closes gh-26202

(cherry picked from commit 834032df1f)
2020-12-07 22:09:30 +01:00
Juergen Hoeller f7605eaf58 Upgrade to Hibernate ORM 5.4.25 and Checkstyle 8.38 2020-12-02 17:37:59 +01:00
Juergen Hoeller ce67b89861 Support for multi-threaded addConverter calls
Closes gh-26183

(cherry picked from commit 396fb0cd51)
2020-12-02 12:35:21 +01:00
Rossen Stoyanchev 736af46fc0 ContentCachingResponseWrapper skips contentLength for chunked responses
Closes gh-26182
2020-12-01 17:50:07 +00:00
Stephane Nicoll a495bd6679 Start building against Reactor Dysprosium-SR15 snapshots
See gh-26175
2020-11-30 07:23:19 +01:00
Juergen Hoeller 7c33c70742 Polishing 2020-11-27 21:58:55 +01:00
Juergen Hoeller 81c1b60f19 Register @Bean definitions as dependent on containing configuration class
Closes gh-26167
2020-11-27 21:57:55 +01:00
Rossen Stoyanchev 3703be5aaf MessageHeaderAccessor handle self-copy correctly
1. Revert changes in setHeader from 5.2.9 that caused regression on self-copy.
2. Update copyHeaders/IfAbsent to ensure a copy of native headers.
3. Exit if source and target are the same instance, as an optimization.

Closes gh-26155
2020-11-26 21:56:17 +00:00
Сергей Цыпанов b929edb221 Remove unused package-private class o.s.w.u.p.SubSequence
(cherry picked from commit 42216b77df)
2020-11-26 15:38:14 +01:00
Juergen Hoeller 50803ce142 Remove misleading default note on ISO.DATE_TIME
Closes gh-26134

(cherry picked from commit 86f9716fef)
2020-11-26 15:38:05 +01:00
Sam Brannen 346445ee7e Fix broken links to XSD schemas in ref docs
Closes gh-26129
2020-11-23 14:52:47 +01:00
Juergen Hoeller e238c8a87c Declare resolvedCharset as transient (restoring serializability)
Closes gh-26127
2020-11-20 18:57:30 +01:00
Juergen Hoeller 9e99fd5df2 Upgrade to Hibernate ORM 5.4.24
(cherry picked from commit 135682e073)
2020-11-19 16:03:03 +01:00
Juergen Hoeller 990c74b1e2 Upgrade to Apache HttpClient 4.5.13 (and consistent Caffeine declarations) 2020-11-19 15:19:29 +01:00
Rossen Stoyanchev 37bda566eb Allow "*" for Access-Control-Expose-Headers
Closes gh-26113
2020-11-19 09:48:41 +00:00
Juergen Hoeller 322babc04a Document that @Transactional does not propagate to new threads
Closes gh-25439
2020-11-17 16:16:24 +01:00
Juergen Hoeller 4e720e8104 Encode hash symbol in jar file path (for compatibility with JDK 11+)
Closes gh-26104

(cherry picked from commit b29723623b)
2020-11-17 16:11:07 +01:00
Juergen Hoeller fdab75a1d8 Upgrade to Reactor Dysprosium-SR14, OpenPDF 1.3.23, AssertJ 3.18.1, MockK 1.10.2, Checkstyle 8.37 2020-11-16 21:08:24 +01:00
Juergen Hoeller 240cfb1224 Polishing 2020-11-16 17:50:15 +01:00
Rossen Stoyanchev db2786264b UrlPathHelper.removeJsessionid correctly appends remainder
Closes gh-26079
2020-11-16 11:18:20 +00:00
Juergen Hoeller 763fa98bdf Early log entry for async EntityManagerFactory initialization failure
Closes gh-26093
2020-11-13 17:59:14 +01:00
Sam Brannen 25cbc263f0 Assert same instance returned for cached merged BeanDefinition 2020-11-12 14:58:58 +01:00
Juergen Hoeller 9949a91048 Fix javadoc and assertion glitches 2020-11-12 14:19:12 +01:00
Juergen Hoeller d8b7a593c5 Individually apply the SQL type from each SqlParameterSource argument
Closes gh-26071
2020-11-12 14:18:23 +01:00
Rossen Stoyanchev d3d8f1a487 LimitedDataBufferList adds or raises error
Closes gh-26060
2020-11-10 20:12:38 +00:00
Spring Buildmaster a637f6a27c Next Development Version 2020-11-10 07:09:28 +00:00
Juergen Hoeller e9416b369e Polishing 2020-11-09 18:23:45 +01:00
Juergen Hoeller cde95e1446 Polishing 2020-11-09 13:52:34 +01:00
Sam Brannen da4e37dc1d Do not create intermediate list in MergedAnnotationCollectors.toAnnotationSet()
Prior to this commit, MergedAnnotationCollectors.toAnnotationSet()
created an intermediate ArrayList for storing the results prior to
creating a LinkedHashSet in the finishing step.

Since the creation of the intermediate list is unnecessary, this commit
simplifies the implementation of toAnnotationSet() by using the
Collector.of() factory method that does not accept a `finisher` argument.
The resulting Collector internally uses a `castingIdentity()` function
as the `finisher`.

Closes gh-26031
2020-11-08 15:20:18 +01:00
Rossen Stoyanchev 010d0947c7 Refine logging in StompErrorHandler
Avoid a full stacktrace at ERROR level for a client message that could
not be sent to a MessageChannel.

See gh-26026
2020-11-05 21:51:16 +00:00
Juergen Hoeller 5b06c23a1b Consistent javadoc within SpelCompiler 2020-11-05 18:33:12 +01:00
Juergen Hoeller 7881329cf7 Polishing 2020-11-05 18:18:38 +01:00
Juergen Hoeller 58aa0659cc Suppress NotWritablePropertyException in case of ignoreUnknown=true
Closes gh-25986
2020-11-05 18:15:59 +01:00
Juergen Hoeller dbbedc6c86 Add FullyQualifiedAnnotationBeanNameGenerator.INSTANCE
Closes gh-26025
2020-11-05 18:15:29 +01:00
Juergen Hoeller 09c1e986b9 Upgrade to Hibernate ORM 5.4.23
(cherry picked from commit b815accca9)
2020-11-05 17:54:18 +01:00
Juergen Hoeller 10bff054a9 Reliably refresh metadata for dynamically changing prototype bean class
Closes gh-26019

(cherry picked from commit 412aa06d86)
2020-11-05 17:50:24 +01:00
Sam Brannen e713e0d6d5 Preserve registration order in @ActiveProfiles
With this commit, bean definition profiles declared via @ActiveProfiles
are once again stored in registration order, in order to support use
cases in Spring Boot and other frameworks that depend on the
registration order.

This effectively reverts the changes made in conjunction with gh-25973.

Closes gh-26004
2020-11-02 22:40:59 +01:00
Rossen Stoyanchev b4f8fc8177 Use static accessors in DefaultSimpUserRegistry
Closes gh-26010
2020-11-02 17:32:12 +00:00
Rossen Stoyanchev 8c3cdc6118 Remove unused import 2020-10-30 18:43:19 +00:00
Rossen Stoyanchev 01827fd8d2 Ensure response not closed by MappingJackson2HttpMessageConverter
Closes gh-25987
2020-10-30 18:42:11 +00:00
Stephane Nicoll af1d721aa3 Fix a broken Asciidoctor syntax in core-resources.adoc
Closes gh-26000
2020-10-30 09:33:36 +01:00
Arjen Poutsma 0acb1e5513 Copy default headers, cookies in WebClient builder
This commit makes copies of the default headers and cookies when a
WebClient is built, so that subsequent changes to these do not affect
previously built clients.

Closes: gh-25992
2020-10-29 13:36:26 +01:00
Spring Buildmaster a9dec6a4af Next Development Version 2020-10-27 13:48:52 +00:00
Rossen Stoyanchev bb4e802af5 Full header support HTTP HEAD Resource requests
Allow the body to be written in order for all headers to be set
as they would be on HTTP GET. The body content is ignored as a
lower level.

See gh-25976
2020-10-27 11:14:37 +00:00
Rossen Stoyanchev d91b66a04c Allow Resource to add headers for range requests
Closes gh-25976
2020-10-27 10:15:56 +00:00
Juergen Hoeller b6dae6acba Upgrade to JUnit 5.6.3, Woodstox 6.2.3, BlockHound 1.0.4 2020-10-26 23:20:14 +01:00
Rossen Stoyanchev f50c2caf59 Upgrade to RSocket 1.0.3
Closes gh-25957
2020-10-26 21:42:54 +00:00
Juergen Hoeller d12996a6a8 Polishing 2020-10-26 18:18:33 +01:00
Stephane Nicoll 188a5a086b Upgrade to Reactor Dysprosium-SR13
Closes gh-25946
2020-10-26 17:00:46 +01:00
Sam Brannen 449377908f Fix JUnit 4 to AssertJ migration bugs
The migration from JUnit 4 assertions to AssertJ assertions resulted in
several unnecessary casts from int to long that actually cause
assertions to pass when they should otherwise fail.

This commit fixes all such bugs for the pattern `.isNotEqualTo((long)`.
2020-10-26 14:53:09 +01:00
Sam Brannen c840ba9989 Avoid cache miss for @ActiveProfiles w/ same profiles but different order
Prior to this commit, two @ActiveProfiles declarations with the same
profiles but different order resulted in an identical, duplicate
ApplicationContext in the context cache in the Spring TestContext
Framework.

This commit uses a TreeSet to ensure that registered active profiles
are both unique and sorted, thereby avoiding cache misses for
semantically identical active profiles configuration on different test
classes.

Closes gh-25973
2020-10-26 11:42:28 +01:00
Juergen Hoeller 9d70d2023c Upgrade to SnakeYAML 1.27 2020-10-26 11:16:52 +01:00
Juergen Hoeller 82835b99ec Restore independent LinkedMultiValueMap implementation (without base class)
Closes gh-25960
2020-10-26 11:16:33 +01:00
Rossen Stoyanchev 4726663f81 Correct Javadoc link core-resources.adoc
Closes gh-25970
2020-10-26 07:43:30 +00:00
Rossen Stoyanchev 86af93a504 Correct sample in webmvc.adoc
Closes gh-25965
2020-10-26 07:40:33 +00:00
Rossen Stoyanchev fb4363e4e0 Refactor DataBufferUtils Matcher implementation
The existing implementation was exposed to very poor performance when matching
with multiple delimiters against a large buffer with many delimiters. In that
case all matchers are invoked many times (as many as the number of delimiters)
even though some of them found no match at all on the first pass.

The revised implementation uses a single index and advances all matchers
together, checking one byte a time, and not letting any one of them search to
the end of the entire buffer on a single pass.

Closes gh-25915
2020-10-23 13:23:51 +01:00
Rossen Stoyanchev 6946fe2f74 Upgrade to RSocket 1.0.3 snapshots
See gh-25957
2020-10-22 21:46:17 +01:00
Rossen Stoyanchev db9e0b0ccb Refactor StringDecoder
Simplify and optimize the processing of the input stream.

The existing implementation was using bufferUntil and creating a List
for every line along with an EndFrameBuffer inserted for the
bufferUntil predicate. So the larger the input buffer and the more
lines it contained, the greater the overhead.

The new implementation avoids bufferUntil for all lines and
instead uses concatMapIterable to aggregate the lines from a buffer
into a single list. So the larger the input buffer and the more
lines it contains, the better the throughput. The only buffering
used then is for partial chunks and those are accumulated in a list.

See gh-25915
2020-10-22 21:29:54 +01:00
Stephane Nicoll f7ec92c647 Start building against Reactor Dysprosium-SR13 snpshots
See gh-25946
2020-10-21 14:19:59 +02:00
Brian Clozel 7bee3d1574 Optimize Jackson resource management in codecs
Prior to this commit, references to `JsonGenerator` and
`ByteArrayBuilder` were not closed/released within codecs calls.
This prevents Jackson from reusing more efficiently shared memory
resources.

This commit properly closes/releases Jackson resources in Spring MVC,
Spring WebFlux and Spring Messaging codecs.
A benchmark on WebFlux codecs (in both single value/streaming mode)
shows significant throughput and allocation improvements for small
payloads.

Closes gh-25910
2020-10-20 15:36:23 +02:00
Rossen Stoyanchev db3d537e72 Protect SseEmitter against early I/O errors
Closes gh-25442
2020-10-16 19:08:30 +01:00
Rossen Stoyanchev a0727191e1 Polishing 2020-10-16 19:08:13 +01:00
Juergen Hoeller 5ab1097b43 Consistent dependency declaration order 2020-10-16 15:19:25 +02:00
Juergen Hoeller d77ecb26a9 Fail on warnings with compileGroovy (since it compiles Java code as well) 2020-10-16 15:18:48 +02:00
Rossen Stoyanchev c45b106d95 Fix race issue and improve readAsynchronousFileChannel
Before this commit, ReadCompletionHandler delayed closing the channel
to allow an ongoing read to complete/fail so we can get a hold of the
associated DataBuffer and release it. This can be problematic since the
read take time to complete but even more importantly there was a race
condition where we didn't check if we've been disposed concurrently
while releasing the read flag.

This commit removes the delay and closes the channel immediately from
cancel() and that should in turn fail any ongoing read operation,
according to AsynchronousChannel, and the DataBuffer is released.

Further improvements include:
- combining the "reading" and "disposed" AtomicBoolean's into a
single "state" AtomicReference.
- an optimistic check to remain in READING mode and avoid state
switches when there is demand to continue reading.

Closes gh-25831
2020-10-15 17:10:22 +01:00
Rossen Stoyanchev 431ec906c4 Ensure buffers released in HttpHeadResponseDecorator
See gh-25908
2020-10-13 23:38:59 +01:00
Rossen Stoyanchev 1d96f6a266 HttpHeaderResponseDecorator checks for "Transfer-Encoding"
This commit extends the fix from b86c11cc9b
by checking for both existing Content-Length and Transfer-Encoding.

Closes gh-25908
2020-10-13 23:06:06 +01:00
Juergen Hoeller 7b6293fa05 Avoid outdated Jackson API in tests
See gh-25907
2020-10-13 11:13:54 +02:00
Juergen Hoeller cd7e5f61f0 Upgrade to Caffeine 2.8.6 and OpenPDF 1.3.22 2020-10-13 01:39:42 +02:00
Juergen Hoeller 06b6a4be16 Polishing 2020-10-13 01:39:12 +02:00
Juergen Hoeller f3f19504c6 Polishing 2020-10-13 00:21:07 +02:00
Juergen Hoeller 72b2dda17f Avoid creation of unused logger instance in AbstractMediaTypeExpression
Closes gh-25901
2020-10-13 00:20:06 +02:00
Juergen Hoeller e176c4e799 Polishing 2020-10-12 19:40:50 +02:00
Juergen Hoeller 690e219fe8 Upgrade to Commons Pool 2.8.1 and WebJars Locator 0.46 2020-10-12 18:34:17 +02:00
Juergen Hoeller 66a67ec807 Polishing 2020-10-12 18:26:14 +02:00
Juergen Hoeller 69c330d905 Attempt fallback Part resolution even without StandardMultipartHttpServletRequest
Closes gh-25829
2020-10-12 18:25:55 +02:00
Juergen Hoeller ec9de943ee Construct StringBuilder in StreamUtils with appropriate initial size
Closes gh-25789
2020-10-07 15:11:53 +02:00
Rossen Stoyanchev eb11c6fa23 Reinstate removal of jsessionid from lookup path
Closes gh-25864
2020-10-07 11:31:52 +01:00
Juergen Hoeller ca7fb23432 Upgrade to Hibernate ORM 5.4.22, Hibernate Validator 6.1.6, Undertow 2.0.32, Checkstyle 8.36.2 2020-10-06 15:31:46 +02:00
Juergen Hoeller f83bb7183e Polishing 2020-10-06 15:31:34 +02:00
Juergen Hoeller 1745a3f25d Consistent @Nullable declarations on overridden converter methods 2020-10-06 15:31:26 +02:00
Juergen Hoeller e417318915 Revise native Hibernate 5 bootstrapping with JTA transaction manager
Closes gh-25858
2020-10-06 15:31:19 +02:00
Rossen Stoyanchev 2533ba5253 Use Mono.fromDirect for Jetty ReactiveRespnose
Closes gh-25849
2020-10-02 13:43:42 +01:00
Rossen Stoyanchev e44b08f1fc Minor refactoring in JettyClientHttpConnector
See gh-25849
2020-10-02 13:32:00 +01:00
Rossen Stoyanchev 86f2ebec1b Fix recursion issue caused by previous commit
See gh-25821
2020-09-30 22:03:46 +01:00
Rossen Stoyanchev 7ad60d385b Fix issue with copying headers in NativeMessageHeaderAccessor
Closes gh-25821
2020-09-30 21:42:26 +01:00
Rossen Stoyanchev 4b9c3fa739 Polishing Javadoc
See gh-25821
2020-09-30 21:42:26 +01:00
Sébastien Deleuze b322cbd625 Add missing @Nullable to WebFlux RequestMappingHandlerMapping
Closes gh-25657
2020-09-25 14:22:53 +02:00
Juergen Hoeller d022fcf32f Explicit note on TransactionalEventListener versus reactive transactions
Closes gh-25805
2020-09-25 12:49:45 +02:00
Juergen Hoeller e028ef8170 Add MariaDB to the supported database products for functions as well
Closes gh-25811
2020-09-25 12:47:31 +02:00
Juergen Hoeller 6e4fcb69f0 Polishing 2020-09-25 11:26:01 +02:00
Juergen Hoeller 392ad09990 Add MariaDB to the list of supported database products for procedures
Closes gh-25811
2020-09-25 11:25:05 +02:00
Juergen Hoeller 21cb9e8bff Translate NullBean result to null for lookup method with bean name
Closes gh-25806
2020-09-25 11:24:50 +02:00
Juergen Hoeller c83f6adc24 Revise event multicaster locking for non-synchronized retriever caching
Closes gh-25799
2020-09-25 11:24:26 +02:00
Juergen Hoeller d9da663f6d Optimize String argument resolution in MessageTag
Closes gh-25809
2020-09-25 11:23:38 +02:00
Juergen Hoeller c04400890f Avoid repeated Charset resolution in MimeType
Closes gh-25808
2020-09-25 11:23:12 +02:00
Sam Brannen bf00db3c6c Avoid AssertJ deprecation warning 2020-09-25 11:08:51 +02:00
Sam Brannen f5d36aa47a Revert use of Map::computeIfAbsent in thread and tx scopes
Issues gh-25038 and gh-25618 collectively introduced a regression for
thread-scoped and transaction-scoped beans.

For example, given a thread-scoped bean X that depends on another
thread-scoped bean Y, if the names of the beans (when used as map keys)
end up in the same bucket within a ConcurrentHashMap AND an attempt is
made to retrieve bean X from the ApplicationContext prior to retrieving
bean Y, then the use of Map::computeIfAbsent in SimpleThreadScope
results in recursive access to the same internal bucket in the map.

On Java 8, that scenario simply hangs. On Java 9 and higher,
ConcurrentHashMap throws an IllegalStateException pointing out that a
"Recursive update" was attempted.

In light of these findings, we are reverting the changes made to
SimpleThreadScope and SimpleTransactionScope in commits 50a4fdac6e and
148dc95eb1.

Closes gh-25801
2020-09-25 11:00:06 +02:00
Brian Clozel a532c527dd Fix missing reference doc from docs archive
Prior to this commit, the `docsZip` task would not reference the new
output locations for the `asciidoctor` and `asciidoctorPdf` tasks.
This results with missing reference docs in the docs zip.

This commit updates the input locations of the Zip task to include the
produced reference docs.

Fixes gh-25783
2020-09-24 17:49:37 +02:00
Sam Brannen a5a4960859 Do not generate reference docs for include-files
Prior to this commit, the Asciidoctor Gradle tasks generated top-level
HTML and PDF documents for AsciiDoc files that are included in other
top-level documents. This causes slower builds and results in each
include-file being published twice:

1) inline in the including document (as intended)
2) as a top-level document but missing surrounding context (unintended)

The reason these include-files are generated as top-level documents is
that the asciidoctor and asciidoctorPdf Gradle tasks are configured to
use '*.adoc' as the input source files.

This commit addresses this issue by moving the following include-files
to new subdirectories. Locating the include-files in the subdirectories
causes them to be ignored in the '*.adoc' pattern used to identify
input source files.

- data-access-appendix.adoc -> data-access/data-access-appendix.adoc
- integration-appendix.adoc -> integration/integration-appendix.adoc
- testing-webtestclient.adoc -> testing/testing-webtestclient.adoc

Closes gh-25783
2020-09-21 11:51:50 +02:00
Sam Brannen 2342f5f48a Remove unnecessary folders and files from PDF reference documentation
Prior to this commit, the asciidoctor Gradle task was configured to
generate both the HTML5 and PDF backends. Unfortunately, this resulted
in resources such as HTML, JavaScript, CSS, and images being published
alongside the generated PDF documents.

This commit addresses this issue by introducing the use of a dedicated
asciidoctorPdf Gradle task. The existing asciidoctor Gradle task has
been modified to only generate HTML5 output. Both of these tasks now
share common configuration supplied by the updated asciidoctorj Gradle
task.

In addition, the asciidoctor task now depends on the asciidoctorPdf
task. Thus, invoking `./gradlew asciidoctor` will still generate both
the HTML5 and PDF outputs; whereas, `./gradlew asciidoctorPdf` will
generate only the PDF outputs. We may later decide to rework the tasks
to introduce a dedicated asciidoctorHtml task so that we can generate
the HTML outputs without having to generate the PDF outputs (which are
more time consuming).

See gh-25783
2020-09-21 11:43:08 +02:00
Juergen Hoeller f5d7161d6b Consistent flushing of given OutputStream 2020-09-18 19:14:11 +02:00
Juergen Hoeller 82e64af5a5 Avoid throwing plain RuntimeException (plus related polishing)
See gh-24805
2020-09-18 19:01:49 +02:00
Juergen Hoeller c1617d3c52 Polishing 2020-09-18 18:15:36 +02:00
Juergen Hoeller 9dfef59af2 Construct StringWriter instances with appropriate initial size
Closes gh-25789
2020-09-18 18:14:57 +02:00
Sam Brannen a6daed1b71 Fix example in Javadoc for Assert.notNull(object, messageSupplier)
Closes gh-25774
2020-09-15 16:27:21 +02:00
Rossen Stoyanchev 28df426798 Update AbstractDataBufferAllocatingTests
We are passing custom values to the constructor of PooledByteBufAllocator in
tests in order to turn of caching. This is based on:
https://github.com/netty/netty/issues/5275#issuecomment-220547057

Netty 4.1.52 has significant changes in PooledByteBufAllocator:
https://github.com/netty/netty/pull/10267

After the changes, our current value for maxOrder=2, which results in
chunkSize=16K, causes an assert failure in PoolChunk where the runSize
exceeds the chunkSize.
2020-09-15 11:31:59 +01:00
Spring Buildmaster 845cb715e7 Next Development Version 2020-09-15 08:31:10 +00:00
Juergen Hoeller f010368a66 Polishing 2020-09-15 10:08:01 +02:00
Juergen Hoeller 3ec4538981 Upgrade to Checkstyle 8.36.1 2020-09-14 22:19:25 +02:00
Juergen Hoeller 3c84863271 Polishing 2020-09-14 22:18:30 +02:00
Juergen Hoeller c2f6a98c90 Lenient handling of empty Content-Disposition filename
Closes gh-25769
2020-09-14 22:16:12 +02:00
Juergen Hoeller 49d65d5c41 Configurable filename encoding in MimeMessageHelper
Closes gh-25755
2020-09-14 22:15:44 +02:00
Rossen Stoyanchev 16d125ce76 Extend Content-Disposition "inline" to error responses
We don't expect a browser to save error responses to a file but we
extend this protection anyway since "inline" is only a suggestion
that shouldn't have any side effects.
2020-09-14 15:28:53 +01:00
Rossen Stoyanchev dccc78146a Expose defaultCharset in StringDecoder
Closes gh-25762
2020-09-14 14:28:02 +01:00
Rossen Stoyanchev dde79a9b65 Upgrade to Reactor Dysprosium-SR12
Closes gh-25730
2020-09-14 14:06:15 +01:00
Rossen Stoyanchev 49356b2c0f SimpleIdGenerator rolls over at Long.MAX_VALUE
Closes gh-25485
2020-09-13 21:09:08 +01:00
Rossen Stoyanchev 852718ec0e Minor fix in PathResourceResolverTests
Closes gh-25671
2020-09-13 21:09:08 +01:00
Arjen Poutsma 07d2c08f48 Do not tokenize Forward header value
This commit remove the tokenization previously used in
UriComponentsBuilder#adaptFromForwardedHeaders, in order to support
Forwarded headers that have multiple, comma-separated 'for' elements.

Closes gh-25737
2020-09-09 16:31:24 +02:00
Juergen Hoeller ed3b7cd10f Upgrade to HSQLDB 2.5.1 and Woodstox 6.2.1 2020-09-08 17:09:13 +02:00
Juergen Hoeller 4d1d60ac42 Check log level before delegating Supplier-based message to target Log
Closes gh-25741
2020-09-08 16:50:40 +02:00
Juergen Hoeller c6cc6705ef FileUrlResource.isWritable() exclusively relies on getFile() implementation
Closes gh-25584
2020-09-08 12:23:27 +02:00
Juergen Hoeller ae1d15c8f4 Declare protected getCharset method as non-static
See gh-25509
2020-09-08 12:22:25 +02:00
Rossen Stoyanchev d616c6632d Remove session on 4xx response from WebSocket handshake
Closes gh-25608
2020-09-07 21:27:52 +01:00
Rossen Stoyanchev 94c91c9e9c Explain how to provide serialization view programmatically
Closes gh-25596
2020-09-07 21:27:52 +01:00
Rossen Stoyanchev b6ff12d2f5 Expose protected method in AbstractJackson2HttpMessageConverter
Closes gh-25509
2020-09-07 21:27:52 +01:00
Rossen Stoyanchev b1d84067cd UriComponentsBuilder Javadoc update
Closes gh-25604
2020-09-07 21:27:52 +01:00
Rossen Stoyanchev c19fc9d53f Switch to Reactor Dysprosium snapshots
See gh-25730
2020-09-07 21:27:52 +01:00
Rossen Stoyanchev 899761f0a8 Avoid unnecessary parsing of path params
See gh-25690
2020-09-07 21:27:52 +01:00
Rossen Stoyanchev f88759c3c9 Shared read-only instances of UrlPathHelper
UrlPathHelper is often created and used without customizations or with
the same customizations. This commit introduces re-usable, instances.
Effectively a backport of commit 23233c.

See gh-25690
2020-09-07 21:27:52 +01:00
Juergen Hoeller 4f0f29880f Upgrade to AssertJ 3.17.2 and Undertow 2.0.31 2020-09-07 19:25:46 +02:00
Juergen Hoeller 4b211fb18c Javadoc refinements 2020-09-07 19:20:26 +02:00
Juergen Hoeller e797398b10 CallParameterMetaData detects function return parameter specifically
Closes gh-25588
2020-09-07 17:51:23 +02:00
Juergen Hoeller 613b05d814 Properties loading with ignoreResourceNotFound covers SocketException as well
Closes gh-25717
2020-09-07 17:51:14 +02:00
Juergen Hoeller 939c76c4a5 Revise documentation notes on getParameterType performance issues
See gh-25679
2020-09-05 13:00:06 +02:00
Juergen Hoeller 40bf83c9e5 Restore original 4.x behavior for initialization of function return name
Closes gh-25707
2020-09-05 12:59:34 +02:00
Juergen Hoeller c368ce8223 Fix SpEL generated code for default method invocation
Closes gh-25706
2020-09-05 12:59:12 +02:00
Juergen Hoeller 670b9fd60b Retry SQLErrorCodesFactory retrieval if DatabaseMetaData access failed
Includes deprecation of JdbcUtils.extractDatabaseMetaData(DataSource, String) in favor of the now generified version of extractDatabaseMetaData(DataSource, DatabaseMetaDataCallback).

Closes gh-25681
Closes gh-25686
2020-09-03 19:16:14 +02:00
Stephane Nicoll c2363a6ef9 Make DataSize serializable
Closes gh-25675
2020-09-02 14:39:12 +02:00
Stephane Nicoll cdfdc340d2 Log cache hit and cache miss for synchronized access
Closes gh-25248
2020-09-02 11:29:03 +02:00
Juergen Hoeller 7bd6b8d279 Upgrade to Checkstyle 8.36 2020-09-01 23:41:34 +02:00
Juergen Hoeller 141470ff58 Explicit nullability declarations for getTarget() implementations 2020-09-01 23:26:22 +02:00
Juergen Hoeller d62202f464 Polishing 2020-09-01 10:27:36 +02:00
Juergen Hoeller bcdc2503fa Avoid repeated calls to getPathWithinApplication from getLookupPathForRequest
Closes gh-25669
2020-09-01 10:27:04 +02:00
Juergen Hoeller 3a73533b1c Upgrade Gradle plugins to latest patch releases 2020-08-31 18:01:22 +02:00
Juergen Hoeller d8c420ab75 Avoid full singleton lock for getSingleton(beanName, false)
Closes gh-25667
2020-08-31 18:00:51 +02:00
Juergen Hoeller 97d84d9ab8 Upgrade to AssertJ 3.17.1 2020-08-30 12:16:14 +02:00
Juergen Hoeller ae4160e131 Avoid direct use of non-exported XStream CompositeClassLoader class
Closes gh-25662
2020-08-30 12:15:45 +02:00
Juergen Hoeller bb9e79daa7 Polishing 2020-08-28 19:58:56 +02:00
Juergen Hoeller 6d9d4157ef Specifically detect Joda-Time 2.x
Closes gh-25655
2020-08-28 19:57:51 +02:00
Juergen Hoeller 387eddcf75 Upgrade to Hibernate ORM 5.4.21, HtmlUnit 2.43, AspectJ 1.9.6 2020-08-27 17:29:06 +02:00
Juergen Hoeller 71e70aed14 Polishing 2020-08-27 17:13:33 +02:00
Juergen Hoeller a8b295c516 Consistent javadoc for ParseState and its entry classes 2020-08-27 14:37:42 +02:00
Juergen Hoeller cf2e0c7959 Selected use of ArrayList instead of LinkedList in common places
See gh-25652
2020-08-27 14:14:44 +02:00
Juergen Hoeller 589060d10f Avoid LinkedList performance issues through use of ArrayDeque
Closes gh-25652
2020-08-27 14:14:08 +02:00
Juergen Hoeller 60fa704f78 Consistent behavior for overloaded @Bean methods with ASM processing
Closes gh-25263
2020-08-27 14:13:33 +02:00
Juergen Hoeller f43c39c905 Upgrade to Hibernate ORM 5.4.20 2020-08-25 16:17:35 +02:00
Juergen Hoeller 6f0461c569 Polishing 2020-08-25 16:17:22 +02:00
Juergen Hoeller 04df9b8f49 Efficient checks for empty strings and single character matches
Closes gh-25552
Closes gh-25553
2020-08-25 16:17:12 +02:00
Juergen Hoeller 0d4040aa63 Avoid potential integer overflow in seconds->millis transformation
Closes gh-25613
2020-08-25 16:16:34 +02:00
Sam Brannen 148dc95eb1 Fix regressions in SimpleThreadScope and SimpleTransactionScope
PR gh-25038 introduced regressions in SimpleThreadScope and
SimpleTransactionScope in Spring Framework 5.2.7. Specifically, if a
thread-scoped or transaction-scoped bean has a dependency on another
thread-scoped or transaction-scoped bean, respectively, a
ConcurrentModificationException will be thrown on Java 11 or higher.

The reason is that Java 11 introduced a check for concurrent
modification in java.util.HashMap's computeIfAbsent() implementation,
and such a modification can occur when a thread-scoped bean is being
created in order to satisfy a dependency of another thread-scoped bean
that is currently being created.

This commit fixes these regressions by switching from HashMap to
ConcurrentHashMap for the instance maps in SimpleThreadScope and
SimpleTransactionScope.

Closes gh-25618
2020-08-22 23:19:58 +02:00
Sam Brannen d939016a09 Polish contribution
See gh-25600
2020-08-17 15:53:45 +02:00
Maciej Miklas a83529c844 Introduce createContext() factory method in AbstractGenericContextLoader
Prior to this commit it was possible to configure the
DefaultListableBeanFactory used by the GenericApplicationContext
created by AbstractGenericContextLoader, but it was not possible to
completely replace the bean factory.

This commit introduces a new createContext() factory method in
AbstractGenericContextLoader which indirectly allows subclasses to
supply a custom DefaultListableBeanFactory implementation to the
GenericApplicationContext.

Closes gh-25600
2020-08-17 15:38:24 +02:00
Sam Brannen 32e851617e Fix Javadoc formatting in GenericGroovyXmlContextLoader 2020-08-17 15:37:51 +02:00
Sam Brannen 93e5214d01 Revise Javadoc regarding log level for non-static BFPP @Bean method
Closes gh-25590
2020-08-16 20:03:46 +02:00
Juergen Hoeller 9bf5cba3c2 Drop outdated notes on handler type versus handler method restrictions
Closes gh-25482
2020-08-10 14:43:27 +02:00
Juergen Hoeller 7d56c303a4 Use getType with allowFactoryBeanInit=false during advisor retrieval
Closes gh-25546
2020-08-10 14:43:02 +02:00
Sam Brannen bd65762582 Polish Javadoc for MessagePostProcessor interfaces
See gh-25571
2020-08-10 11:26:41 +02:00
Philippe Marschall 6a7e58ac82 Add @FunctionalInterface to MessagePostProcessor
Add the @FunctionalInterface annotation to the MessagePostProcessor
interfaces in the spring-jms and spring-messaging projects.

Closes gh-25571
2020-08-10 11:19:35 +02:00
Sam Brannen e25e690ad4 Assert preconditions for MergedAnnotations.from() factory methods
Prior to this commit, if null values were supplied for the
RepeatableContainers or AnnotationFilter arguments to `from()` factory
methods in MergedAnnotations, certain operations would eventually
result in a NullPointerException. This is to be expected; however, the
NullPointerException is often swallowed and only logged at INFO level
with an exception message similar to the following.

> Failed to introspect annotations on org.example.MyClass: NullPointerException

In such cases, the INFO log message is not helpful in diagnosing the
problem. Furthermore, since the exception is swallowed, the desired
operation (e.g., MergedAnnotations.stream(...)) simply returns no
results.

This commit improves the user experience by eagerly asserting non-null
preconditions for required arguments in MergedAnnotations.from()
factory methods.

Closes gh-25568
2020-08-08 12:21:15 +02:00
Sam Brannen a614abe17b Polish Javadoc for MergedAnnotations 2020-08-08 11:59:24 +02:00
Juergen Hoeller 292f581cdd Populate dependencies metadata for resolved target behind lazy dependency proxy
Closes gh-25562
2020-08-07 21:42:02 +02:00
Juergen Hoeller 686f5d4a5e Upgrade to Jackson 2.10.5 2020-08-07 15:55:10 +02:00
Juergen Hoeller 3b9558a269 Polishing 2020-08-07 15:51:33 +02:00
Juergen Hoeller 692c5f292d Polishing 2020-08-07 13:11:48 +02:00
Juergen Hoeller 7fdb33a105 Upgrade to Jetty 9.4.31, Groovy 2.5.13, Hibernate ORM 5.4.19, EclipseLink 2.7.7, Checkstyle 8.35 2020-08-07 13:03:28 +02:00
Juergen Hoeller 8dd285f877 Polishing 2020-08-07 13:02:43 +02:00
Juergen Hoeller 94eee6a32a Provide access to AbstractRoutingDataSource's resolved target DataSources
Closes gh-25544
2020-08-07 13:00:35 +02:00
Juergen Hoeller 96a4e1150e Avoid unnecessary computation of cleaned URL
Closes gh-25531
2020-08-07 12:59:41 +02:00
Stephane Nicoll 6acbc5093a Indicate caches should be initialized in SimpleCacheManager
Closes gh-22988
2020-08-07 11:01:39 +02:00
diguage 0501999e43 Fix comment syntax in xml examples
See gh-25537
2020-08-06 14:25:30 +02:00
Stephane Nicoll b6842730f7 Merge pull request #25539 from diguage
* pr/25539:
  Fix asciidoctor syntax for source

Closes gh-25539
2020-08-06 09:27:38 +02:00
diguage 5cb2cc2466 Fix asciidoctor syntax for source
See gh-25539
2020-08-06 09:27:09 +02:00
Sam Brannen 96da1ff9ea Support @RestControllerAdvice in Standalone MockMvc again
Since Spring Framework 5.2, @RestControllerAdvice registered with
MockMvc when using MockMvcBuilders.standaloneSetup() has no longer been
properly supported if annotation attributes were declared in the
@RestControllerAdvice annotation. Prior to 5.2, this was not an issue.

The cause for this regression is two-fold.

1. Commit 50c257794f refactored
   DefaultListableBeanFactory so that findAnnotationOnBean() supports
   merged annotations; however, that commit did not refactor
   StaticListableBeanFactory#findAnnotationOnBean() to support merged
   annotations.

2. Commit 978adbdae7 refactored
   ControllerAdviceBean so that a merged @ControllerAdvice annotation
   is only looked up via ApplicationContext#findAnnotationOnBean().

The latter relies on the fact that findAnnotationOnBean() supports
merged annotations (e.g., @RestControllerAdvice as a merged instance of
@ControllerAdvice). Behind the scenes, MockMvcBuilders.standaloneSetup()
creates a StubWebApplicationContext which internally uses a
StubBeanFactory which extends StaticListableBeanFactory. Consequently,
since the implementation of findAnnotationOnBean() in
StaticListableBeanFactory was not updated to support merged annotations
like it was in DefaultListableBeanFactory, we only see this regression
with the standalone MockMvc support and not with MockMvc support for an
existing WebApplicationContext or with standard Spring applications
using an ApplicationContext that uses DefaultListableBeanFactory.

This commit fixes this regression by supporting merged annotations in
StaticListableBeanFactory#findAnnotationOnBean() as well.

Closes gh-25520
2020-08-05 17:40:16 +02:00
Sam Brannen 40fc472c70 Polish ExceptionHandlerTests 2020-08-05 17:24:45 +02:00
Sam Brannen 7a31885ae5 Fix bug in StaticListableBeanFactory.isSingleton()
Prior to this commit, StaticListableBeanFactory.isSingleton() returned
false for singleton beans unless they were created by a FactoryBean.

StaticListableBeanFactory.isSingleton() now properly returns true for
all beans not created by a FactoryBean.

Closes gh-25522
2020-08-04 15:13:10 +02:00
Sam Brannen 91d1383e93 Use Spliterators.emptySpliterator() in TypeMappedAnnotations
For greater clarity, this commit invokes Spliterators.emptySpliterator()
directly instead of going through java.util.Collections.EmptyList.
2020-08-03 13:44:02 +02:00
Sam Brannen 969aa8ad47 Update copyright date 2020-08-03 12:19:21 +02:00
Sam Brannen 482adb9478 Fix error message for type mismatch in jsonPath().value()
Prior to this commit, if a value existed at the specified JSON path but
had an incompatible type, the AssertionError thrown contained a message
stating that the value did not exist (i.e., "No Value at JSON Path"),
which was not only misleading but also technically incorrect.

This commit fixes the error message for such use cases. For example, the
AssertionError thrown in such use cases now resembles the following.

  At JSON path "$.name", value <Lisa> of type <java.lang.String> cannot
  be converted to type <byte[]>

Closes gh-25480
2020-08-01 16:35:54 +02:00
Sam Brannen 5a12e7b2c5 Fix typo in test method names 2020-08-01 16:30:12 +02:00
Sam Brannen 5576321b04 Reset charset field in MockHttpServletResponse
Prior to this commit, calling reset() on MockHttpServletResponse did not
reset the `charset` field to `false` which could result in the
"Content-Type" header containing `;charset=null` which in turn would
result in errors when parsing the "Content-Type" header.

This commit resets the charset field to `false` in
MockHttpServletResponse's reset() method to avoid such errors.

Closes gh-25501
2020-08-01 14:01:39 +02:00
Sam Brannen 785ab5798a Sync MockHttpServletResponse changes 2020-08-01 12:43:26 +02:00
Sam Brannen 89bb9cb749 Polish Javadoc 2020-08-01 12:26:56 +02:00
Sam Brannen 9b0729007f Polish MockHttpServletResponseTests 2020-08-01 12:26:38 +02:00
Sam Brannen 7dbf42e858 Polish contribution
See gh-25483
2020-07-29 20:16:21 +02:00
yilianhuaixiao 83a95832e6 Filter repeatable annotations in AnnotationTypeMappings
Prior to this commit, AnnotationTypeMappings did not filter repeatable
annotations with the supplied annotation filter.

Closes gh-25483
2020-07-29 17:11:24 +02:00
Sam Brannen b841e8560c Polish MergedAnnotation API internals 2020-07-29 17:08:58 +02:00
Sam Brannen 2b3fdfabb2 Remove unused class filtering support in AnnotationScanner
PR gh-25429 brought it to our attention that there was a bug in
AnnotationScanner when using a non-null class filter that filtered out
classes; however, it turns out that there is no production code that
utilizes the package-private class filtering support.

This commit therefore removes all class filtering support from
AnnotationScanner since that functionality is effectively unused.

Closes gh-25477
2020-07-28 09:58:14 +02:00
Sam Brannen 5442d8779a Polish contribution
See gh-25429
2020-07-25 15:24:36 +02:00
yilianhuaixiao 650cbeee14 Avoid infinite loop in AnnotationScanner
Prior to this commit, scanning for annotations resulted in an infinite
loop when using the INHERITED_ANNOTATIONS search strategy and a class
filter that filters out visited classes.

This commit avoids an infinite loop in AnnotationsScanner's
processClassInheritedAnnotations(...) method by skipping the current
level of the class hierarchy when the current source class has been
filtered out.

Closes gh-25429
2020-07-25 15:23:21 +02:00
Sam Brannen 335c3d5db6 Polish contribution
See gh-25445
2020-07-22 17:26:59 +02:00
XenoAmess ab859fcc96 Refine use of substring operations
Closes gh-25445
2020-07-22 17:26:42 +02:00
Spring Buildmaster fc6b38a8f6 Next Development Version 2020-07-21 08:20:59 +00:00
Jay Bryant 1c83b3fc22 Wording changes
Replace potentially insensitive language with more neutral language.

Closes gh-25314
2020-07-20 17:14:13 +02:00
Rossen Stoyanchev 913eca9e14 ReactorNettyRequestUpgradeStrategy uses unique builder per request
See gh-25315
2020-07-20 17:55:23 +03:00
Juergen Hoeller 6c7f18e902 Upgrade to Jetty Reactive HttpClient 1.1.4 2020-07-20 16:47:52 +02:00
Juergen Hoeller 64f4703445 Defer creating logger in StandardWebSocketHandlerAdapter to instantiation time
Closes gh-25427
2020-07-20 16:47:32 +02:00
Rossen Stoyanchev eb032a50a0 Upgrade to Reactor Dysprosium-SR10
Closes gh-25376
2020-07-20 16:48:33 +03:00
Juergen Hoeller 65e601090f Copy queryParams MultiValueMap through addAll (for independent List entries)
Closes gh-25423
2020-07-20 07:07:17 +02:00
Juergen Hoeller f1345aadf5 Defensively access existing beanDefinitionMap entries
See gh-22263
2020-07-20 07:04:45 +02:00
Juergen Hoeller 43e315f10c Unwrap SqlParameterValue for disposable value detection in cleanupParameters
Closes gh-22972
2020-07-19 19:59:15 +02:00
Juergen Hoeller 30bc5e09e7 Defensively catch NoSuchBeanDefinitionException on beanDefinitionNames traversal
Closes gh-22263
2020-07-19 19:56:33 +02:00
Juergen Hoeller 7b6924522a Avoid unnecessarily alarming stack trace logged during scheduler resolution
Closes gh-23268
2020-07-19 19:55:19 +02:00
Juergen Hoeller 9a618dc7a1 Enforce ConditionalContentCachingResponseWrapper in ShallowEtagHeaderFilter
Closes gh-24976
2020-07-19 19:53:29 +02:00
Juergen Hoeller 165a6f186d Expose setExceptionListener on AbstractJmsListenerContainerFactory
Closes gh-22102
2020-07-19 19:53:01 +02:00
Juergen Hoeller bd3b44838f Upgrade to Checkstyle 8.34 and HtmlUnit 2.42 2020-07-17 19:24:50 +02:00
Juergen Hoeller 0b697a3068 Polishing 2020-07-17 19:24:23 +02:00
Juergen Hoeller 851908851d Upgrade to Tomcat 9.0.37, Netty 4.1.51, Apache Johnzon 1.2.8, OpenPDF 1.3.20, Caffeine 2.8.5, Hessian 4.0.63 2020-07-17 17:49:24 +02:00
Juergen Hoeller e9898f7d52 Polishing 2020-07-17 17:48:33 +02:00
Juergen Hoeller 30bf870810 Check JDBC 4 getFunctions (for compatibility with PostgreSQL driver 42.2.11)
Closes gh-25399
2020-07-17 17:47:53 +02:00
Juergen Hoeller 01bab89dba Consistently use PropertySource.getName() for comparison
Includes synchronization for mutators on MutablePropertySources.

Closes gh-25369
2020-07-17 17:45:58 +02:00
Juergen Hoeller 5846d9c2ea Clarify enforceInitMethod/enforceDestroyMethod default values
Closes gh-25402
2020-07-17 17:44:59 +02:00
Sam Brannen fcf20bab2a Delete duplicate code block in WebHttpHandlerBuilder.applicationContext()
This commit deletes a duplicated code block that was accidentally
introduced in a8a1fc6de5.

Closes gh-25389
2020-07-15 18:58:31 +02:00
Rossen Stoyanchev 03fa48919e Switch to Reactor Dysprosium snapshots
See gh-25376
2020-07-13 16:51:09 +03:00
Sam Brannen b769b73960 Improve JavaDoc for ConfigurableApplicationContext.refresh()
Closes gh-25380
2020-07-10 15:39:45 +02:00
Sam Brannen 2c9e794676 Make Profiles created via Profiles.of() comparable
Prior to this commit, a Profiles instance created via Profiles.of() was
not considered equivalent to another Profiles instance created via
Profiles.of() with the exact same expressions. This makes it difficult
to mock invocations of Environment#acceptsProfiles(Profiles) -- for
example, when using a mocking library such as Mockito.

This commit makes Profiles instances created via Profiles.of()
"comparable" by implementing equals() and hashCode() in ParsedProfiles.

Note, however, that equivalence is only guaranteed if the exact same
profile expression strings are supplied to Profiles.of(). In other
words, Profiles.of("A & B", "C | D") is equivalent to
Profiles.of("A & B", "C | D") and Profiles.of("C | D", "A & B"), but
Profiles.of("X & Y") is not equivalent to Profiles.of("X&Y") or
Profiles.of("Y & X").

Closes gh-25340
2020-07-07 14:17:36 +02:00
Sam Brannen 8734c64b75 Remove invalid import from Kotlin example 2020-07-06 16:31:33 +02:00
Sam Brannen 8be2a43d52 Rename SystemArchitecture aspect to CommonPointcuts in AOP ref doc
See gh-25357
2020-07-06 16:20:05 +02:00
Sam Brannen 52c2ca610b Polish AOP reference documentation
- fix formatting
- fix syntax
- use consistent example package name
2020-07-06 14:50:44 +02:00
Sam Brannen 35582ded0e Use System.nanoTime() for Random seed in SocketUtils
Prior to this commit, SocketUtils used System.currentTimeMillis() for
the seed for the java.util.Random instance used internally. The use of
the milliseconds value returned by currentTimeMillis() can lead to
collisions for randomly selected free ports for tests executing in
parallel on the same computer.

This commit therefore switches to System.nanoTime() for the Random seed
used in SocketUtils in an attempt to avoid such collisions for tests
executing in parallel in different JVMs on the same computer.

Closes gh-25321
2020-07-03 12:04:02 +02:00
Maksim 008a0a1bdd Fix interface and class names in examples in core-aop doc
Closes gh-25351
2020-07-02 15:28:05 +02:00
Arjen Poutsma 5b94d9b00b Use UTF-8 for application/*+json
This commit makes sure that the StringHttpMessageConverter reads
input with "application/*+json" as Content-Type with the UTF-8
character set.

Closes gh-25328
2020-07-01 10:46:58 +02:00
Rossen Stoyanchev b2a4d1c5b1 Avoid re-creating connect Mono<RSocket>
Closes gh-25330
2020-07-01 08:02:03 +01:00
Arjen Poutsma 79c339b03e Support for ASCII in Jackson codec & converter
This commit introduces support for writing JSON with an US-ASCII
character encoding in the Jackson encoder and message converter,
treating it like UTF-8.

See gh-25322
2020-06-30 15:46:54 +02:00
Sam Brannen 51a5517a45 Polishing 2020-06-27 14:33:44 +02:00
Сергей Цыпанов d08ce303f1 Extract Class.getName() from String concatenation
This commit extracts a Class.getName() invocation from String
concatenation in AbstractMonitoringInterceptor to avoid an issue
related to profile pollution.

Closes gh-25324
2020-06-27 14:24:49 +02:00
Sam Brannen 9876ca003b Support fragments in UriComponentsBuilder.fromHttpUrl()
Prior to this commit, UriComponentsBuilder.fromHttpUrl() threw an
IllegalArgumentException if the provided URL contained a fragment.

This commit aligns the implementation of fromHttpUrl() with that of
fromUriString(), by parsing a fragment and storing it in the builder.

Closes gh-25300
2020-06-26 18:30:09 +02:00
Sam Brannen dd11dbf3b1 Polish UriComponentsBuilderTests 2020-06-26 14:58:06 +02:00
Juergen Hoeller fb903f34b0 Upgrade to Hibernate ORM 5.4.18 2020-06-23 23:21:12 +02:00
Juergen Hoeller b0cabb29f3 Polishing 2020-06-23 23:20:45 +02:00
Rossen Stoyanchev 21d069695f Refine solution for 21de09
The following was reported after the change and is related to it:
https://github.com/reactor/reactor-netty/issues/1170. An HTTP HEAD with the body
not consumed. Connection is disposed and closed leading to subsequent request to
fail. Adding toBodilessEntity() helps.

This change does not close the connection but rather drains the body which does
not impact subsequent re-use of the connection. This however may compete with a
late subscriber actually attempting to read the response. At that point there is
little choice but to raise an ISE with a more specific description.

See gh-25216
2020-06-23 19:58:57 +01:00
DK Lee 6419b18bee Fix typo in Java example for handler class
Closes gh-25302
2020-06-23 16:46:14 +02:00
Rossen Stoyanchev f0b8e638ad Avoid dependency on netty-common in DataBufferUtils
See: gh-22594
2020-06-23 14:20:24 +01:00
Juergen Hoeller 9e12a20324 Polishing 2020-06-23 11:35:22 +02:00
Brian Clozel c4326cb0f5 Fix missing contextPath when mutating ServerHttpRequest
This commit ensures that when mutating `ServerHttpRequest` instances,
the original contextPath information is copied to the request being
built.

Note that mutation on the `contextPath(String)` or `path(String)` should
be reflected to the other. (See their Javadoc for more information).

Fixes gh-25279
2020-06-22 19:13:10 +02:00
Sam Brannen 80d1aaec0c Add spring-r2dbc and spring-rsocket to Stack Overflow tags 2020-06-22 11:38:04 +02:00
Arjen Poutsma 405fdd3a57 Map from charset name rather than Charset
With this commit it is no longer assumed that all charset names in the
JsonEncoding can be resolved by Charset.forName. Instead, we store the
charset name itself, rather than the Charset object.
2020-06-22 09:48:41 +02:00
Sam Brannen 0a208a4941 Fix broken link to Stack Overflow tags 2020-06-21 19:41:56 +02:00
Rossen Stoyanchev f35903f23d Catch IllegalReferenceCountException
Closes gh-22594
2020-06-19 21:58:03 +01:00
Rossen Stoyanchev 21de098756 Dispose on cancel if response not subscribed
Closes gh-25216
2020-06-19 21:58:03 +01:00
Brian Clozel 9b615ed8c6 Fix missing sslInfo with Reactor Netty and http/2
Prior to this commit, the `SslInfo` would be missing for WebFlux apps
when deployed on Reactor Netty with http/2.

This commit ensures that the request adapter checks the current channel
and the parent channel for the presence of the `SslHander`.
In the case of http/2, the `SslHander` is tied to the parent channel.

Fixes gh-25278
2020-06-19 16:43:34 +02:00
Sam Brannen d07be59801 Improve Javadoc for @Value regarding supported expressions
Closes gh-25284
2020-06-19 14:32:36 +02:00
Sam Brannen 46c786167e Replace "blacklist" with alternative words
See gh-25262
2020-06-18 14:54:33 +02:00
Juergen Hoeller 0a14ea6c57 Upgrade to Jetty 9.4.30 2020-06-17 15:40:00 +02:00
Juergen Hoeller a08bf8c063 Avoid misleading log message for commit-triggering exception
Closes gh-25253
2020-06-17 15:39:41 +02:00
Sam Brannen d51abe462e Upgrade to nohttp 0.0.5
Closes gh-25266
2020-06-17 14:46:23 +02:00
Sam Brannen 9acb5b1a4a Replace "black box" with alternative term
See gh-25262
2020-06-17 14:22:26 +02:00
Sam Brannen 972c01cbbd Replace "blacklist" with alternative words
See gh-25262
2020-06-17 14:00:26 +02:00
Arjen Poutsma 9c3417f703 Convert non-unicode input when reading w/ Jackson
This commit makes sure that Jackson-based message converters and
decoders can deal with non-unicode input. It does so by reading
non-unicode input messages with a InputStreamReader.

This commit also adds additional tests forthe canRead/canWrite methods
on both codecs and message converters.

Closes: gh-25247
2020-06-16 11:45:53 +02:00
wonwoo fd7e6486de Fix syntax in validation examples
Closes gh-25251
2020-06-15 14:58:27 +02:00
Sam Brannen 94d7462891 Ensure spring-core JAR is reproducible
Prior to this commit, a change to Javadoc in any class in spring-core
would result in ALL tests in the entire test suite being re-run via the
Gradle build.

Thanks to a tip from @melix, this commit aims to ensure that the
spring-core JAR is "reproducible".
2020-06-13 14:53:06 +02:00
Sam Brannen 3f7e86eadd Update Javadoc for Assert regarding Guava Preconditions 2020-06-13 14:53:06 +02:00
Juergen Hoeller 5e24085061 Upgrade to Apache Johnzon 1.2.7 and OpenPDF 1.3.19 2020-06-12 00:47:31 +02:00
Juergen Hoeller b24a337146 Polishing 2020-06-12 00:39:58 +02:00
Juergen Hoeller 9138a04a0a Polishing 2020-06-11 23:45:23 +02:00
Juergen Hoeller e46ccd74b1 Consistent abstract declaration of "Abstract" base classes
Closes gh-25240
2020-06-11 23:43:41 +02:00
Juergen Hoeller ae1ed9d458 Document exception handling limitations in TaskDecorator implementations
Closes gh-25231
2020-06-10 22:52:01 +02:00
Juergen Hoeller 8697026987 Support for custom cache registration in CaffeineCacheManager
Closes gh-25230
2020-06-10 22:50:11 +02:00
Rossen Stoyanchev 1d0fe1223d Fix checkstyle violation 2020-06-09 11:47:05 +01:00
Rossen Stoyanchev b48ddef4c6 Upgrade to RSocket 1.0.1 2020-06-09 08:59:55 +01:00
Spring Buildmaster d0a9e359aa Next Development Version 2020-06-09 06:51:55 +00:00
Rossen Stoyanchev a2d516d526 Replace "whitelist" with alternative words 2020-06-08 21:19:28 +01:00
Juergen Hoeller 4c29bbb77f Upgrade to Reactor Dysprosium-SR8
Closes gh-25210
2020-06-08 20:23:37 +02:00
Juergen Hoeller d2cd4c50f4 Upgrade to Tomcat 9.0.36 2020-06-08 19:38:23 +02:00
Juergen Hoeller c777468056 Polishing 2020-06-08 19:37:58 +02:00
Sam Brannen 721fd20708 Document advice precedence in reference manual
This commit documents the precedence for advice declared within the
same @Aspect class or within the same <aop:aspect> element.

See gh-25186
2020-06-08 19:06:46 +02:00
Sam Brannen 0b760c15ea Polish AOP chapter in reference manual 2020-06-08 19:06:46 +02:00
Rossen Stoyanchev 9e1121fd8d Document behavior on reactive tx cancellation
Closes gh-25091
2020-06-08 17:43:52 +01:00
Arjen Poutsma 0ccf5e19aa Undo MockServerRequest deprecation
Setting path variables (and making sure they are available in a
HandlerFunction) is more convenient with MockServerRequest than
having to set attributes in MockServerWebExchange.

This commit removes MockServerRequest's deprecation.

Closes gh-25087
2020-06-08 15:40:09 +02:00
Sam Brannen 0998bd49ef Implement reliable advice invocation order within an @Aspect
The AspectJPrecedenceComparator was designed to mimic the precedence
order enforced by the AspectJ compiler with regard to multiple 'after'
methods defined within the same aspect whose pointcuts match the same
joinpoint. Specifically, if an aspect declares multiple @After,
@AfterReturning, or @AfterThrowing advice methods whose pointcuts match
the same joinpoint, such 'after' advice methods should be invoked in
the reverse order in which they are declared in the source code.

When the AspectJPrecedenceComparator was introduced in Spring Framework
2.0, it achieved its goal of mimicking the AspectJ compiler since the
JDK at that time (i.e., Java 5) ensured that an invocation of
Class#geDeclaredMethods() returned an array of methods that matched the
order of declaration in the source code. However, Java 7 removed this
guarantee. Consequently, in Java 7 or higher,
AspectJPrecedenceComparator no longer works as it is documented or as
it was designed when sorting advice methods in a single @Aspect class.
Note, however, that AspectJPrecedenceComparator continues to work as
documented and designed when sorting advice configured via the
<aop:aspect> XML namespace element.

PR gh-24673 highlights a use case where AspectJPrecedenceComparator
fails to assign the highest precedence to an @After advice method
declared last in the source code. Note that an @After advice method
with a precedence higher than @AfterReturning and @AfterThrowing advice
methods in the same aspect will effectively be invoked last due to the
try-finally implementation in AspectJAfterAdvice.invoke() which invokes
proceed() in the try-block and invokeAdviceMethod() in the
finally-block.

Since Spring cannot reliably determine the source code declaration
order of annotated advice methods without using ASM to analyze the byte
code, this commit introduces reliable invocation order for advice
methods declared within a single @Aspect. Specifically, the
getAdvisors(...) method in ReflectiveAspectJAdvisorFactory now hard
codes the declarationOrderInAspect to `0` instead of using the index of
the current advice method. This is necessary since the index no longer
has any correlation to the method declaration order in the source code.
The result is that all advice methods discovered via reflection will
now be sorted only according to the precedence rules defined in the
ReflectiveAspectJAdvisorFactory.METHOD_COMPARATOR. Specifically, advice
methods within a single @Aspect will be sorted in the following order
(with @After advice methods effectively invoked after @AfterReturning
and @AfterThrowing advice methods): @Around, @Before, @After,
@AfterReturning, @AfterThrowing.

The modified assertions in AspectJAutoProxyAdviceOrderIntegrationTests
demonstrate the concrete effects of this change.

Closes gh-25186
2020-06-08 14:18:28 +02:00
Sam Brannen d6525cfb97 Polishing 2020-06-08 14:17:39 +02:00
Juergen Hoeller d01830355d Upgrade to Jetty Reactive HttpClient 1.1.3 2020-06-06 18:49:47 +02:00
Juergen Hoeller 65154170d3 Polishing 2020-06-06 18:49:32 +02:00
Juergen Hoeller d71957ce7c Polishing 2020-06-06 17:45:12 +02:00
Juergen Hoeller 7244f03064 Avoid unnecessary creation of not-found entity in ResponseEntity#of
Closes gh-25183
2020-06-06 17:44:30 +02:00
Juergen Hoeller 98030f3794 Avoid unnecessary copy of cookies map in DefaultWebClientBuilder
See gh-25034
2020-06-06 17:44:02 +02:00
Juergen Hoeller f3d4df2fd4 Consistently check available local/remote addresses for non-null 2020-06-06 15:15:16 +02:00
Juergen Hoeller 9cd9a8e86b Extend readOnlyWebSocketHttpHeaders deprecation to 5.1.16 2020-06-06 14:41:06 +02:00
Juergen Hoeller 7b7d0a353d Upgrade to Hibernate ORM 5.4.17 and Checkstyle 8.33 2020-06-06 13:22:55 +02:00
Juergen Hoeller d14140da69 Polishing 2020-06-06 13:21:46 +02:00
Juergen Hoeller 196bb6fe32 Support for shared GroovyClassLoader in GroovyScriptFactory
Exposes setClassLoader method in ConfigurableApplicationContext interface as obvious first-class configuration option.

Closes gh-25177
2020-06-06 13:21:20 +02:00
Juergen Hoeller ad5710c1d1 Restore original readOnlyHttpHeaders signature for binary compatibility
Closes gh-25034
2020-06-06 13:14:47 +02:00
Sam Brannen fbeecf3bf8 Test status quo for invocation order of all advice types
Prior to this commit we did not have tests in place to verify the status
quo for the invocation order of all advice types when declared within
a single aspect, either via the <aop:aspect> XML namespace or AspectJ
auto-proxy support.

This commit introduces such tests that demonstrate where such ordering
is broken or suboptimal.

The only test for which the advice invocation order is correct or at
least as expected is the afterAdviceTypes() test method in
ReflectiveAspectJAdvisorFactoryTests, where an AOP proxy is hand crafted
using ReflectiveAspectJAdvisorFactory without the use of Spring's
AspectJPrecedenceComparator.

See gh-25186
2020-06-05 15:30:57 +02:00
Sam Brannen 04c8de4e50 Polishing 2020-06-05 15:22:41 +02:00
Arjen Poutsma 847629412f Respect MimeType charset in Jackson codecs
Before this commit, Jackson2CodecSupport and subclasses
did not check media type encoding in the supportsMimeType
method (called from canEncode/canDecode).
As a result, the encoder reported that it can write
(for instance) "application/json;charset=ISO-8859-1", but in practice
wrote the default charset (UTF-8).

This commit fixes that bug.

Closes: gh-25076
2020-06-05 10:53:28 +02:00
Arjen Poutsma eb0aae066c Respect MediaType charset in Jackson converters
Before this commit, AbstractJackson2HttpMessageConverter and subclasses
did not check media type encoding in the canRead and canWrite
methods. As a result, the converter reported that it can write
(for instance) "application/json;charset=ISO-8859-1", but in practice
wrote the default charset (UTF-8).

This commit fixes that bug.

See: gh-25076
2020-06-05 10:52:42 +02:00
Sam Brannen a61ab5d296 Fix @since tags
See gh-25186
2020-06-04 18:51:51 +02:00
Sam Brannen 63e8609f3b Test status quo for 'after' advice invocation order
See gh-25186
2020-06-04 18:37:24 +02:00
Sam Brannen 70b3de4afe Polish AspectJAdvisorFactory tests 2020-06-04 18:37:16 +02:00
Rossen Stoyanchev 8dc8d88f88 Pre-calculated RequestMappingInfo hashcode
See gh-25143
2020-06-03 06:11:35 +01:00
Rossen Stoyanchev 1e25556049 Shared PathPatternParser instance
See gh-25143
2020-06-03 05:58:10 +01:00
Sam Brannen 1ced9370cd Configure Gradle wrapper validation action
This commit configures the Gradle Wrapper Validation Action
for GitHub actions.

See: https://github.com/gradle/wrapper-validation-action

Closes gh-25175
2020-06-02 14:43:45 +02:00
Juergen Hoeller 914425eefa Polishing 2020-05-29 15:52:39 +02:00
Juergen Hoeller cd4ef6f781 Consistently refer to FlushMode.MANUAL instead of outdated NEVER
Closes gh-25158
2020-05-29 15:51:54 +02:00
Juergen Hoeller 08474aa921 Clarify JDBC-defined negative values returned from batchUpdate
Closes gh-25138
2020-05-29 15:51:19 +02:00
Juergen Hoeller 2ff22510d9 Avoid earlyApplicationEvents iteration in case of empty Set
Closes gh-25161
2020-05-29 15:50:10 +02:00
Juergen Hoeller ef626e992d Document that MapPropertySource should not contain null values
Closes gh-25142
2020-05-29 15:49:36 +02:00
Juergen Hoeller bec89dba4c Consistent MultiValueMap behavior for empty list values
This commit extracts MultiValueMapAdapter from CollectionUtils and reuses its implementation as base class of LinkedMultiValueMap.

Closes gh-25140
2020-05-29 15:48:19 +02:00
Sam Brannen 768257567d Make use of custom types configurable in YamlProcessor
Prior to this commit, there was no easy way to restrict what types could
be loaded from a YAML document in subclasses of YamlProcessor such as
YamlPropertiesFactoryBean and YamlMapFactoryBean.

This commit introduces a setSupportedTypes(Class<?>...) method in
YamlProcessor in order to address this. If no supported types are
configured, all types encountered in YAML documents will be supported.
If an unsupported type is encountered, an IllegalStateException will be
thrown when the corresponding YAML node is processed.

Closes gh-25152
2020-05-29 13:32:52 +02:00
Sam Brannen 3201671ceb Polish contribution
See gh-25149
2020-05-28 14:37:18 +02:00
dlsrb6342 fce972eec8 Fix BaseCodecConfigurer clone bug
Prior to this commit, ExchangeStrategies custom codec's reader and
writer were not registered due to a bug in BaseCodecConfigurer.

This commit fixes this by correcting the implementation of the
DefaultCustomCodecs constructor used within BaseCodecConfigurer.

Closes gh-25149
2020-05-28 12:34:29 +02:00
Rossen Stoyanchev a92f425529 Also use constant for custom mapping condition
See gh-25143
2020-05-28 06:51:57 +01:00
Rossen Stoyanchev c0c3c01afd Fix race condition in WriteResultPublisher
between subscription and error from the Publish

Closes gh-25096
2020-05-27 19:11:29 +01:00
Rossen Stoyanchev 955f77bf5d Add error message to MockServerHttpRequest
Closes gh-25109
2020-05-27 18:57:02 +01:00
Rossen Stoyanchev e9a9883aa9 Optimal initialization of empty request mapping conditions
Closes gh-25143
2020-05-27 18:57:02 +01:00
Sam Brannen 3cbc297fc6 Polish contribution
See gh-25137
2020-05-27 16:29:34 +02:00
limo520 d6cab259c3 Fix URI pattern example in webflux.adoc
Closes gh-25137
2020-05-27 16:14:47 +02:00
Juergen Hoeller ae8d0d4a12 Upgrade to Groovy 2.5.12, Caffeine 2.8.4, Apache Johnzon 1.2.6 2020-05-26 23:35:58 +02:00
Juergen Hoeller 27d5fdc5aa Polishing 2020-05-26 23:35:38 +02:00
Juergen Hoeller 1dea55dc20 WebSphereUowTransactionManager sets timeout for actual transaction only
Closes gh-25132
2020-05-26 23:34:36 +02:00
Juergen Hoeller dfa948c2ca Introduce AutowireCandidateResolver.cloneIfNecessary() method
Closes gh-25131
2020-05-26 23:33:39 +02:00
Juergen Hoeller f9aae8dd5a Consistently determine minimum number of arguments from specified index
Closes gh-25130
2020-05-26 23:33:02 +02:00
Rossen Stoyanchev 4f65ba4e74 Simplify creation of HttpContext for Apache HttpClient
Closes gh-25066
2020-05-24 21:09:49 +01:00
Rossen Stoyanchev 23a66e016e UriBuilder javadoc update
Closes gh-25055
2020-05-24 21:09:13 +01:00
Rossen Stoyanchev c3e55d537e DefaultResponseErrorHandler javadoc update
Closes gh-25067
2020-05-23 10:41:35 +01:00
Rossen Stoyanchev d7a29bbcef DefaultClientResponseBuilder copies logPrefix
Closes gh-25069
2020-05-23 10:41:07 +01:00
Rossen Stoyanchev 8204055924 MockServerHttpRequest accepts custom HTTP method
Closes gh-25109
2020-05-23 10:40:25 +01:00
Juergen Hoeller cd9ee98ff8 Upgrade to Jetty 9.4.29, Hibernate ORM 5.4.16, WebJars Locator 0.45 2020-05-22 17:08:02 +02:00
Juergen Hoeller 4018b462f1 JdbcOperations polishing (backported from master) 2020-05-22 16:35:34 +02:00
Juergen Hoeller d7161f5e5e Polishing 2020-05-22 16:23:46 +02:00
Juergen Hoeller e5c079edfc Introduce serializeToByteArray/deserializeFromByteArray on (De)Serializer
Closes gh-25117
2020-05-22 16:22:59 +02:00
Juergen Hoeller 807ded24c4 Avoid ClassCastException on IllegalArgumentException from sync invocation
Closes gh-25110
2020-05-22 16:12:49 +02:00
Sam Brannen 4f2b6473ac Honor attributes configured in ServerRequest.from() builder
Prior to this commit, if attributes were configured in the builder
returned by `ServerRequest.from(...)`, those attributes were not
available in the `ServerRequest` built by the builder. In addition, any
attributes in the original `ServerRequest` supplied to
`ServerRequest.from(...)` were also ignored.

This commit addresses this issue by ensuring that the attributes
configured via DefaultServerRequestBuilder are used as the attributes
in the resulting `ServerRequest`.

This commit also polishes the Javadoc in `ServerRequest` and
`ClientResponse` and avoids the use of lambda expressions in the
constructors for `DefaultServerRequestBuilder` and
`DefaultClientResponseBuilder`.

Closes gh-25106
2020-05-20 14:10:44 +02:00
Juergen Hoeller b5b718f1e5 Upgrade to AssertJ 3.16.1, Log4J 2.13.3, Vavr 0.10.3, JAMon 2.82, Joda-Time 2.10.6, Caffeine 2.8.3, OkHttp 3.14.9, OpenPDF 1.3.17, HtmlUnit 2.40 2020-05-18 20:09:37 +02:00
Juergen Hoeller 9631db71c4 Direct exposure of StringBuilder instead of intermediate String
Closes gh-25024
2020-05-18 20:09:24 +02:00
Juergen Hoeller c35b21b49f Consistent not-null assertions for configured interceptors
Closes gh-25088
2020-05-18 14:23:05 +02:00
Juergen Hoeller 06cfd80c1c Avoid full synchronization in refreshable getBeanFactory() implementation
Closes gh-25081
2020-05-18 14:22:24 +02:00
Juergen Hoeller 35f3277910 Revised javadoc note on Lookup annotation limitations/recommendations
Closes gh-25044
2020-05-18 14:21:14 +02:00
Juergen Hoeller 28177ad91b Explicit notes on access to standard context beans in SpEL expressions
Closes gh-25037
2020-05-18 14:19:05 +02:00
Yanming Zhou 9d429e30de Fix SpelEvaluationException with example code
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
2020-05-18 14:16:15 +02:00
Juergen Hoeller e660386670 Upgrade to Checkstyle 8.32, Tomcat 9.0.35, Netty 4.1.50, Jackson 2.10.4, Hibernate ORM 5.4.15, Hibernate Validator 6.1.5 2020-05-14 00:23:50 +02:00
Juergen Hoeller fe33822fa7 Polishing 2020-05-14 00:23:20 +02:00
Juergen Hoeller 8212aaf3bb ResolvableType ignores TypeNotPresentException from generic signature
Closes gh-25064
2020-05-14 00:22:58 +02:00
Andy Wilkinson 1015f79b42 Include timeout unit in shutdown failure logging
Closes gh-25058
2020-05-12 18:42:40 +02:00
Rossen Stoyanchev ef27bc4b82 Upgrade to RSocket 1.0.0
Closes gh-25053
2020-05-12 12:00:06 +01:00
Rossen Stoyanchev 7c9ad6dd08 Add deprecation notes to the WebMvc config schema
Closes gh-23915
2020-05-12 06:50:09 +01:00
Yanming Zhou 50a4fdac6e Use Map::computeIfAbsent to simplify scope implementations
Closes gh-25038
2020-05-10 15:41:00 +02:00
Sam Brannen f5d011cb82 Filter reactive tx managers in TransactionAttributeSourceClassFilter
Prior to this commit, the TransactionAttributeSourceClassFilter
filtered out PlatformTransactionManager but not
ReactiveTransactionManager implementations.

TransactionAttributeSourceClassFilter now filters out any
TransactionManager implementation, covering both imperative and
reactive transaction managers.
2020-05-09 13:57:03 +02:00
Sam Brannen ec3d647d1d Update spring-tx.xsd regarding reactive tx mgmt support
Closes gh-25030
2020-05-08 19:49:00 +02:00
Sam Brannen 0f22a5e409 Update Javadoc regarding reactive tx mgmt support
See gh-25030
2020-05-08 19:25:22 +02:00
Sam Brannen e1b2cafb33 Polish reactive transaction mgmt documentation in reference manual
See gh-25030
2020-05-08 18:13:31 +02:00
Mark Paluch 7fbdc3ad11 Document ReactiveTransactionManager support in reference manual
See gh-25030.
2020-05-08 16:11:02 +02:00
Rossen Stoyanchev 706446a660 Deprecate unused method 2020-05-08 14:30:10 +01:00
Rossen Stoyanchev 19ba9087f5 HttpHeaders#equals handles wrapping correctly
Closes gh-25034
2020-05-08 09:37:37 +01:00
Sam Brannen 4805288122 Use SingletonSupplier for XStream instance in XStreamMarshaller
Closes gh-25017
2020-05-07 12:35:32 +02:00
Sam Brannen ce11fdfa80 Fix concurrency issues in XStreamMarshaller
Prior to this commit, if an instance of XStreamMarshaller was used
concurrently from multiple threads without having first invoked the
afterPropertiesSet() method, the private `xstream` field could be
initialized multiple times resulting in a ConcurrentModificationException
in XStream's internal DefaultConverterLookup.

This commit fixes these concurrency issues by making the `xstream` field
volatile and by implementing a double-checked locking algorithm in
getXStream() to avoid concurrent instance creation.

Closes gh-25017
2020-05-06 18:49:47 +02:00
Sam Brannen 740f0d766f Polish XStreamMarshallerTests 2020-05-06 18:17:09 +02:00
Rossen Stoyanchev 53e018362f Update samples to latest RSocket API
A follow-up fix on the upgrade to 1.0 RC7 in gh-24934,
2020-05-06 14:28:18 +01:00
swapy 9288067ea8 Add missing @PathVariable declarations in examples
Closes gh-25006
2020-05-04 11:19:19 +02:00
Rossen Stoyanchev 6659e96104 Fix failing test
See gh-24986
2020-05-01 18:20:26 +01:00
Rossen Stoyanchev aa97563853 Add UnknownContentTypeException
Closes gh-24964
2020-05-01 17:32:19 +01:00
Rossen Stoyanchev c35b3e5c82 Fix race condition in WriteResultPublisher
Closes gh-24989
2020-05-01 17:06:18 +01:00
Rossen Stoyanchev e17736dd0a Error handling improvement in AbstractSockJsSession
Closes gh-24986
2020-05-01 16:45:25 +01:00
Rossen Stoyanchev c2cce0c547 Add isDeferred to ReactiveTypeDescriptor
Closes gh-24995
2020-05-01 15:39:52 +01:00
Stephane Nicoll a5c6294d62 Next Development Version 2020-04-28 10:58:49 +02:00
Rossen Stoyanchev d2bcf1ed71 Upgrade to RSocket 1.0.0-RC7
Closes gh-24934
2020-04-28 06:28:04 +01:00
Rossen Stoyanchev afc8a5d786 Upgrade to Reactor Dysprosium-SR7
Closes gh-24892
2020-04-27 13:24:53 +01:00
Rossen Stoyanchev f425a993e7 Ignore missing STOMP decoder if session closed
Closes gh-24842
2020-04-27 13:19:43 +01:00
Juergen Hoeller 57f1e86a35 AnnotationBeanNameGenerator caches meta-annotations for stereotype check
Closes gh-24980
2020-04-27 13:47:58 +02:00
Juergen Hoeller 73fadd8b7c Polishing 2020-04-27 11:45:41 +02:00
Juergen Hoeller 127e879726 Store source in index-derived ScannedGenericBeanDefinition as well
Includes consistent constructor-level storage of derived resource in ScannedGenericBeanDefinition and ConfigurationClassBeanDefinition.

Closes gh-24978
2020-04-27 11:45:08 +02:00
Sam Brannen 59ecd4997c Optimize toString() for synthesized annotations
This commit moves the toString() implementation for synthesized
annotations from TypeMappedAnnotation to
SynthesizedMergedAnnotationInvocationHandler in order to take advantage
of the synthesized annotation attribute value cache introduced in
72b1abd226.

Closes gh-24970
2020-04-26 14:14:07 +02:00
Sam Brannen db45b80b1f Suppress warnings for deprecated AnnotationFilter.NONE enum constant
See gh-24932
2020-04-26 13:58:31 +02:00
Juergen Hoeller f6df21eaa9 Upgrade to Mockito 3.3.3, MockK 1.10, HtmlUnit 2.39, Checkstyle 8.31 2020-04-25 18:00:34 +02:00
Juergen Hoeller ad088f2157 Polishing 2020-04-25 17:59:04 +02:00
Juergen Hoeller 5bca18f091 Upgrade to Netty 4.1.49, Groovy 2.5.11, Log4J 2.13.2, Hibernate Validator 6.1.4 2020-04-25 16:37:58 +02:00
Juergen Hoeller af65b1ca62 Polishing 2020-04-25 16:37:16 +02:00
Juergen Hoeller e5a292fb34 Deprecate AnnotationFilter.NONE and document MergedAnnotations design
Closes gh-24932
2020-04-25 16:36:44 +02:00
Juergen Hoeller e36a415994 Explain FactoryBean lifecycle management and destroy method handling
Closes gh-24948
2020-04-25 16:34:59 +02:00
Juergen Hoeller 401f9599ca Caching of autowire candidate metadata for injection point matching
Closes gh-24904
2020-04-25 16:34:28 +02:00
Juergen Hoeller 0552102780 Enforce limit for storing suppressed exceptions
Closes gh-24902
2020-04-25 16:33:35 +02:00
liuhy365 3af54692fa Fix parent bean factory self-reference issue.
If set parent bean factory to self, once try to get an undefined bean,  bellow condition
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
...
}
will always be true and  StackOverflowError will be thrown.
Sometimes, this issue is hard to detect during runtime, if self-reference is not allowed here, error will be found at the early time of startup.
Also, a self-reference parent bean factory is valueless.
2020-04-25 16:28:09 +02:00
mattbertolini 21887ad23b Allow override of data binder binding
Motivation
----------
The Spring MVC ModelAttributeMethodProcessor includes many helpful
extension methods that allow developers to extend and enhance the data
binding capabilities of the class. Unfortunately, Spring WebFlux's
equivalent class, the ModelAttributeMethodArgumentResolver, does not
include these same extension methods. I am leveraging these extension
methods, specifically the bindRequestParameters method, to provide
valuable enhancements to my application. I would like to provide these
same enhancements to the WebFlux portion of my application and am
unable to do so at this time. I would like to update the WebFlux
ModelAttributeMethodArgumentResolver to add the bindRequestParameters
method.

Modifications
-------------
I created a new method called bindRequestParameters and encapsulated
the WebExchangeDataBinder bind call inside of it. This method is
marked as protected as it should only be used by children of this
class. This change mirrors the behavior in the equivalent Spring MVC
class (ModelAttributeMethodProcessor).

Result
------
The WebFlux ModelAttributeMethodArgumentResolver can now accept
alternative data binding implementations mirroring the Web MVC
behavior.
2020-04-25 16:27:36 +02:00
Сергей Цыпанов bff1a1932f Rid pointless wrapping with BufferedInputStream from class reading 2020-04-25 16:27:01 +02:00
Sam Brannen 72b1abd226 Reintroduce synthesized annotation attribute value caching
Prior to the introduction of the MergedAnnotation API in Spring Framework
5.2, our SynthesizedAnnotationInvocationHandler utilized a cache for
annotation attribute values; whereas, the new
SynthesizedMergedAnnotationInvocationHandler has no such caching in
place.

Issues such as gh-24961 indicate a regression in performance caused by
the lack of such an attribute value cache. For example, the required
attribute in @RequestParam is looked up using the internal meta-model
in the MergedAnnotation API twice per request for each @RequestParam in
a given controller handler method.

This commit reintroduces the attribute value cache to avoid the
unnecessary performance overhead associated with multiple lookups of
the same attribute in a synthesized annotation. This applies not only
to direct attribute method invocations but also to invocations of
equals() and hashCode() on a synthesized annotation.

Note, however, that this commit does NOT address multiple lookups of
annotation attribute values for invocations of toString(). That behavior
currently remains unchanged in the implementation of
org.springframework.core.annotation.TypeMappedAnnotation.toString().

Closes gh-24970
2020-04-25 15:28:09 +02:00
rahulmlokurte 0e9da17910 Fix typo in webmvc-functional.adoc
Closes gh-24968
2020-04-25 09:24:15 +02:00
Rossen Stoyanchev 583435d068 Consistent ordering in MethodNotAllowedException
This caused random failures in a newly added test. Also remove defensive
check in ResponseStatusExceptionResolver.

See gh-24944
2020-04-25 07:33:30 +01:00
Rossen Stoyanchev 2002a1689a Adapt test to changes in RSocket Java
See gh-24934
2020-04-25 07:11:34 +01:00
Rossen Stoyanchev 18474c921d Document IAE in HttpHeaders methods that parse ETags
See gh-24950
2020-04-24 13:02:12 +01:00
Rossen Stoyanchev d9262b8a0c Suppress deprecated Reactor Netty call
See gh-24892
2020-04-24 12:57:16 +01:00
Rossen Stoyanchev e18901d6b1 Headers support in ResponseStatusExceptionResolver
Closes gh-24944
2020-04-24 12:53:00 +01:00
Sam Brannen 8265db0ae1 Avoid synthesizing annotations unnecessarily
Commit 31fa1569c5 introduced initial support for avoiding unnecessary
annotation synthesis in the MergedAnnotation API; however, it only
avoided synthesis for annotations that do not declare any attributes.

This commit reworks this support to avoid unnecessary annotation
synthesis for annotations that declare attributes.

Specifically, this commit introduces a new `isSynthesizable()` method
in AnnotationTypeMapping that allows the "synthesizable" flag to be
computed once and cached along with the other metadata already cached
in AnnotationTypeMapping instances. TypeMappedAnnotation now delegates
to this new method when determining whether it should synthesize an
annotation.

Closes gh-24861
2020-04-23 19:09:30 +02:00
Rossen Stoyanchev 0520ee0fb6 Use the Reactor Netty WebsocketServerSpec
Closes gh-24959
2020-04-23 13:50:00 +01:00
Brian Clozel dc4cda1b13 WARN against invalid patterns with PathPatternParser
As of gh-24952, `PathPatternParser` will strictly reject patterns with
`"**"` in the middle of them. `"**"` is only allowed at the end of the
pattern for matching multiple path segments until the end of the path.

Currently, if `"**"` is used in the middle of a pattern it will be
considered as a single `"*"` instead. Rejecting such cases should
clarify the situation.

This commit prepares for that upcoming change and:

* logs a warning message if such a case is used by an application
* expands the MVC and WebFlux documentation about URI matching in
general

Closes gh-24958
2020-04-23 13:03:05 +02:00
Sam Brannen 5eba1ae73c Avoid deprecation warning in DefaultRSocketRequesterBuilderTests 2020-04-22 19:19:34 +02:00
Sam Brannen a9cc7b3edc Improve tests for synthesized array of annotations 2020-04-22 15:17:33 +02:00
Sam Brannen 5721c747b2 Polishing 2020-04-21 18:47:28 +02:00
Sam Brannen 31fa1569c5 Avoid synthesizing annotations unnecessarily
Prior to Spring Framework 5.2, some of our annotation utilities would
not synthesize an annotation if it was already synthesized or not
synthesizable (i.e., did not declare local aliases via @AliasFor and
did not declare attributes that could override attributes in the
meta-annotation hierarchy above the given annotation); however, we lost
most of this functionality with the introduction of the new
MergedAnnotations API.

This commit revises the implementation of createSynthesized() in
TypeMappedAnnotation so that, for invocations of
MergedAnnotation.synthesize() and indirectly for invocations of
AnnotatedElementUtils.findMergedAnnotation(), etc.:

1. An annotation that was previously synthesized will not be
   synthesized again.

2. An annotation that is not "synthesizable" will not be synthesized.

For both of the above use cases, the original annotation is now
returned from createSynthesized().

Closes gh-24861
2020-04-21 13:31:06 +02:00
Rossen Stoyanchev 8d31dcaa29 Clarification on path extension deprecations
Closes gh-24642
2020-04-20 14:43:07 +01:00
Rossen Stoyanchev 4b85b44bbd Update Javadoc of InputStreamResource#contentLength
Closes gh-20990
2020-04-20 12:53:42 +01:00
Rossen Stoyanchev fa5e8485ab Update StackOverflow link 2020-04-20 12:32:11 +01:00
Rossen Stoyanchev 1904e9b7e7 Disable failing test temporarily 2020-04-20 10:16:40 +01:00
Sébastien Deleuze 6d5080825c Remove potentially confusing kotlin-reflect related log message
Closes gh-24935
2020-04-20 11:00:29 +02:00
Rossen Stoyanchev ed8c61a852 Upgrade to RSocket 1.0 RC7 snapshots 2020-04-20 09:42:28 +01:00
Sam Brannen 376434eb75 Polishing 2020-04-19 19:17:02 +02:00
Sam Brannen f42955c31b Polishing 2020-04-19 17:49:08 +02:00
Mikael d6c9c7d642 Simplify substring() usage in MimeTypeUtils
Closes gh-24933
2020-04-19 17:39:06 +02:00
Sam Brannen 3dadcaeb2d Polishing 2020-04-17 19:07:49 +02:00
Johnny Lim 87fa2c3b97 Avoid unnecessary String instantiation in StringUtils.deleteAny()
This commit avoids unnecessary String instantiation in
StringUtils.deleteAny() if nothing was deleted from the
input string.

Closes gh-24924
2020-04-17 18:44:16 +02:00
Deycoesr 87f28ce48e Simplify some control flow code
Closes gh-24925
2020-04-17 18:32:02 +02:00
Sam Brannen b8835c9f32 Copy MockHttpServletRequest changes to spring-web
See gh-24916
2020-04-17 16:20:42 +02:00
Sam Brannen 6b410df45b Retain brackets for IPV6 address in MockHttpServletRequest
According to the Javadoc for ServletRequest's getServerName() method,
when the `Host` header is set, the server name is "the value of the
part before ':' in the Host header value ...". For a value representing
an IPV6 address such as `[::ffff:abcd:abcd]`, the enclosing square
brackets should therefore not be stripped from the enclosed IPV6
address.

However, the changes made in conjunction with gh-16704 introduced a
regression in Spring Framework 4.1 for the getServerName() method in
MockHttpServletRequest by stripping the enclosing brackets from the
IPV6 address in the `Host` header. Similarly, the changes made in
conjunction with gh-20686 introduced a regression in Spring Framework
4.3.13 and 5.0.2 in the getRequestURL() method in
MockHttpServletRequest by delegating to the getServerName() method
which strips the enclosing brackets.

This commit fixes the implementation of getServerName() so that the
enclosing brackets are no longer stripped from an IPV6 address in the
`Host` header. The implementation of getRequestURL() is therefore also
fixed.

In addition, in order to avoid a NullPointerException, the
implementations of getServerName() and getServerPort() now assert that
an IPV6 address present in the `Host` header correctly contains an
opening and closing bracket and throw an IllegalStateException if that
is not the case.

Closes gh-24916
2020-04-17 15:01:35 +02:00
Sam Brannen 0017256968 Test that @TestConstructor can be used as a meta-annotation 2020-04-17 13:29:33 +02:00
Oliver Degener df291a39b1 Fix Javadoc link in DefaultCorsProcessor
Closes gh-24921
2020-04-17 09:26:53 +02:00
Brian Hartung 1658223e58 Fixed typo
Fixed another small documentation typo.
2020-04-15 14:20:35 +01:00
Brian Hartung 89775844ed Fixed typos
Fixed a couple of minor documentation typos
2020-04-15 14:20:35 +01:00
Juergen Hoeller d211381b58 Upgrade to Tomcat 9.0.34, Jetty 9.4.28, Hibernate ORM 5.4.14, Hibernate Validator 6.1.3 2020-04-15 13:05:02 +02:00
Sébastien Deleuze a33a6c310a Upgrade to Kotlin 1.3.72 2020-04-15 12:12:59 +02:00
Sébastien Deleuze 67955dfb35 Prevent duplicated Vary headers in CORS processing
Closes gh-24829
2020-04-15 11:23:59 +02:00
Stephane Nicoll ae8f333d36 Merge pull request #24908 from chenqimiao
* pr/24908:
  Fix typo in Javadoc

Closes gh-24908
2020-04-15 08:37:58 +02:00
陈其苗 1e1ea34e87 Fix typo in Javadoc
See gh-24908
2020-04-15 08:36:33 +02:00
onnadi-sa 75457c440c Fix typo in webflux-functional.adoc
Closes gh-24906
2020-04-14 15:42:50 +02:00
Sébastien Deleuze 884c7696ce Make it possible to run Spring MVC without kotlin-reflect
Closes gh-24828
2020-04-14 14:56:47 +02:00
Sam Brannen 3aa7f45738 Upgrade to JUnit 5.6.2 2020-04-14 14:49:11 +02:00
Sam Brannen 154fa29471 Upgrade to spring-doc-resources 0.2.1
See gh-24865
2020-04-14 13:36:11 +02:00
Stephane Nicoll 4523d9586f Start building against Reactor Dysprosium-SR7 snapshots
See gh-24892
2020-04-10 17:16:31 +02:00
Brian Clozel 39536acf9f Fix potential leak in MimeTypeUtils LRUCache
Prior to this commit, the `MimeTypeUtils` LRUCache would maintain a
queue to track least recently used cached values. In some cases,
concurrent access could create more entries in that unbounded queue than
expected and spend a significant amount of time removing entries in that
queue (i.e. iterating over a long list of elements).

This commit ensures that recently used entries are only added to the
queue if they've been removed by the current thread, in case of
concurrent access.

Fixes gh-24886
2020-04-09 15:38:01 +02:00
Juergen Hoeller de0d06fab5 Polishing 2020-04-09 11:49:35 +02:00
Lars Grefer 8682a5d89a Honor overriden AccepptHeaderLocaleContextResolver.getDefaultLocale() 2020-04-09 11:37:50 +02:00
Сергей Цыпанов e1951a098b Improve performance of StringUtils.deleteAny() 2020-04-09 11:36:32 +02:00
Sam Brannen 8c0aaf4863 Delete meaningless "performance" test
The test deleted in this commit didn't even assert anything to begin
with.

See gh-24830
2020-04-08 15:21:32 +02:00
Sam Brannen 9628038c58 Upgrade to BeanShell 2.0b6 2020-04-07 18:06:43 +02:00
Sébastien Deleuze 3c354a9b18 Avoid using Mockito argument matcher in Mockk test 2020-04-07 16:38:09 +02:00
Sam Brannen 6c26765985 Document default constructor as fallback for non-@Autowired constructors
Prior to this commit, it was unclear in the documentation that a default
constructor will be used by default for autowiring if multiple
constructors are present and none of them is annotated with @Autowired.

This commit improves the documentation in this regard.

Closes gh-24838
2020-04-07 14:35:40 +02:00
Sam Brannen a5498ba2ad Test status quo for @Primary + TransactionManagementConfigurer in TCF
This commit introduces an integration test for the status quo in the
Spring TestContext Framework (TCF) for multiple transaction managers
registered as @Primary and via the TransactionManagementConfigurer API.

In Spring Framework 5.3 we will revise the transaction manager lookup in
TestContextTransactionUtils so that the transaction manager configured
via the TransactionManagementConfigurer API is favored over a @Primary
transaction manager.

See gh-24869
2020-04-06 19:11:53 +02:00
Sam Brannen a42944d364 Consolidate TxMgr lookup tests in the TCF
This commit consolidates TransactionManager lookup tests in the Spring
TestContext Framework (TCF), migrates some to JUnit Jupiter, simplifies
their implementations, and removes duplicated test cases.
2020-04-06 18:21:48 +02:00
Sam Brannen 1d0c5195bc Polish Javadoc for TransactionManagementConfigurer 2020-04-06 15:31:48 +02:00
Sam Brannen 144b0e1437 Test status quo for @Primary + TransactionManagementConfigurer
This commit introduces tests for the status quo in production support
for multiple transaction managers registered as @Primary and via the
TransactionManagementConfigurer API.

See gh-24869
2020-04-06 15:16:31 +02:00
Sam Brannen dc5ddffd03 Polishing 2020-04-06 14:42:23 +02:00
Sam Brannen f8ab19dc68 Ensure @EnableTxMgmt tests actually test something 2020-04-06 14:32:34 +02:00
Qimiao Chen fd8d11c7e3 Use single String instead of String[] for varargs argument
Closes gh-24864
2020-04-04 20:05:19 +02:00
Juergen Hoeller 251501587b Consistent nullability of arguments array in JdbcOperations/Template
Closes gh-24839
2020-04-03 21:15:00 +02:00
Juergen Hoeller 6177e38eb6 Close-suppressing Connection proxy exposes target isClosed() state
Closes gh-24853
2020-04-03 21:13:53 +02:00
Juergen Hoeller a70ad0094f Clear by-type cache in case of no pre-existing bean definition as well
Closes gh-24852
2020-04-03 21:12:03 +02:00
Juergen Hoeller 151a18d691 Explicit notes on BeanFactory.getType vs bean class in bean definition
Closes gh-24816
2020-04-03 21:11:07 +02:00
Juergen Hoeller 8595f01e44 Polishing 2020-04-03 21:08:45 +02:00
Moran Avigdor 7d5e474e0d Recursively copy directory with symbolic link
The following modification will also recursively traverse the directory that the symbolic link points to.
This modification is not proposed for deleteRecursively, since it can be harmful if not intended.

This modification relates to the following commit:
Consistent use of NIO.2 for file read/write interactions
Issue: SPR-15748
12114a9
2020-04-03 21:05:26 +02:00
Sam Brannen 9f0ce09cf0 Update copyright date 2020-04-02 16:33:50 +02:00
Sam Brannen 0636ba68d7 Fix Javadoc in PathPattern (#24841)
* corrected javadoc

* Revert change to PathPattern Javadoc

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-04-02 16:29:27 +02:00
Sam Brannen c9e13d448a Revert change to PathPattern Javadoc 2020-04-02 16:28:26 +02:00
Rossen Stoyanchev 897557fd1b Fix faulty tests
The tests were doing Callable async request processing in the main
thread which was already bound (via HandlerInterceptor#preProcess).
This leads to an ISE from TransactionSynchronizationManager#bindResource
but it went unnoticed because there is no Servlet container and no
async dispatch to continue processing.

See gh-24835
2020-04-02 09:31:00 +01:00
Rossen Stoyanchev 6f0a76a65f Polishing
See gh-24835
2020-04-02 08:34:44 +01:00
Gurps Bassi 4aca91c3b0 corrected javadoc 2020-04-01 22:05:53 +01:00
Rossen Stoyanchev 7d0f48289b Improve error handling in WebAsyncManager
See gh-24835
2020-04-01 18:35:22 +01:00
Sam Brannen a842434bff Document precedence for @DynamicPropertySource
Closes gh-24837
2020-04-01 18:09:31 +02:00
Jay Bryant b7eb983107 Update to spring-doc-resources version 0.2.0
This commit updates the spring-doc-resources version to 0.2.0 to get the
latest look and feel in the HTML version of the reference manual.

Closes gh-24831
2020-04-01 14:52:58 +02:00
陈其苗 13970ae528 Use autoboxing instead of explicit wrapping in tests
Closes gh-24801
2020-04-01 14:34:20 +02:00
Sam Brannen d8567749b8 Fix Javadoc 2020-03-31 19:14:56 +02:00
Sam Brannen 01cf0a3d4e Polish MBeanClientInterceptorTests and recover two lost tests
Two test methods were missing the @Test annotation after the migration
from JUnit 3 to JUnit 4.
2020-03-31 19:02:15 +02:00
Sam Brannen 9bd74c270f Remove flaky check in MBeanClientInterceptorTests
Prior to this commit, the testTestLazyConnectionToRemote() method in
MBeanClientInterceptorTests expected an exception to be thrown while
attempting to access the state of a proxied MBean after the MBeanServer
had been shutdown; however, the test occasionally failed if the server
had not been properly shutdown.

Since an attempt to wait on the server to shutdown proved not to be
consistently helpful in this scenario, we are entirely removing this
check from the test.
2020-03-31 18:55:54 +02:00
Sam Brannen 89d282125a Ensure logPrefix is not null or blank in AbstractListenerWriteProcessor 2020-03-31 18:49:05 +02:00
Sam Brannen e87ab6f4ee Update Javadoc for AbstractListenerWriteProcessor.write()
Co-authored-by: Rossen Stoyanchev <rstoyanchev@pivotal.io>
2020-03-31 18:47:06 +02:00
Rossen Stoyanchev 99c2b1e242 Add snippet for maxInMemorySize config
See gh-23961
2020-03-31 17:08:12 +01:00
Juergen Hoeller 1795a6ad0a Upgrade to Hibernate ORM 5.4.13, Apache Johnzon 1.2.4, OpenPDF 1.3.14, Woodstox 6.1.1 2020-03-31 16:44:02 +02:00
Sam Brannen ddaf0029ae Polishing 2020-03-31 16:31:34 +02:00
Rossen Stoyanchev 95ef9c25c2 Reduce byte[] allocations in StompEncoder
Closes gh-24694
2020-03-31 12:56:10 +01:00
Sam Brannen 329f08ad08 Suppress warnings in Gradle build 2020-03-31 12:17:58 +02:00
Sam Brannen e26764d249 Remove duplicate words in documentation and polish Javadoc 2020-03-31 12:17:58 +02:00
Sam Brannen 53106d5741 Polishing 2020-03-31 10:40:04 +02:00
Juergen Hoeller 3ad42aa983 Upgrade to Tomcat 9.0.33, FreeMarker 2.3.30, Apache HttpClient 4.5.12, WebJars Locator 0.44, JRuby 9.2.11.1 2020-03-30 19:04:06 +02:00
Taehee Kim 8b3521d2bf Fix typo in webflux-cors.adoc
Closes gh-24815
2020-03-30 14:00:25 +02:00
Sam Brannen ee42e3e730 Polish StreamUtils 2020-03-30 13:57:09 +02:00
Sam Brannen 9e30620ac2 Polish contribution
See gh-24805
2020-03-30 13:47:00 +02:00
Сергей Цыпанов e63d1cf12d Improve usage of ByteArrayOutputStream/ByteArrayInputStream
Closes gh-24805
2020-03-30 13:22:21 +02:00
Qimiao Chen 821984a5cf Remove unnecessary assignment in PropertiesBeanDefinitionReader
Closes gh-24804
2020-03-30 12:41:19 +02:00
Qimiao Chen f8ff4e42b9 Use try-with-resource to close resources
Closes gh-24807
2020-03-30 12:05:29 +02:00
Qimiao Chen 7c831d2ef4 Replace anonymous inner classes with lambdas in tests
Closes gh-24808
2020-03-30 12:02:23 +02:00
Qimiao Chen 7db00c9e22 Remove incorrect @Nullable in DynamicPropertiesContextCustomizer
Closes gh-24796
2020-03-28 15:29:01 +01:00
Qimiao Chen 5d6139eb7a Set initialValue of NamedThreadLocal in XmlBeanDefinitionReader
This commit overrides initialValue() of NamedThreadLocal to lazily initialize
the set used in XmlBeanDefinitionReader.

Closes gh-24800
2020-03-27 14:58:55 +01:00
Sam Brannen 06fa8692cd Attempt to make MBeanClientInterceptorTests more robust 2020-03-27 11:18:45 +01:00
Qimiao Chen c77853b766 Remove unnecessary mem alloc in CollectingReaderEventListener
Closes gh-24799
2020-03-27 11:00:05 +01:00
Rossen Stoyanchev a606fb4b21 Fix checkstyle errors 2020-03-26 22:02:32 +00:00
Rossen Stoyanchev 6f1ea14718 Merge pull request #24786 from stsypanov/data-buffer
Closes gh-24786
2020-03-26 21:42:33 +00:00
Rossen Stoyanchev 3175f0771e Remove dumpString from DataBufferTestUtils
See gh-24786
2020-03-26 21:42:12 +00:00
Rossen Stoyanchev 7aa06b8610 Polishing contribution
See gh-24786
2020-03-26 21:42:12 +00:00
Сергей Цыпанов f17b0125ff Simplify conversion of DataBuffer to String
See gh-24786
2020-03-26 21:42:12 +00:00
Sam Brannen ac11acb532 Optimize sorting in PostProcessorRegistrationDelegate
Closes gh-24776
2020-03-26 17:32:38 +01:00
Rossen Stoyanchev dd3dd5d67d UriComponentsBuilder.cloneBuilder copies uriVariables
Closes gh-24772
2020-03-26 16:31:25 +00:00
Juergen Hoeller 593a2ade91 Expose context class for interface-based CGLIB proxies as well
Closes gh-24657
2020-03-26 17:30:37 +01:00
Rossen Stoyanchev f720225c22 Merge toBodilessEntity fix and refactoring
Closes gh-24788
2020-03-26 15:59:44 +00:00
Rossen Stoyanchev 1822f272c7 toBodilessEntity() actually drains response body
See gh-24788
2020-03-26 15:59:28 +00:00
Rossen Stoyanchev 5309757026 WebClientIntegrationTests refactoring
- consistent test naming
- grouping by category and logical ordering within category
- consolidate overlapping tests
- polishing

See gh-24788
2020-03-26 15:59:04 +00:00
Rossen Stoyanchev d1cf16320b Minor refactoring and polishing in WebClientUtils
See: gh-24788
2020-03-26 15:59:04 +00:00
Sam Brannen 6222efc54b Polish contribution
See gh-24785
2020-03-26 16:52:24 +01:00
Сергей Цыпанов 65aa2d03f0 Simplify conversion of ByteArrayOutputStream to String
Closes gh-24785
2020-03-26 16:52:14 +01:00
Andy Wilkinson 62c545d0ed Upgrade to Gradle Build Scan Plugin 3.2
Closes gh-24793
2020-03-26 16:27:06 +01:00
Qimiao Chen 9f2fd4f0d5 Fix broken link in Javadoc for DynamicPropertySource
Closes gh-24792

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-03-26 16:20:55 +01:00
Qimiao Chen 1f9fa3bab8 Remove useless .gitignore files
Closes gh-24790
2020-03-26 15:53:39 +01:00
Sam Brannen fb0b915e3d Remove obsolete comment in BeanDefinitionParserDelegate (#24789)
* Fix typo in BeanDefinitionParserDelegate

* Update spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-03-26 15:48:48 +01:00
Sam Brannen 3e9d51220d Update spring-beans/src/main/java/org/springframework/beans/factory/xml/BeanDefinitionParserDelegate.java 2020-03-26 15:47:46 +01:00
Mikael Elm 822ca0130a Fix typos and improve readability in Webflux documentation
Closes gh-24781
2020-03-26 15:16:22 +01:00
陈其苗 072961b91a Fix typo in BeanDefinitionParserDelegate 2020-03-26 20:11:06 +08:00
Sam Brannen 5c977ce119 Make remaining static fields final in CommonAnnotationBPP 2020-03-25 18:58:56 +01:00
Sam Brannen 6d0bab332c Polishing 2020-03-25 18:41:21 +01:00
Arjen Poutsma 9fb614a5c6 Clarify the role of views with Spring MVC
This commit adds a section to the reference docs that explains
views live within the trust boundary of the application, and the
security implications thereof.

Closes gh-24777
2020-03-25 15:05:50 +01:00
Qimiao Chen c42a0eeb38 Make resourceAnnotationTypes field final in CommonAnnotationBPP
Closes gh-24774
2020-03-25 14:34:29 +01:00
Johnny Lim 0f50a9a60a Fix empty domain handling in ResponseCookie
This commit also updates its test to use its intended inputs.
2020-03-25 08:18:03 +00:00
Sam Brannen c24fa22a1b Polishing 2020-03-24 14:22:42 +01:00
Sam Brannen 4be358e47f Cross reference Dynamic Property Sources section 2020-03-24 14:07:56 +01:00
Spring Buildmaster d26b84acd6 Next Development Version 2020-03-24 11:33:18 +00:00
Brian Clozel d97eabba2f Do not cache multipart MIME types in cache
Prior to this commmit, "mutipart/*" MIME types would be cached by the
`MimeTypeUtils` LRU cache. Since those MIME types are likely to have
random boundaries in them, they can waste space in the LRU cache.
This is not improving things since we're parsing them anyway.

This commit skips the caching step for all "multipart" MIME types.

Fixes gh-24767
2020-03-24 10:59:05 +01:00
Sébastien Deleuze 1cd0e720f7 Specify that Kotlin code samples leverage kotlin-allopen 2020-03-24 10:31:57 +01:00
Sébastien Deleuze 60dca027e7 Add Kotlin documentation and tests for @DynamicPropertySource
See gh-24540
2020-03-24 10:08:37 +01:00
Juergen Hoeller 2209e7cb92 Reuse empty class array constant in ClassUtils
Closes gh-24221
2020-03-24 00:08:43 +01:00
Juergen Hoeller fdc60311ed Avoid unnecessary trace logging in ProxyFactoryBean
Closes gh-24669
2020-03-24 00:07:40 +01:00
Christoph Dreis 1c6dda3ca4 Improve performance of StringUtils#cleanPath 2020-03-23 23:25:15 +01:00
Sam Brannen ac0363c94e Document @DynamicPropertySource support in the reference manual
Closes gh-24540
2020-03-23 20:43:38 +01:00
Sam Brannen a90716522c Include Testcontainers in Further Resources section 2020-03-23 20:05:58 +01:00
Rossen Stoyanchev b2fa574879 Upgrade to Reactor Dysprosium-SR6
Closes gh-24725
2020-03-23 17:36:39 +00:00
Juergen Hoeller 910d2788e9 Polishing 2020-03-23 18:02:55 +01:00
Juergen Hoeller 2e23cf32ce Clarify name generation responsibility for PropertySourceFactory impls
Closes gh-24757
2020-03-23 18:02:05 +01:00
Juergen Hoeller bb1699a9d3 Revise documentation for autowiring with annotated constructors
Closes gh-24711
2020-03-23 18:01:30 +01:00
Juergen Hoeller 10d47d4d21 Enable ASM8_EXPERIMENTAL for Java 14 record support
Closes gh-24722
2020-03-23 18:00:59 +01:00
Juergen Hoeller 1800b10717 Expose parameter annotations from interfaces across entire class hierarchy
Closes gh-24127
2020-03-23 17:57:44 +01:00
Juergen Hoeller 7ebd850b85 Mark MediaTypeNotSupportedStatusException as deprecated
Closes gh-24743
2020-03-23 17:56:28 +01:00
Juergen Hoeller fd1ca46ca1 Thread-safe access to WebSocketServerFactory and WebSocketExtensions
See gh-24745
2020-03-23 17:56:14 +01:00
Sébastien Deleuze b7b36891fb Upgrade to Kotlin 1.3.71 2020-03-23 17:41:55 +01:00
Sam Brannen cf7daa36c8 Add @DynamicPropertySource support in TestContext framework
This commit introduces a @DynamicPropertySource annotation that can be
used on methods in test classes that want to add properties to the
Environment with a dynamically supplied value.

This new feature can be used in conjunction with Testcontainers and
other frameworks that manage resources outside the lifecycle of a
test's ApplicationContext.

Closes gh-24540

Co-authored-by: Phillip Webb <pwebb@pivotal.io>
2020-03-23 17:10:18 +01:00
陈其苗 821a8eebdd Improve Javadoc in Configuration 2020-03-23 15:42:45 +01:00
陈其苗 0463d7fcb9 Set proxyBeansMethod to false when no method is called 2020-03-23 15:42:23 +01:00
陈其苗 0e5f27c94e Introduce NonNull to package-info 2020-03-23 15:42:02 +01:00
Rossen Stoyanchev e11373fe69 Unwrap XMLStreamException from cause
Closes: gh-24622
2020-03-23 12:22:43 +00:00
Sébastien Deleuze 623a019ef8 Upgrade to Dokka 0.10.1
Closes gh-24764
2020-03-23 13:01:06 +01:00
Sam Brannen b069efade4 Polish Javadoc for @ManagedAttribute
See gh-24742
2020-03-23 11:34:25 +01:00
Tom van den Berge 107f88a7e4 Allow non-public Kotlin classes/ctors to be instantiated
Closes gh-24712
2020-03-23 10:47:28 +01:00
Brian Clozel 831a95154e Polish ConcurrentLruCache
This commit improves the performance of the `ConcurrentLruCache` and
applies a consistent style to the code:

* separating read/write locks into different variables does not help
performance, so this change is reverted
* apply a consistent style for read/write locks and try/cactch calls
* the reordering of recently used keys is only done when the cache is
full

Fixes gh-24671
2020-03-22 21:49:07 +01:00
Kwangyong Kim 713a112812 Improve ConcurrentLruCache performance
- manage collection size manually
- check cache hit first before size check
- reduce read-lock scope
- use `map.get` to test cache instead of `queue.remove`

Closes gh-24469
See gh-24671
2020-03-22 21:48:55 +01:00
Sam Brannen 7e7e54b75e Upgrade to JUnit 5.6.1
Closes gh-24762
2020-03-22 20:56:57 +01:00
Sam Brannen 5be0db9259 Consistently refer to t_actor table 2020-03-22 20:32:45 +01:00
Sam Brannen b52136dfa5 Revert renaming of local variable
This commit fixes the example by reverting the renaming of the local
Actor variable to avoid a conflict with a same-named variable already
in the current scope.

See gh-24398
2020-03-22 20:28:59 +01:00
Rossen Stoyanchev 1f72ab4816 Add Javadoc to ManagedAttribute
Closes: gh-24742
2020-03-20 21:50:52 +00:00
陈其苗 45a629e20a Remove unnecessary check in ConvertingEncoderDecoderSupport 2020-03-20 21:25:29 +00:00
Rossen Stoyanchev 9685380334 Fix typos 2020-03-20 21:14:56 +00:00
Qimiao Chen 09b36380cd Fix typos in source files
Closes gh-24746
2020-03-20 20:06:52 +01:00
Sam Brannen 331b14bb0b Fix NoHttp violation 2020-03-20 19:43:00 +01:00
Sam Brannen 90268de9c0 Polish implementation of BeanDefinitionReaderUtils.generateBeanName()
Closes gh-24739
2020-03-20 19:13:29 +01:00
Rossen Stoyanchev 2ca93cbe1c Update Javadoc for WebClient onStatus handlers
Closes gh-24736
2020-03-20 18:02:18 +00:00
Sam Brannen 116a256e81 Fix typos in AnnotationsScannerTests 2020-03-20 15:03:01 +01:00
Qimiao Chen 2c5781473c Improve Javadoc in AnnotatedElementUtils
Closes gh-24740
2020-03-20 15:00:17 +01:00
Rossen Stoyanchev 7efb62091d MessagingRSocket correctly handles unconsumed input
Closes gh-24741
2020-03-20 10:03:56 +00:00
Rossen Stoyanchev 0d42a1bd7f Add retry for flaky test (suspected Tomcat issue) 2020-03-19 14:32:56 +00:00
Rossen Stoyanchev a7fe6b8f5c Avoid NPE in ResponseCookie on null domain
See gh-24663
2020-03-19 12:18:29 +00:00
Rossen Stoyanchev b121c0e2ea Avoid ClassCastException in TomcatHttpHandlerAdapter
Closes gh-24707
2020-03-19 12:17:24 +00:00
Rossen Stoyanchev 5b27df772a Suppress deprecation warning
See gh-24725
2020-03-19 07:21:21 +00:00
Juergen Hoeller c2149e38fc Upgrade to Kotlin Coroutines 1.3.5 (and Checkstyle 8.30) 2020-03-18 18:38:43 +01:00
Rossen Stoyanchev e7329271fa Switch to Reactor Dysprosium snapshots
See gh-24725
2020-03-18 17:20:03 +00:00
Sam Brannen 7b94112ec6 Update documentation for custom-java-home.gradle
See gh-24719
2020-03-18 17:10:16 +01:00
Sam Brannen e6814f6609 Clean up warnings in Jsr354NumberFormatAnnotationFormatterFactory 2020-03-18 17:04:28 +01:00
Sam Brannen 678b6edad2 Delete unused method in ConfigurationClassParser 2020-03-18 17:01:33 +01:00
Sam Brannen 4bd0ad5d2e Delete obsolete log4j config 2020-03-18 17:01:01 +01:00
Yoo In Keun eaabe21c7b Delete empty .gitignore file
Closes gh-24717
2020-03-18 16:13:56 +01:00
Sam Brannen edb5e73d48 Update Kotlin example based on feedback from @lnhrdt
See gh-24398
2020-03-18 15:34:27 +01:00
Juergen Hoeller d4b2860cc9 Upgrade to Groovy 2.5.10 (and Netty 4.1.48)
Closes gh-24719
2020-03-18 12:32:23 +01:00
Sam Brannen 14f5032e97 Update Kotlin example
See gh-gh-24398
2020-03-17 19:22:26 +01:00
Sam Brannen 17140c8d4b Polish contribution
See gh-24595
2020-03-17 17:15:12 +01:00
Andrew Woodbury 2fb13d410d Include response body in UnknownHttpStatusCodeException
Spring Framework 5.2.2 introduced a regression in
DefaultResponseErrorHandler.handleError(ClientHttpResponse)
Specifically, for use cases where the InputStream had already been
consumed by the first invocation of getResponseBody(), the second
invocation of getResponseBody() resulted in the response body being
absent in the created UnknownHttpStatusCodeException.

This commit fixes this by invoking getResponseBody() only once in
DefaultResponseErrorHandler.handleError(ClientHttpReponse) in order to
reuse the retrieved response body for creating the exception message
and as a separate argument to the UnknownHttpStatusCodeException
constructor.

Closes gh-24595
2020-03-17 17:06:57 +01:00
Sam Brannen 5e1e689739 Polishing 2020-03-17 15:06:10 +01:00
Sam Brannen 7dea2686b8 Polish contribution
See gh-24398
2020-03-17 15:06:10 +01:00
maxxedev 9b827283f1 Use more lambda expressions in data-access code examples
Closes gh-24398
2020-03-17 15:06:03 +01:00
Sam Brannen a8feb792da Fix broken Javadoc links 2020-03-16 16:30:27 +01:00
Sam Brannen e500456f1c Publish distribution zip files again
A change in `docs.gradle` in 5.2.4 resulted in distribution zip files
no longer being published to
https://repo.spring.io/release/org/springframework/spring/.

This commit fixes this by updating the `mavenContent` configuration as
suggested by @wilkinsona.

Closes gh-24605
2020-03-16 15:43:57 +01:00
Sam Brannen 35d0b3dba9 Fix Javadoc links accidentally broken in 7b6d83a106 2020-03-16 15:43:04 +01:00
Qimiao Chen 5f2e298c08 Extract isDebugEnabled() checks to local variables
Closes gh-24683
2020-03-16 15:25:05 +01:00
Qimiao Chen 193a76fe2a Avoid unnecessary sorting in AbstractHandlerMethodMapping
Closes gh-24704
2020-03-16 12:38:43 +01:00
Qimiao Chen 70581d1ea2 Improve javadoc in RollbackRuleAttribute regarding nested classes
Closes gh-24682

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-03-15 12:06:16 +01:00
Qimiao Chen d85a6c0bea Fix typos in MergedAnnotationsCollectionTests
Closes gh-24701
2020-03-15 11:48:29 +01:00
Stephane Nicoll 7411b2e025 Merge pull request #24697 from chenqimiao
* pr/24697:
  Fix typo in buildSrc/README.md

Closes gh-24697
2020-03-14 10:06:46 +01:00
陈其苗 fac1b94623 Fix typo in buildSrc/README.md
See gh-24697
2020-03-14 10:06:25 +01:00
Juergen Hoeller d91fc8c672 No log level check unless String concatenation is following 2020-03-14 00:01:13 +01:00
Juergen Hoeller 6599383dac Upgrade to RxJava 2.2.19, Undertow 2.0.30, HtmlUnit 2.38 2020-03-13 23:15:07 +01:00
Juergen Hoeller 33642345a4 Lazily check log level within validation conditions
See gh-24672
2020-03-13 23:14:38 +01:00
Arjen Poutsma 7c4f0318bb Improve efficiency of built RouterFunction
This commit changes the way RouterFunctions registered to the builder
are composed in both WebFlux.fn and WebMvc.fn.
Prior to this commit, all routes added to the build were composed with
`reduce`.
After this commit, all routes are stored in a special router function,
allowing for more efficient execution and smaller stack traces.

Closes gh-24652
2020-03-13 16:09:41 +01:00
Arjen Poutsma 54e2df2e0e Improve RouterFunction composition
This commit changes the way two RouterFunctions are composed in
WebFlux.fn. Prior to this commit, two were composed with
`switchIfEmpty()`, switching from the first to the second route if the
first did not provide an element.
After this commit, two router functions are compose using `concat`,
which results in a smaller stack trace.

See gh-24652
2020-03-13 16:09:41 +01:00
Rossen Stoyanchev f4ce22f6ba Merge branch '23828-sockjs' 2020-03-13 14:58:48 +00:00
Rossen Stoyanchev fa6ccc066d Do not raise exception for undelivered empty messages
Closes gh-23828
2020-03-13 14:58:31 +00:00
Rossen Stoyanchev 1a8caf9e2b Polishing and minor refactoring
See gh-23828
2020-03-13 14:58:31 +00:00
Rossen Stoyanchev 7b7dfcaaed Polishing contribution
See gh-24691
2020-03-13 14:58:01 +00:00
mdindoffer c11dd4a839 Do not mention credentials as enabled by default in CorsRegistry
Credentials are not enabled by default contrary to the javadocs. 
The credentials support must be enabled via #allowCredentials.

Closes gh-24691

Co-authored-by: Martin Dindoffer <martin.dindoffer@sigp.eu>
2020-03-13 15:21:53 +01:00
陈其苗 c5b8406def Add some test cases in StringUtilsTests 2020-03-13 12:35:04 +00:00
陈其苗 6013591fac Polish containsAny of CollectionUtils by reusing findFirstMatch 2020-03-13 12:32:43 +00:00
Qimiao Chen c8c1e61c0a Improve Javadoc in AutoProxyRegistrar
Closes gh-24688

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-03-13 10:01:58 +01:00
Qimiao Chen 201827cb0b Fix exception message in getMergedBeanDefinition
Closes gh-24686

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-03-13 09:47:57 +01:00
Rossen Stoyanchev a599859595 ServerCookie ignores empty domain with double quotes
Closes gh-24663
2020-03-12 12:21:19 +00:00
Rossen Stoyanchev 4aedf2ea13 MetadataEncoder expands vars correctly
Closes gh-24656
2020-03-12 11:35:08 +00:00
Arjen Poutsma 0dc1c7eb8b Add ServerRequest::checkNotModified
This commit adds the checkNotModified method to ServerRequest in both
WebFlux.fn and WebMvc.fn. Unlike other checkNotModified methods found
in the framework, this method does not return a boolean, but rather
a response wrapped in a Mono/Optional. If the resource has
not been changed, the not-modified response can be returned directly;
if the resource has changed, the user can create a corresponding
response using switchIfEmpty/orElse(Get).

Closes gh-24173
2020-03-11 16:45:00 +01:00
Juergen Hoeller 73e39726cd Upgrade to Kotlin 1.3.70
Includes latest dependency updates (Netty 4.1.47, Jetty 9.4.27, Jackson 2.10.3, Log4J 2.13.1, SnakeYAML 1.26, Vavr 0.10.2, Commons Pool 2.8, POI 4.1.2, OkHttp 3.14.7, Jetty Reactive HttpClient 1.1.2, JRuby 9.2.11, AssertJ 3.15)
2020-03-11 14:56:41 +01:00
Juergen Hoeller bcee6b9da4 Consistent assertions for supplier-based bean definition tests 2020-03-11 14:55:39 +01:00
Juergen Hoeller 7f26e8cfc6 Short-circuit interface visibility check in case of same ClassLoader
Closes gh-24664
2020-03-11 14:55:08 +01:00
Juergen Hoeller bee63e38c1 Create ScannedGenericBeanDefinitions for index-derived components as well
Closes gh-24638
2020-03-11 14:54:16 +01:00
Juergen Hoeller 193f419520 Deprecate PTM-based constructors in favor of generic TransactionManager
Closes gh-24612
2020-03-11 14:52:03 +01:00
Juergen Hoeller 6df80a8f70 Restore original JsonMappingException handling (assuming invalid input)
Closes gh-24610
Closes gh-24630
Closes gh-24646
2020-03-11 14:51:36 +01:00
Qimiao Chen 988aae4f2e Remove unnecessary variable declaration in ProxyCallbackFilter
Closes gh-24675
2020-03-11 13:51:13 +01:00
Arjen Poutsma 61569003b5 CORS support in HTTP header predicate
This commit introduces CORS support for the HeadersPredicate in
WebMvc.fn and WebFlux.fn.

Closes gh-24564
2020-03-10 17:22:26 +01:00
Сергей Цыпанов 1fd447f395 Reduce String garbage in CglibAopProxy.doValidateClass()
Closes gh-24672
2020-03-10 17:16:08 +01:00
Arjen Poutsma 3cbea86335 Deprecate MockServerRequest
Deprecate MockServerRequest in favor of ServerRequest::create
combined with a MockServerWebExchange.
2020-03-10 15:45:11 +01:00
Arjen Poutsma c03cdbac21 CORS support in HTTP method predicate
This commit introduces CORS support for the HttpMethodPredicate in
WebMvc.fn and WebFlux.fn.

Closes gh-24564
2020-03-10 15:45:11 +01:00
Arjen Poutsma fc12891006 Add ServerRequest::firstHeader
This commit introduces the method firstHeaderiin both WebMvc.fn and
WebFlux.fn, which return the first header value of a given header name,
if any.
2020-03-10 15:45:11 +01:00
Qimiao Chen b92515bdee Add logger.isInfoEnabled check before logger.info
Closes gh-24667
2020-03-10 14:41:20 +01:00
Sviatoslav Hryb 018ba92214 Fix formatting in AOP examples in documentation 2020-03-09 14:44:41 +00:00
Sviatoslav Hryb f5195887c9 Fix ampersands in AOP examples in documentation 2020-03-09 13:27:55 +00:00
Qimiao Chen 7ce22e2f3a Update IntroductionInfo example in reference manual
Closes gh-24650
2020-03-06 12:34:00 +01:00
Arjen Poutsma 2fb90cb16b Support for byte-range requests in WebMvc.fn
This commit introduces support for byte-range requests in Servlet
Functional endpoints.

Closes gh-24562
2020-03-05 15:32:31 +01:00
Rossen Stoyanchev c237338d8f Merge pull request #24632 from sada-sigsci/sse_content_type
Closes gh-24632
2020-03-04 19:28:05 +00:00
Rossen Stoyanchev 7e03728b2c Polishing contribution
See gh-24632
2020-03-04 19:27:37 +00:00
sada-sigsci cc1f57823b Remove charset from content-type in SseEmitter
See gh-24632
2020-03-04 19:27:37 +00:00
Rossen Stoyanchev b2fe494b9c Merge changes for ShallowEtagHeaderFilter
Closes gh-24635
2020-03-04 19:18:11 +00:00
Rossen Stoyanchev a98bf30ee6 ShallowEtagHeaderFilter checks for pre-existing eTag
The filter now checks for an explicitly set eTag and uses it instead of
generating one, and also suppresses caching.

Closes gh-24635
2020-03-04 19:17:56 +00:00
Rossen Stoyanchev c7e037da39 Remove unnecessary calls to disableContentCaching
These calls were added in error when trying to fix #22797 and #23775.
They are not needed in 304 scenarios. Those have no response content and
are skipped by ShallowETagHeaderFilter based on the status.

This leaves disableContentCaching invoked only in streaming scenarios,
which was the original intent and should be the only reason for that
method.

See gh-24635
2020-03-04 19:17:56 +00:00
Rossen Stoyanchev d3da7a50ec Polishing and minor refactoring
See gh-24635
2020-03-04 19:17:56 +00:00
Rossen Stoyanchev e7df445e37 Merge pull reqest #24617 from dreis2211/avoid-unnecessary-sorting
Closes gh-24617
2020-03-04 19:16:10 +00:00
Christoph Dreis 2093e35f27 Avoid unnecessary sorting 2020-03-04 19:10:14 +00:00
Rossen Stoyanchev 87230c4f1f Merge pull request #24589 from chenqimiao/fix404url-in-doc
Closes gh-24589
2020-03-03 15:40:32 +00:00
Rossen Stoyanchev e1b0296f9e Polishing contribution
See gh-24589
2020-03-03 15:38:47 +00:00
陈其苗 771fbde951 Fix URL to Spring Tool Suite
See gh-24589
2020-03-03 15:38:47 +00:00
Rossen Stoyanchev 2afae430eb Update list of support multipart media types
See gh-24582
2020-03-03 15:38:00 +00:00
Yoo In Keun e706fcba1f Fix typo in testing.adoc
Closes gh-24627
2020-03-02 16:25:28 +01:00
Johnny Lim 8285666ee8 Polish ReactorResourceFactory
Closes gh-24620
2020-03-02 13:48:19 +01:00
Sviatoslav Hryb 60fd95a354 Fix formatting for pointcut expression examples in documentation
Closes gh-24621
2020-03-02 13:42:09 +01:00
Adrian Cole 7f5395a216 Fix typos in AbstractClientHttpRequest
Closes gh-24623
2020-03-02 13:36:47 +01:00
陈其苗 8a7bb49436 Improve WebClient.Builder Javadoc 2020-02-28 17:07:58 +00:00
Rossen Stoyanchev 5f1e4ffc4f WebClient.Builder javadoc updates
Closes gh-24611
2020-02-28 15:55:53 +00:00
Brian Clozel 89560777e4 Upgrade Guava for API Diff plugin
Fixes gh-24606
2020-02-28 13:56:49 +01:00
Andreas Volkmann b30f9a1308 Fix typo in core-aop.adoc
Closes gh-24602
2020-02-26 18:33:25 +00:00
Florian Berger d4de3396f7 Fix typo about URI Encoding in docs
Closes gh-24603
2020-02-26 18:28:52 +00:00
wonwoo 5c2d65b8ef Fix typo in reference manual
Closes gh-24597
2020-02-26 14:34:25 +01:00
Sam Brannen 787b09b202 Relax GraalVM check in DefaultParameterNameDiscoverer
Prior to this commit, DefaultParameterNameDiscoverer did not register
any discovers when compiling or running as a GraalVM native image.

This commit relaxes the GraalVM check so that it is only applied to the
registration of KotlinReflectionParameterNameDiscoverer.

Consequently, StandardReflectionParameterNameDiscoverer and
LocalVariableTableParameterNameDiscoverer are once again always
registered by DefaultParameterNameDiscoverer.

Closes gh-24600
2020-02-26 14:18:56 +01:00
Sam Brannen c3bc28762e Delete unused import in ExpressionLanguageScenarioTests
See gh-24586
2020-02-26 14:09:01 +01:00
ZhangT c5fb7b9fb7 Simplify some redundant code
Closes gh-24586

Co-authored-by: Sam Brannen <sbrannen@pivotal.io>
2020-02-26 12:29:09 +01:00
Spring Buildmaster 0ad942f337 Next Development Version 2020-02-25 16:42:55 +00:00
1134 changed files with 23365 additions and 12881 deletions
@@ -0,0 +1,10 @@
name: "Validate Gradle Wrapper"
on: [push, pull_request]
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
+1 -1
View File
@@ -25,7 +25,7 @@ Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
#### Discuss
If you have a question, check Stack Overflow using
[this list of tags](https://spring.io/questions), organized by Spring project.
[this list of tags](https://stackoverflow.com/questions/tagged/spring+or+spring-mvc+or+spring-aop+or+spring-jdbc+or+spring-transactions+or+spring-annotations+or+spring-jms+or+spring-el+or+spring-test+or+spring+or+spring-remoting+or+spring-orm+or+spring-jmx+or+spring-cache+or+spring-webflux?tab=Newest).
Find an existing discussion, or start a new one if necessary.
If you believe there is an issue, search through
+1 -1
View File
@@ -1,4 +1,4 @@
# <img src="src/docs/asciidoc/images/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://build.spring.io/plugins/servlet/wittified/build-status/SPR-PUBM)](https://build.spring.io/browse/SPR)
# <img src="src/docs/asciidoc/images/spring-framework.png" width="80" height="80"> Spring Framework [![Build Status](https://ci.spring.io/api/v1/teams/spring-framework/pipelines/spring-framework-5.2.x/jobs/build/badge)](https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x?groups=Build")
This is the home of the Spring Framework: the foundation for all [Spring projects](https://spring.io/projects). Collectively the Spring Framework and the family of Spring projects are often referred to simply as "Spring".
+1 -1
View File
@@ -8,4 +8,4 @@ wiki page.
## Reporting a Vulnerability
Please see https://pivotal.io/security.
Please see https://spring.io/security-policy.
+58 -60
View File
@@ -1,15 +1,15 @@
plugins {
id 'io.spring.dependency-management' version '1.0.8.RELEASE' apply false
id 'org.jetbrains.kotlin.jvm' version '1.3.61' apply false
id 'org.jetbrains.dokka' version '0.9.18' apply false
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
id 'io.spring.ge.conventions' version '0.0.7'
id 'io.spring.nohttp' version '0.0.5.RELEASE'
id "io.freefair.aspectj" version '4.1.6' apply false
id 'org.jetbrains.dokka' version '0.10.1' apply false
id 'org.jetbrains.kotlin.jvm' version '1.3.72' apply false
id 'org.asciidoctor.jvm.convert' version '2.4.0'
id 'io.spring.gradle-enterprise-conventions' version '0.0.2'
id 'io.spring.nohttp' version '0.0.4.RELEASE'
id 'de.undercouch.download' version '4.0.0'
id 'com.gradle.build-scan' version '3.1.1'
id "com.jfrog.artifactory" version '4.12.0' apply false
id "io.freefair.aspectj" version "4.1.1" apply false
id "com.github.ben-manes.versions" version "0.24.0"
id 'org.asciidoctor.jvm.pdf' version '2.4.0'
id "com.github.ben-manes.versions" version '0.28.0'
id 'com.gradle.build-scan' version '3.2'
id 'de.undercouch.download' version '4.1.1'
}
apply from: "$rootDir/gradle/build-scan-user-data.gradle"
@@ -26,33 +26,31 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.10.2"
mavenBom "io.netty:netty-bom:4.1.45.Final"
mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR5"
mavenBom "io.rsocket:rsocket-bom:1.0.0-RC6"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.26.v20200117"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.61"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.2"
mavenBom "org.junit:junit-bom:5.6.0"
mavenBom "com.fasterxml.jackson:jackson-bom:2.10.5"
mavenBom "io.netty:netty-bom:4.1.51.Final"
mavenBom "io.projectreactor:reactor-bom:Dysprosium-SR25"
mavenBom "io.rsocket:rsocket-bom:1.0.4"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.31.v20200723"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.3.72"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.5"
mavenBom "org.junit:junit-bom:5.6.3"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.13.0') {
dependencySet(group: 'org.apache.logging.log4j', version: '2.17.2') {
entry 'log4j-api'
entry 'log4j-core'
entry 'log4j-slf4j-impl'
entry 'log4j-jul'
entry 'log4j-slf4j-impl'
}
dependency "org.slf4j:slf4j-api:1.7.30"
dependency "org.slf4j:slf4j-api:1.7.32"
dependency "com.google.code.findbugs:jsr305:3.0.2"
dependencySet(group: 'org.aspectj', version: '1.9.5') {
dependencySet(group: 'org.aspectj', version: '1.9.7') {
entry 'aspectjrt'
entry 'aspectjtools'
entry 'aspectjweaver'
}
// If customJavaHome has been set, we assume we need Groovy 3.0 for testing purposes.
dependencySet(group: 'org.codehaus.groovy', version: System.getProperty("customJavaHome") ? '3.0.1' : '2.5.9') {
dependencySet(group: 'org.codehaus.groovy', version: '2.5.15') {
entry 'groovy'
entry 'groovy-jsr223'
entry 'groovy-templates'
@@ -62,12 +60,12 @@ configure(allprojects) { project ->
dependency "io.reactivex:rxjava:1.3.8"
dependency "io.reactivex:rxjava-reactive-streams:1.2.1"
dependency "io.reactivex.rxjava2:rxjava:2.2.18"
dependency "io.projectreactor.tools:blockhound:1.0.2.RELEASE"
dependency "io.reactivex.rxjava2:rxjava:2.2.21"
dependency "io.projectreactor.tools:blockhound:1.0.6.RELEASE"
dependency "com.caucho:hessian:4.0.62"
dependency "com.caucho:hessian:4.0.63"
dependency "com.fasterxml:aalto-xml:1.2.2"
dependency("com.fasterxml.woodstox:woodstox-core:6.0.3") {
dependency("com.fasterxml.woodstox:woodstox-core:6.2.3") {
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.6"
@@ -77,7 +75,7 @@ configure(allprojects) { project ->
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
dependency "org.apache.johnzon:johnzon-jsonb:1.2.3"
dependency "org.apache.johnzon:johnzon-jsonb:1.2.10"
dependency("org.codehaus.jettison:jettison:1.3.8") {
exclude group: "stax", name: "stax-api"
}
@@ -86,14 +84,14 @@ configure(allprojects) { project ->
entry 'jibx-run'
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.25"
dependency "org.yaml:snakeyaml:1.27"
dependency "com.h2database:h2:1.4.200"
dependency "com.github.ben-manes.caffeine:caffeine:2.8.1"
dependency "com.github.librepdf:openpdf:1.3.13"
dependency "com.github.ben-manes.caffeine:caffeine:2.8.8"
dependency "com.github.librepdf:openpdf:1.3.25"
dependency "com.rometools:rome:1.12.2"
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.0"
dependency "io.vavr:vavr:0.10.3"
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
dependencySet(group: 'org.apache.activemq', version: '5.8.0') {
entry 'activemq-broker'
@@ -103,37 +101,37 @@ configure(allprojects) { project ->
entry 'activemq-stomp'
}
dependency "org.apache.bcel:bcel:6.0"
dependency "org.apache.commons:commons-pool2:2.7.0"
dependency "org.apache.commons:commons-pool2:2.8.1"
dependencySet(group: 'org.apache.derby', version: '10.14.2.0') {
entry 'derby'
entry 'derbyclient'
}
dependency "org.apache.poi:poi-ooxml:4.1.1"
dependency "org.beanshell:bsh:2.0b5"
dependency "org.freemarker:freemarker:2.3.29"
dependency "org.hsqldb:hsqldb:2.5.0"
dependency "org.apache.poi:poi-ooxml:4.1.2"
dependency "org.apache-extras.beanshell:bsh:2.0b6"
dependency "org.freemarker:freemarker:2.3.30"
dependency "org.hsqldb:hsqldb:2.5.1"
dependency "org.quartz-scheduler:quartz:2.3.2"
dependency "org.codehaus.fabric3.api:commonj:1.1.0"
dependency "net.sf.ehcache:ehcache:2.10.6"
dependency "org.ehcache:jcache:1.0.1"
dependency "org.ehcache:ehcache:3.4.0"
dependency "org.hibernate:hibernate-core:5.4.12.Final"
dependency "org.hibernate:hibernate-validator:6.1.2.Final"
dependency "org.webjars:webjars-locator-core:0.43"
dependency "org.hibernate:hibernate-core:5.4.28.Final"
dependency "org.hibernate:hibernate-validator:6.1.7.Final"
dependency "org.webjars:webjars-locator-core:0.46"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.31') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.37') {
entry 'tomcat-util'
entry('tomcat-websocket') {
exclude group: "org.apache.tomcat", name: "tomcat-websocket-api"
exclude group: "org.apache.tomcat", name: "tomcat-servlet-api"
}
}
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.31') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.37') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.0.29.Final') {
dependencySet(group: 'io.undertow', version: '2.0.32.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
@@ -144,19 +142,19 @@ configure(allprojects) { project ->
}
}
dependencySet(group: 'com.squareup.okhttp3', version: '3.14.6') {
dependencySet(group: 'com.squareup.okhttp3', version: '3.14.9') {
entry 'okhttp'
entry 'mockwebserver'
}
dependency("org.apache.httpcomponents:httpclient:4.5.11") {
dependency("org.apache.httpcomponents:httpclient:4.5.13") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.1"
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.4"
dependency "org.jruby:jruby:9.2.9.0"
dependency "org.jruby:jruby:9.2.11.1"
dependency "org.python:jython-standalone:2.7.1"
dependency "org.mozilla:rhino:1.7.11"
@@ -181,25 +179,25 @@ configure(allprojects) { project ->
dependency "org.testng:testng:6.14.3"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.14.0"
dependency "org.assertj:assertj-core:3.18.1"
dependencySet(group: 'org.xmlunit', version: '2.6.2') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.2.4') {
dependencySet(group: 'org.mockito', version: '3.3.3') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
entry 'mockito-junit-jupiter'
}
dependency "io.mockk:mockk:1.9.3"
dependency "io.mockk:mockk:1.10.2"
dependency("net.sourceforge.htmlunit:htmlunit:2.37.0") {
dependency("net.sourceforge.htmlunit:htmlunit:2.43.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.37.0") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.43.1") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -225,9 +223,9 @@ configure(allprojects) { project ->
}
dependency "com.ibm.websphere:uow:6.0.2.17"
dependency "com.jamonapi:jamon:2.81"
dependency "joda-time:joda-time:2.10.5"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.6"
dependency "com.jamonapi:jamon:2.82"
dependency "joda-time:joda-time:2.10.10"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.7"
dependency "org.javamoney:moneta:1.3"
dependency "com.sun.activation:javax.activation:1.2.0"
@@ -327,7 +325,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "8.29"
toolVersion = "8.38"
configDir = rootProject.file("src/checkstyle")
}
@@ -368,7 +366,7 @@ configure([rootProject] + javaProjects) { project ->
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
"https://junit.org/junit4/javadoc/4.12/",
"https://junit.org/junit5/docs/5.6.0/api/"
"https://junit.org/junit5/docs/5.6.3/api/"
] as String[]
}
@@ -388,7 +386,7 @@ configure(rootProject) {
nohttp {
source.exclude "**/test-output/**"
whitelistFile = project.file("src/nohttp/whitelist.lines")
allowlistFile = project.file("src/nohttp/allowlist.lines")
def rootPath = file(rootDir).toPath()
def projectDirs = allprojects.collect { it.projectDir } + "${rootDir}/buildSrc"
projectDirs.forEach { dir ->
+1 -1
View File
@@ -7,7 +7,7 @@ They are declared in the `build.gradle` file in this folder.
### Compiler conventions
The `org.springframework.build.compile` plubin applies the Java compiler conventions to the build.
The `org.springframework.build.compile` plugin applies the Java compiler conventions to the build.
By default, the build compiles sources with Java `1.8` source and target compatibility.
You can test a different source compatibility version on the CLI with a project property like:
+1 -1
View File
@@ -9,7 +9,7 @@ repositories {
dependencies {
implementation "me.champeau.gradle:japicmp-gradle-plugin:0.2.8"
implementation "com.google.guava:guava:18.0" // required by japicmp-gradle-plugin
implementation "com.google.guava:guava:28.2-jre" // required by japicmp-gradle-plugin
}
gradlePlugin {
+57
View File
@@ -0,0 +1,57 @@
== Spring Framework Concourse pipeline
The Spring Framework uses https://concourse-ci.org/[Concourse] for its CI build and other automated tasks.
The Spring team has a dedicated Concourse instance available at https://ci.spring.io with a build pipeline
for https://ci.spring.io/teams/spring-framework/pipelines/spring-framework-5.2.x[Spring Framework 5.2.x].
=== Setting up your development environment
If you're part of the Spring Framework project on GitHub, you can get access to CI management features.
First, you need to go to https://ci.spring.io and install the client CLI for your platform (see bottom right of the screen).
You can then login with the instance using:
[source]
----
$ fly -t spring login -n spring-framework -c https://ci.spring.io
----
Once logged in, you should get something like:
[source]
----
$ fly ts
name url team expiry
spring https://ci.spring.io spring-framework Wed, 25 Mar 2020 17:45:26 UTC
----
=== Pipeline configuration and structure
The build pipelines are described in `pipeline.yml` file.
This file is listing Concourse resources, i.e. build inputs and outputs such as container images, artifact repositories, source repositories, notification services, etc.
It also describes jobs (a job is a sequence of inputs, tasks and outputs); jobs are organized by groups.
The `pipeline.yml` definition contains `((parameters))` which are loaded from the `parameters.yml` file or from our https://docs.cloudfoundry.org/credhub/[credhub instance].
You'll find in this folder the following resources:
* `pipeline.yml` the build pipeline
* `parameters.yml` the build parameters used for the pipeline
* `images/` holds the container images definitions used in this pipeline
* `scripts/` holds the build scripts that ship within the CI container images
* `tasks` contains the task definitions used in the main `pipeline.yml`
=== Updating the build pipeline
Updating files on the repository is not enough to update the build pipeline, as changes need to be applied.
The pipeline can be deployed using the following command:
[source]
----
$ fly -t spring set-pipeline -p spring-framework-5.2.x -c ci/pipeline.yml -l ci/parameters.yml
----
NOTE: This assumes that you have credhub integration configured with the appropriate secrets.
+17
View File
@@ -0,0 +1,17 @@
changelog:
repository: spring-projects/spring-framework
sections:
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
+10
View File
@@ -0,0 +1,10 @@
logging:
level:
io.spring.concourse: DEBUG
spring:
main:
banner-mode: off
sonatype:
exclude:
- 'build-info\.json'
- '.*\.zip'
+21
View File
@@ -0,0 +1,21 @@
== CI Images
These images are used by CI to run the actual builds.
To build the image locally run the following from this directory:
----
$ docker build --no-cache -f <image-folder>/Dockerfile .
----
For example
----
$ docker build --no-cache -f spring-framework-ci-image/Dockerfile .
----
To test run:
----
$ docker run -it --entrypoint /bin/bash <SHA>
----
+8
View File
@@ -0,0 +1,8 @@
FROM ubuntu:focal-20220302
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java11
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
+8
View File
@@ -0,0 +1,8 @@
FROM ubuntu:focal-20220302
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
RUN ./setup.sh java8
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
set -e
case "$1" in
java8)
echo "https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u322-b06/OpenJDK8U-jdk_x64_linux_hotspot_8u322b06.tar.gz"
;;
java11)
echo "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.14.1%2B1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.14.1_1.tar.gz"
;;
*)
echo $"Unknown java version"
exit 1
esac
+35
View File
@@ -0,0 +1,35 @@
#!/bin/bash
set -ex
###########################################################
# UTILS
###########################################################
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq fontconfig
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
dpkg-reconfigure --frontend noninteractive tzdata
rm -rf /var/lib/apt/lists/*
curl https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh > /opt/concourse-java.sh
curl --output /opt/concourse-release-scripts.jar https://repo.spring.io/release/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.2/concourse-release-scripts-0.3.2.jar
###########################################################
# JAVA
###########################################################
JDK_URL=$( ./get-jdk-url.sh $1 )
mkdir -p /opt/openjdk
cd /opt/openjdk
curl -L ${JDK_URL} | tar zx --strip-components=1
test -f /opt/openjdk/bin/java
test -f /opt/openjdk/bin/javac
###########################################################
# GRADLE ENTERPRISE
###########################################################
cd /
mkdir ~/.gradle
echo 'systemProp.user.name=concourse' > ~/.gradle/gradle.properties
+13
View File
@@ -0,0 +1,13 @@
email-server: "smtp.svc.pivotal.io"
email-from: "ci@spring.io"
email-to: ["spring-framework-dev@pivotal.io"]
github-repo: "https://github.com/spring-projects/spring-framework.git"
github-repo-name: "spring-projects/spring-framework"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "5.2.x"
milestone: "5.2.x"
build-name: "spring-framework"
pipeline-name: "spring-framework"
concourse-url: "https://ci.spring.io"
task-timeout: 1h00m
+391
View File
@@ -0,0 +1,391 @@
anchors:
git-repo-resource-source: &git-repo-resource-source
uri: ((github-repo))
username: ((github-username))
password: ((github-ci-release-token))
branch: ((branch))
gradle-enterprise-task-params: &gradle-enterprise-task-params
GRADLE_ENTERPRISE_ACCESS_KEY: ((gradle_enterprise_secret_access_key))
GRADLE_ENTERPRISE_CACHE_USERNAME: ((gradle_enterprise_cache_user.username))
GRADLE_ENTERPRISE_CACHE_PASSWORD: ((gradle_enterprise_cache_user.password))
sonatype-task-params: &sonatype-task-params
SONATYPE_USERNAME: ((sonatype-username))
SONATYPE_PASSWORD: ((sonatype-password))
SONATYPE_URL: ((sonatype-url))
SONATYPE_STAGING_PROFILE_ID: ((sonatype-staging-profile-id))
artifactory-task-params: &artifactory-task-params
ARTIFACTORY_SERVER: ((artifactory-server))
ARTIFACTORY_USERNAME: ((artifactory-username))
ARTIFACTORY_PASSWORD: ((artifactory-password))
build-project-task-params: &build-project-task-params
privileged: true
timeout: ((task-timeout))
params:
BRANCH: ((branch))
<<: *gradle-enterprise-task-params
docker-resource-source: &docker-resource-source
username: ((docker-hub-username))
password: ((docker-hub-password))
tag: ((milestone))
slack-fail-params: &slack-fail-params
text: >
:concourse-failed: <https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}|${BUILD_PIPELINE_NAME} ${BUILD_JOB_NAME} failed!>
[$TEXT_FILE_CONTENT]
text_file: git-repo/build/build-scan-uri.txt
silent: true
icon_emoji: ":concourse:"
username: concourse-ci
changelog-task-params: &changelog-task-params
name: generated-changelog/tag
tag: generated-changelog/tag
body: generated-changelog/changelog.md
github-task-params: &github-task-params
GITHUB_USERNAME: ((github-username))
GITHUB_TOKEN: ((github-ci-release-token))
resource_types:
- name: artifactory-resource
type: registry-image
source:
repository: springio/artifactory-resource
tag: 0.0.17
- name: github-release
type: registry-image
source:
repository: concourse/github-release-resource
tag: 1.5.5
- name: github-status-resource
type: registry-image
source:
repository: dpb587/github-status-resource
tag: master
- name: slack-notification
type: registry-image
source:
repository: cfcommunity/slack-notification-resource
tag: latest
resources:
- name: git-repo
type: git
icon: github
source:
<<: *git-repo-resource-source
- name: every-morning
type: time
icon: alarm
source:
start: 8:00 AM
stop: 9:00 AM
location: Europe/Vienna
- name: ci-images-git-repo
type: git
icon: github
source:
uri: ((github-repo))
branch: ((branch))
paths: ["ci/images/*"]
- name: ci-image
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci
- name: ci-image-jdk11
type: docker-image
icon: docker
source:
<<: *docker-resource-source
repository: ((docker-hub-organization))/spring-framework-ci-jdk11
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
source:
uri: ((artifactory-server))
username: ((artifactory-username))
password: ((artifactory-password))
build_name: ((build-name))
- name: repo-status-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: build
- name: repo-status-jdk11-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk11-build
- name: slack-alert
type: slack-notification
icon: slack
source:
url: ((slack-webhook-url))
- name: github-pre-release
type: github-release
icon: briefcase-download-outline
source:
owner: spring-projects
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: true
release: false
- name: github-release
type: github-release
icon: briefcase-download
source:
owner: spring-projects
repository: spring-framework
access_token: ((github-ci-release-token))
pre_release: false
jobs:
- name: build-ci-images
plan:
- get: ci-images-git-repo
trigger: true
- in_parallel:
- put: ci-image
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/ci-image/Dockerfile
- put: ci-image-jdk11
params:
build: ci-images-git-repo/ci/images
dockerfile: ci-images-git-repo/ci/images/ci-image-jdk11/Dockerfile
- name: build
serial: true
public: true
plan:
- get: ci-image
- get: git-repo
trigger: true
- put: repo-status-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: build-project
image: ci-image
file: git-repo/ci/tasks/build-project.yml
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-build
params: { state: "success", commit: "git-repo" }
- put: artifactory-repo
params: &artifactory-params
signing_key: ((signing-key))
signing_passphrase: ((signing-passphrase))
repo: libs-snapshot-local
folder: distribution-repository
build_uri: "https://ci.spring.io/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}"
build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}"
disable_checksum_uploads: true
threads: 8
artifact_set:
- include:
- "/**/spring-*.zip"
properties:
"zip.name": "spring-framework"
"zip.displayname": "Spring Framework"
"zip.deployed": "false"
- include:
- "/**/spring-*-docs.zip"
properties:
"zip.type": "docs"
- include:
- "/**/spring-*-dist.zip"
properties:
"zip.type": "dist"
- include:
- "/**/spring-*-schema.zip"
properties:
"zip.type": "schema"
get_params:
threads: 8
- name: jdk11-build
serial: true
public: true
plan:
- get: ci-image-jdk11
- get: git-repo
- get: every-morning
trigger: true
- put: repo-status-jdk11-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: check-project
image: ci-image-jdk11
file: git-repo/ci/tasks/check-project.yml
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk11-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk11-build
params: { state: "success", commit: "git-repo" }
- name: stage-milestone
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: M
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-milestone
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-milestone]
params:
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: M
<<: *artifactory-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: M
<<: *github-task-params
- put: github-pre-release
params:
<<: *changelog-task-params
- name: stage-rc
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RC
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-rc
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-rc]
params:
download_artifacts: false
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RC
<<: *artifactory-task-params
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: RC
<<: *github-task-params
- put: github-pre-release
params:
<<: *changelog-task-params
- name: stage-release
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- task: stage
image: ci-image
file: git-repo/ci/tasks/stage-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *gradle-enterprise-task-params
- put: artifactory-repo
params:
<<: *artifactory-params
repo: libs-staging-local
- put: git-repo
params:
repository: stage-git-repo
- name: promote-release
serial: true
plan:
- get: ci-image
- get: git-repo
trigger: false
- get: artifactory-repo
trigger: false
passed: [stage-release]
params:
download_artifacts: true
save_build_info: true
- task: promote
image: ci-image
file: git-repo/ci/tasks/promote-version.yml
params:
RELEASE_TYPE: RELEASE
<<: *artifactory-task-params
<<: *sonatype-task-params
- name: create-github-release
serial: true
plan:
- get: ci-image
- get: git-repo
- get: artifactory-repo
trigger: true
passed: [promote-release]
params:
download_artifacts: false
save_build_info: true
- task: generate-changelog
file: git-repo/ci/tasks/generate-changelog.yml
params:
RELEASE_TYPE: RELEASE
<<: *github-task-params
- put: github-release
params:
<<: *changelog-task-params
groups:
- name: "builds"
jobs: ["build", "jdk11-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release"]
- name: "ci-images"
jobs: ["build-ci-images"]
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
repository=$(pwd)/distribution-repository
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
popd > /dev/null
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
pushd git-repo > /dev/null
./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 check
popd > /dev/null
+2
View File
@@ -0,0 +1,2 @@
source /opt/concourse-java.sh
setup_symlinks
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
set -e
CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
milestone=${version}
if [[ $RELEASE_TYPE = "RELEASE" ]]; then
milestone=${version%.RELEASE}
fi
java -jar /github-changelog-generator.jar \
--spring.config.location=${CONFIG_DIR}/changelog-generator.yml \
${milestone} generated-changelog/changelog.md
echo ${version} > generated-changelog/version
echo v${version} > generated-changelog/tag
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
source $(dirname $0)/common.sh
CONFIG_DIR=git-repo/ci/config
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
publishToCentral $RELEASE_TYPE $BUILD_INFO_LOCATION artifactory-repo || { exit 1; }
java -jar /opt/concourse-release-scripts.jar \
--spring.config.location=${CONFIG_DIR}/release-scripts.yml \
promote $RELEASE_TYPE $BUILD_INFO_LOCATION || { exit 1; }
echo "Promotion complete"
echo $version > version/version
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
set -e
source $(dirname $0)/common.sh
repository=$(pwd)/distribution-repository
pushd git-repo > /dev/null
git fetch --tags --all > /dev/null
popd > /dev/null
git clone git-repo stage-git-repo > /dev/null
pushd stage-git-repo > /dev/null
snapshotVersion=$( awk -F '=' '$1 == "version" { print $2 }' gradle.properties )
if [[ $RELEASE_TYPE = "M" ]]; then
stageVersion=$( get_next_milestone_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RC" ]]; then
stageVersion=$( get_next_rc_release $snapshotVersion)
nextVersion=$snapshotVersion
elif [[ $RELEASE_TYPE = "RELEASE" ]]; then
stageVersion=$( get_next_release $snapshotVersion "RELEASE")
nextVersion=$( bump_version_number $snapshotVersion)
else
echo "Unknown release type $RELEASE_TYPE" >&2; exit 1;
fi
echo "Staging $stageVersion (next version will be $nextVersion)"
sed -i "s/version=$snapshotVersion/version=$stageVersion/" gradle.properties
git config user.name "Spring Builds" > /dev/null
git config user.email "spring-builds@users.noreply.github.com" > /dev/null
git add gradle.properties > /dev/null
git commit -m"Release v$stageVersion" > /dev/null
git tag -a "v$stageVersion" -m"Release v$stageVersion" > /dev/null
./gradlew --no-daemon --max-workers=4 -PdeploymentRepository=${repository} build publishAllPublicationsToDeploymentRepository
git reset --hard HEAD^ > /dev/null
if [[ $nextVersion != $snapshotVersion ]]; then
echo "Setting next development version (v$nextVersion)"
sed -i "s/version=$snapshotVersion/version=$nextVersion/" gradle.properties
git add gradle.properties > /dev/null
git commit -m"Next development version (v$nextVersion)" > /dev/null
fi;
echo "Staging Complete"
popd > /dev/null
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json
version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' )
java -jar /opt/concourse-release-scripts.jar syncToCentral "RELEASE" $BUILD_INFO_LOCATION || { exit 1; }
echo "Sync complete"
echo $version > version/version
+22
View File
@@ -0,0 +1,22 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: distribution-repository
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/build-project.sh
+22
View File
@@ -0,0 +1,22 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: distribution-repository
- name: git-repo
caches:
- path: gradle
params:
BRANCH:
CI: true
GRADLE_ENTERPRISE_ACCESS_KEY:
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
run:
path: bash
args:
- -ec
- |
${PWD}/git-repo/ci/scripts/check-project.sh
+20
View File
@@ -0,0 +1,20 @@
---
platform: linux
image_resource:
type: registry-image
source:
repository: springio/github-changelog-generator
tag: '0.0.7'
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: generated-changelog
params:
GITHUB_ORGANIZATION:
GITHUB_REPO:
GITHUB_USERNAME:
GITHUB_TOKEN:
RELEASE_TYPE:
run:
path: git-repo/ci/scripts/generate-changelog.sh
+18
View File
@@ -0,0 +1,18 @@
---
platform: linux
inputs:
- name: git-repo
- name: artifactory-repo
outputs:
- name: version
params:
RELEASE_TYPE:
ARTIFACTORY_SERVER:
ARTIFACTORY_USERNAME:
ARTIFACTORY_PASSWORD:
SONATYPE_USER:
SONATYPE_PASSWORD:
SONATYPE_URL:
SONATYPE_STAGING_PROFILE_ID:
run:
path: git-repo/ci/scripts/promote-version.sh
+17
View File
@@ -0,0 +1,17 @@
---
platform: linux
inputs:
- name: git-repo
outputs:
- name: stage-git-repo
- name: distribution-repository
params:
RELEASE_TYPE:
CI: true
GRADLE_ENTERPRISE_CACHE_USERNAME:
GRADLE_ENTERPRISE_CACHE_PASSWORD:
GRADLE_ENTERPRISE_URL: https://ge.spring.io
caches:
- path: gradle
run:
path: git-repo/ci/scripts/stage-version.sh
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.2.4.BUILD-SNAPSHOT
version=5.2.22.RELEASE
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.parallel=true
+3 -4
View File
@@ -5,10 +5,9 @@
// the one used to launch the Gradle process).
//
// - customJavaHome: absolute path to the alternate JDK installation to
// use to compile Java code and execute tests. Setting this system
// property causes Groovy 3.0 RC3 to be used instead of 2.5.x. This
// system property is also used in spring-oxm.gradle to determine
// whether JiBX is supported.
// use to compile Java code and execute tests. This system property
// is also used in spring-oxm.gradle to determine whether JiBX is
// supported.
//
// - customJavaSourceVersion: Java version supplied to the `--release`
// command line flag to control the Java source and target
+72 -51
View File
@@ -10,7 +10,7 @@ repositories {
maven {
url "https://repo.spring.io/release"
mavenContent {
group "io.spring.asciidoctor"
includeGroup "io.spring.asciidoctor"
}
}
}
@@ -65,39 +65,49 @@ dokka {
dependsOn {
tasks.getByName("api")
}
doFirst {
classpath = moduleProjects.collect { project -> project.jar.outputs.files.getFiles() }.flatten()
classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath })
sourceDirs = files(moduleProjects
.findAll {
it.pluginManager.hasPlugin("kotlin")
configuration {
classpath = moduleProjects.collect { project -> project.jar.outputs.files.getFiles() }.flatten()
classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath })
moduleProjects.findAll {
it.pluginManager.hasPlugin("kotlin")
}.each { project ->
def kotlinDirs = project.sourceSets.main.kotlin.srcDirs.collect()
kotlinDirs -= project.sourceSets.main.java.srcDirs
kotlinDirs.each { dir ->
if (dir.exists()) {
sourceRoot {
path = dir.path
}
}
}
.collect { project ->
def kotlinDirs = project.sourceSets.main.kotlin.srcDirs.collect()
kotlinDirs -= project.sourceSets.main.java.srcDirs
})
}
}
}
moduleName = "spring-framework"
outputFormat = "html"
outputDirectory = "$buildDir/docs/kdoc"
externalDocumentationLink {
url = new URL("https://docs.spring.io/spring-framework/docs/$version/javadoc-api/")
packageListUrl = new File(buildDir, "docs/javadoc/package-list").toURI().toURL()
}
externalDocumentationLink {
url = new URL("https://projectreactor.io/docs/core/release/api/")
}
externalDocumentationLink {
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
}
externalDocumentationLink {
url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
configuration {
moduleName = "spring-framework"
externalDocumentationLink {
url = new URL("https://docs.spring.io/spring-framework/docs/$version/javadoc-api/")
packageListUrl = new File(buildDir, "docs/javadoc/package-list").toURI().toURL()
}
externalDocumentationLink {
url = new URL("https://projectreactor.io/docs/core/release/api/")
}
externalDocumentationLink {
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
}
}
}
task downloadResources(type: Download) {
def version = "0.1.3.RELEASE"
def version = "0.2.1.RELEASE"
src "https://repo.spring.io/release/io/spring/docresources/" +
"spring-doc-resources/$version/spring-doc-resources-${version}.zip"
dest project.file("$buildDir/docs/spring-doc-resources.zip")
@@ -117,29 +127,6 @@ asciidoctorj {
}
}
fatalWarnings ".*"
}
/**
* Produce the Spring Framework Reference documentation
* from "src/docs/asciidoc" into "build/asciidoc/html5"
*/
asciidoctor {
baseDirFollowsSourceDir()
configurations 'asciidoctorExt'
sources {
include '*.adoc'
}
outputDir "$buildDir/docs/ref-docs/"
resources {
from(sourceDir) {
include 'images/*', 'css/**', 'js/**'
}
from extractDocResources
}
logDocuments = true
outputOptions {
backends = ["html5", "pdf"]
}
options doctype: 'book', eruby: 'erubis'
attributes([
icons: 'font',
@@ -151,17 +138,51 @@ asciidoctor {
sectnums: '',
'source-highlighter': 'highlight.js',
highlightjsdir: 'js/highlight',
'highlightjs-theme': 'github',
'highlightjs-theme': 'github', // 'googlecode',
stylesdir: 'css/',
stylesheet: 'stylesheet.css',
'spring-version': project.version
])
}
/**
* Generate the Spring Framework Reference documentation from "src/docs/asciidoc"
* in "build/docs/ref-docs/html5".
*/
asciidoctor {
baseDirFollowsSourceDir()
configurations 'asciidoctorExt'
sources {
include '*.adoc'
}
outputDir "$buildDir/docs/ref-docs/html5"
logDocuments = true
resources {
from(sourceDir) {
include 'images/*', 'css/**', 'js/**'
}
from extractDocResources
}
}
/**
* Generate the Spring Framework Reference documentation from "src/docs/asciidoc"
* in "build/docs/ref-docs/pdf".
*/
asciidoctorPdf {
baseDirFollowsSourceDir()
configurations 'asciidoctorExt'
sources {
include '*.adoc'
}
outputDir "$buildDir/docs/ref-docs/pdf"
logDocuments = true
}
/**
* Zip all docs (API and reference) into a single archive
*/
task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) {
task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'asciidoctorPdf', 'dokka']) {
group = "Distribution"
description = "Builds -${archiveClassifier} archive containing api and reference " +
"for deployment at https://docs.spring.io/spring-framework/docs."
@@ -174,10 +195,10 @@ task docsZip(type: Zip, dependsOn: ['api', 'asciidoctor', 'dokka']) {
from (api) {
into "javadoc-api"
}
from ("$asciidoctor.outputDir/html5") {
from ("$asciidoctor.outputDir") {
into "spring-framework-reference"
}
from ("$asciidoctor.outputDir/pdf") {
from ("$asciidoctorPdf.outputDir") {
into "spring-framework-reference/pdf"
}
from (dokka) {
+1 -2
View File
@@ -29,12 +29,11 @@ eclipse.classpath.file.whenMerged { classpath ->
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
}
// Use separate main/test outputs (prevents WTP from packaging test classes)
eclipse.classpath.defaultOutputDir = file(project.name+"/bin/eclipse")
eclipse.classpath.file.beforeMerged { classpath ->
classpath.entries.findAll{ it instanceof SourceFolder }.each {
if(it.output.startsWith("bin/")) {
if (it.output.startsWith("bin/")) {
it.output = null
}
}
+12 -3
View File
@@ -1,5 +1,4 @@
apply plugin: "maven-publish"
apply plugin: 'com.jfrog.artifactory'
publishing {
publications {
@@ -50,6 +49,16 @@ publishing {
}
}
artifactoryPublish {
publications(publishing.publications.mavenJava)
configureDeploymentRepository(project)
void configureDeploymentRepository(Project project) {
project.plugins.withType(MavenPublishPlugin.class).all {
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
if (project.hasProperty("deploymentRepository")) {
publishing.repositories.maven {
it.url = project.property("deploymentRepository")
it.name = "deployment"
}
}
}
}
@@ -0,0 +1,119 @@
/*
* Copyright 2002-2020 the original author 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
*
* https://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.config;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Integration tests for advice invocation order for advice configured via the
* AOP namespace.
*
* @author Sam Brannen
* @since 5.2.7
* @see org.springframework.aop.framework.autoproxy.AspectJAutoProxyAdviceOrderIntegrationTests
*/
class AopNamespaceHandlerAdviceOrderIntegrationTests {
@Nested
@SpringJUnitConfig(locations = "AopNamespaceHandlerAdviceOrderIntegrationTests-afterFirst.xml")
@DirtiesContext
class AfterAdviceFirstTests {
@Test
void afterAdviceIsInvokedFirst(@Autowired Echo echo, @Autowired InvocationTrackingAspect aspect) throws Exception {
assertThat(aspect.invocations).isEmpty();
assertThat(echo.echo(42)).isEqualTo(42);
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after returning");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after", "after throwing");
}
}
@Nested
@SpringJUnitConfig(locations = "AopNamespaceHandlerAdviceOrderIntegrationTests-afterLast.xml")
@DirtiesContext
class AfterAdviceLastTests {
@Test
void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired InvocationTrackingAspect aspect) throws Exception {
assertThat(aspect.invocations).isEmpty();
assertThat(echo.echo(42)).isEqualTo(42);
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after returning", "after");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "around - end", "after throwing", "after");
}
}
static class Echo {
Object echo(Object obj) throws Exception {
if (obj instanceof Exception) {
throw (Exception) obj;
}
return obj;
}
}
static class InvocationTrackingAspect {
List<String> invocations = new ArrayList<>();
Object around(ProceedingJoinPoint joinPoint) throws Throwable {
invocations.add("around - start");
try {
return joinPoint.proceed();
}
finally {
invocations.add("around - end");
}
}
void before() {
invocations.add("before");
}
void afterReturning() {
invocations.add("after returning");
}
void afterThrowing() {
invocations.add("after throwing");
}
void after() {
invocations.add("after");
}
}
}
@@ -0,0 +1,233 @@
/*
* Copyright 2002-2020 the original author 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
*
* https://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.autoproxy;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Integration tests for advice invocation order for advice configured via
* AspectJ auto-proxy support.
*
* @author Sam Brannen
* @since 5.2.7
* @see org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests
*/
class AspectJAutoProxyAdviceOrderIntegrationTests {
/**
* {@link After @After} advice declared as first <em>after</em> method in source code.
*/
@Nested
@SpringJUnitConfig(AfterAdviceFirstConfig.class)
@DirtiesContext
class AfterAdviceFirstTests {
@Test
void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceFirstAspect aspect) throws Exception {
assertThat(aspect.invocations).isEmpty();
assertThat(echo.echo(42)).isEqualTo(42);
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(
() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
}
}
/**
* This test class uses {@link AfterAdviceLastAspect} which declares its
* {@link After @After} advice as the last <em>after advice type</em> method
* in its source code.
*
* <p>On Java versions prior to JDK 7, we would have expected the {@code @After}
* advice method to be invoked before {@code @AfterThrowing} and
* {@code @AfterReturning} advice methods due to the AspectJ precedence
* rules implemented in
* {@link org.springframework.aop.aspectj.autoproxy.AspectJPrecedenceComparator}.
*/
@Nested
@SpringJUnitConfig(AfterAdviceLastConfig.class)
@DirtiesContext
class AfterAdviceLastTests {
@Test
void afterAdviceIsInvokedLast(@Autowired Echo echo, @Autowired AfterAdviceLastAspect aspect) throws Exception {
assertThat(aspect.invocations).isEmpty();
assertThat(echo.echo(42)).isEqualTo(42);
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
aspect.invocations.clear();
assertThatExceptionOfType(Exception.class).isThrownBy(
() -> echo.echo(new Exception()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
}
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
static class AfterAdviceFirstConfig {
@Bean
AfterAdviceFirstAspect echoAspect() {
return new AfterAdviceFirstAspect();
}
@Bean
Echo echo() {
return new Echo();
}
}
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
static class AfterAdviceLastConfig {
@Bean
AfterAdviceLastAspect echoAspect() {
return new AfterAdviceLastAspect();
}
@Bean
Echo echo() {
return new Echo();
}
}
static class Echo {
Object echo(Object obj) throws Exception {
if (obj instanceof Exception) {
throw (Exception) obj;
}
return obj;
}
}
/**
* {@link After @After} advice declared as first <em>after</em> method in source code.
*/
@Aspect
static class AfterAdviceFirstAspect {
List<String> invocations = new ArrayList<>();
@Pointcut("execution(* echo(*))")
void echo() {
}
@After("echo()")
void after() {
invocations.add("after");
}
@AfterReturning("echo()")
void afterReturning() {
invocations.add("after returning");
}
@AfterThrowing("echo()")
void afterThrowing() {
invocations.add("after throwing");
}
@Before("echo()")
void before() {
invocations.add("before");
}
@Around("echo()")
Object around(ProceedingJoinPoint joinPoint) throws Throwable {
invocations.add("around - start");
try {
return joinPoint.proceed();
}
finally {
invocations.add("around - end");
}
}
}
/**
* {@link After @After} advice declared as last <em>after</em> method in source code.
*/
@Aspect
static class AfterAdviceLastAspect {
List<String> invocations = new ArrayList<>();
@Pointcut("execution(* echo(*))")
void echo() {
}
@Around("echo()")
Object around(ProceedingJoinPoint joinPoint) throws Throwable {
invocations.add("around - start");
try {
return joinPoint.proceed();
}
finally {
invocations.add("around - end");
}
}
@Before("echo()")
void before() {
invocations.add("before");
}
@AfterReturning("echo()")
void afterReturning() {
invocations.add("after returning");
}
@AfterThrowing("echo()")
void afterThrowing() {
invocations.add("after throwing");
}
@After("echo()")
void after() {
invocations.add("after");
}
}
}
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="echo" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$Echo"/>
<bean id="invocationTrackingAspect" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$InvocationTrackingAspect" />
<aop:config>
<aop:aspect id="echoAdvice" ref="invocationTrackingAspect">
<aop:pointcut id="echoMethod" expression="execution(* echo(*))" />
<aop:around method="around" pointcut-ref="echoMethod" />
<aop:before method="before" pointcut-ref="echoMethod" />
<aop:after method="after" pointcut-ref="echoMethod" />
<aop:after-throwing method="afterThrowing" pointcut-ref="echoMethod" />
<aop:after-returning method="afterReturning" pointcut-ref="echoMethod" />
</aop:aspect>
</aop:config>
</beans>
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="echo" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$Echo"/>
<bean id="invocationTrackingAspect" class="org.springframework.aop.config.AopNamespaceHandlerAdviceOrderIntegrationTests$InvocationTrackingAspect" />
<aop:config>
<aop:aspect id="echoAdvice" ref="invocationTrackingAspect">
<aop:pointcut id="echoMethod" expression="execution(* echo(*))" />
<aop:around method="around" pointcut-ref="echoMethod" />
<aop:before method="before" pointcut-ref="echoMethod" />
<aop:after-throwing method="afterThrowing" pointcut-ref="echoMethod" />
<aop:after-returning method="afterReturning" pointcut-ref="echoMethod" />
<aop:after method="after" pointcut-ref="echoMethod" />
</aop:aspect>
</aop:config>
</beans>
+2 -2
View File
@@ -10,8 +10,8 @@ include "spring-aop"
include "spring-aspects"
include "spring-beans"
include "spring-context"
include "spring-context-support"
include "spring-context-indexer"
include "spring-context-support"
include "spring-core"
include "kotlin-coroutines"
project(':kotlin-coroutines').projectDir = file('spring-core/kotlin-coroutines')
@@ -26,8 +26,8 @@ include "spring-oxm"
include "spring-test"
include "spring-tx"
include "spring-web"
include "spring-webmvc"
include "spring-webflux"
include "spring-webmvc"
include "spring-websocket"
include "framework-bom"
include "integration-tests"
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2021 the original author 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 java.lang.reflect.AccessibleObject;
* terminology).
*
* <p>A runtime joinpoint is an <i>event</i> that occurs on a static
* joinpoint (i.e. a location in a the program). For instance, an
* joinpoint (i.e. a location in a program). For instance, an
* invocation is the runtime joinpoint on a method (static joinpoint).
* The static part of a given joinpoint can be generically retrieved
* using the {@link #getStaticPart()} method.
@@ -33,9 +33,9 @@ public interface AfterReturningAdvice extends AfterAdvice {
/**
* Callback after a given method successfully returned.
* @param returnValue the value returned by the method, if any
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @param method the method being invoked
* @param args the arguments to the method
* @param target the target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@ import org.aopalliance.aop.Advice;
* <p>Introductions are often <b>mixins</b>, enabling the building of composite
* objects that can achieve many of the goals of multiple inheritance in Java.
*
* <p>Compared to {qlink IntroductionInfo}, this interface allows an advice to
* <p>Compared to {@link IntroductionInfo}, this interface allows an advice to
* implement a range of interfaces that is not necessarily known in advance.
* Thus an {@link IntroductionAdvisor} can be used to specify which interfaces
* will be exposed in an advised object.
@@ -32,9 +32,9 @@ public interface MethodBeforeAdvice extends BeforeAdvice {
/**
* Callback before a given method is invoked.
* @param method method being invoked
* @param args arguments to the method
* @param target target of the method invocation. May be {@code null}.
* @param method the method being invoked
* @param args the arguments to the method
* @param target the target of the method invocation. May be {@code null}.
* @throws Throwable if this object wishes to abort the call.
* Any exception thrown will be returned to the caller if it's
* allowed by the method signature. Otherwise the exception
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -648,7 +648,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
}
if (tokens[currentIndex].endsWith(")")) {
sb.append(tokens[currentIndex].substring(0, tokens[currentIndex].length() - 1));
sb.append(tokens[currentIndex], 0, tokens[currentIndex].length() - 1);
return new PointcutBody(numTokensConsumed, sb.toString().trim());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -219,10 +219,12 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
@Override
@Nullable
public String[] getParameterNames() {
if (this.parameterNames == null) {
this.parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
String[] parameterNames = this.parameterNames;
if (parameterNames == null) {
parameterNames = parameterNameDiscoverer.getParameterNames(getMethod());
this.parameterNames = parameterNames;
}
return this.parameterNames;
return parameterNames;
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -103,10 +103,11 @@ public abstract class AbstractAspectJAdvisorFactory implements AspectJAdvisorFac
@Override
public void validate(Class<?> aspectClass) throws AopConfigException {
// If the parent has the annotation and isn't abstract it's an error
if (aspectClass.getSuperclass().getAnnotation(Aspect.class) != null &&
!Modifier.isAbstract(aspectClass.getSuperclass().getModifiers())) {
Class<?> superclass = aspectClass.getSuperclass();
if (superclass.getAnnotation(Aspect.class) != null &&
!Modifier.isAbstract(superclass.getModifiers())) {
throw new AopConfigException("[" + aspectClass.getName() + "] cannot extend concrete aspect [" +
aspectClass.getSuperclass().getName() + "]");
superclass.getName() + "]");
}
AjType<?> ajType = AjTypeSystem.getAjType(aspectClass);
@@ -56,7 +56,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst
* introspect to create AJType metadata using the type returned for the
* given bean name from the BeanFactory.
* @param beanFactory the BeanFactory to obtain instance(s) from
* @param name name of the bean
* @param name the name of the bean
*/
public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) {
this(beanFactory, name, null);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@ public class BeanFactoryAspectJAdvisorsBuilder {
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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,14 +56,15 @@ import org.springframework.util.comparator.InstanceComparator;
/**
* Factory that can create Spring AOP Advisors given AspectJ classes from
* classes honoring the AspectJ 5 annotation syntax, using reflection to
* invoke the corresponding advice methods.
* classes honoring AspectJ's annotation syntax, using reflection to invoke the
* corresponding advice methods.
*
* @author Rod Johnson
* @author Adrian Colyer
* @author Juergen Hoeller
* @author Ramnivas Laddad
* @author Phillip Webb
* @author Sam Brannen
* @since 2.0
*/
@SuppressWarnings("serial")
@@ -72,13 +73,17 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
private static final Comparator<Method> METHOD_COMPARATOR;
static {
// Note: although @After is ordered before @AfterReturning and @AfterThrowing,
// an @After advice method will actually be invoked after @AfterReturning and
// @AfterThrowing methods due to the fact that AspectJAfterAdvice.invoke(MethodInvocation)
// invokes proceed() in a `try` block and only invokes the @After advice method
// in a corresponding `finally` block.
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> annotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (annotation != null ? annotation.getAnnotation() : null);
AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (ann != null ? ann.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
@@ -123,7 +128,15 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
@@ -154,7 +167,9 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
methods.add(method);
}
}, ReflectionUtils.USER_DECLARED_METHODS);
methods.sort(METHOD_COMPARATOR);
if (methods.size() > 1) {
methods.sort(METHOD_COMPARATOR);
}
return methods;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,27 +50,27 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
/**
* Sort the rest by AspectJ precedence. If two pieces of advice have
* come from the same aspect they will have the same order.
* Advice from the same aspect is then further ordered according to the
* Sort the supplied {@link Advisor} instances according to AspectJ precedence.
* <p>If two pieces of advice come from the same aspect, they will have the same
* order. Advice from the same aspect is then further ordered according to the
* following rules:
* <ul>
* <li>if either of the pair is after advice, then the advice declared
* last gets highest precedence (runs last)</li>
* <li>otherwise the advice declared first gets highest precedence (runs first)</li>
* <li>If either of the pair is <em>after</em> advice, then the advice declared
* last gets highest precedence (i.e., runs last).</li>
* <li>Otherwise the advice declared first gets highest precedence (i.e., runs
* first).</li>
* </ul>
* <p><b>Important:</b> Advisors are sorted in precedence order, from highest
* precedence to lowest. "On the way in" to a join point, the highest precedence
* advisor should run first. "On the way out" of a join point, the highest precedence
* advisor should run last.
* advisor should run first. "On the way out" of a join point, the highest
* precedence advisor should run last.
*/
@Override
@SuppressWarnings("unchecked")
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
for (Advisor element : advisors) {
for (Advisor advisor : advisors) {
partiallyComparableAdvisors.add(
new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
}
List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
if (sorted != null) {
@@ -86,8 +86,8 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
}
/**
* Adds an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
* These additional advices are needed when using AspectJ expression pointcuts
* Add an {@link ExposeInvocationInterceptor} to the beginning of the advice chain.
* <p>This additional advice is needed when using AspectJ pointcut expressions
* and when using AspectJ-style advice.
*/
@Override
@@ -110,7 +110,7 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
/**
* Implements AspectJ PartialComparable interface for defining partial orderings.
* Implements AspectJ's {@link PartialComparable} interface for defining partial orderings.
*/
private static class PartiallyComparableAdvisorHolder implements PartialComparable {
@@ -140,17 +140,19 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Advice advice = this.advisor.getAdvice();
sb.append(ClassUtils.getShortName(advice.getClass()));
sb.append(": ");
StringBuilder sb = new StringBuilder(ClassUtils.getShortName(advice.getClass()));
boolean appended = false;
if (this.advisor instanceof Ordered) {
sb.append("order ").append(((Ordered) this.advisor).getOrder()).append(", ");
sb.append(": order = ").append(((Ordered) this.advisor).getOrder());
appended = true;
}
if (advice instanceof AbstractAspectJAdvice) {
sb.append(!appended ? ": " : ", ");
AbstractAspectJAdvice ajAdvice = (AbstractAspectJAdvice) advice;
sb.append("aspect name = ");
sb.append(ajAdvice.getAspectName());
sb.append(", declaration order ");
sb.append(", declaration order = ");
sb.append(ajAdvice.getDeclarationOrder());
}
return sb.toString();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,20 +27,22 @@ import org.springframework.util.Assert;
/**
* Orders AspectJ advice/advisors by precedence (<i>not</i> invocation order).
*
* <p>Given two pieces of advice, {@code a} and {@code b}:
* <p>Given two pieces of advice, {@code A} and {@code B}:
* <ul>
* <li>if {@code a} and {@code b} are defined in different aspects, then the advice
* in the aspect with the lowest order value has the highest precedence</li>
* <li>if {@code a} and {@code b} are defined in the same aspect, then if one of
* {@code a} or {@code b} is a form of after advice, then the advice declared last
* in the aspect has the highest precedence. If neither {@code a} nor {@code b} is
* a form of after advice, then the advice declared first in the aspect has the
* highest precedence.</li>
* <li>If {@code A} and {@code B} are defined in different aspects, then the advice
* in the aspect with the lowest order value has the highest precedence.</li>
* <li>If {@code A} and {@code B} are defined in the same aspect, if one of
* {@code A} or {@code B} is a form of <em>after</em> advice, then the advice declared
* last in the aspect has the highest precedence. If neither {@code A} nor {@code B}
* is a form of <em>after</em> advice, then the advice declared first in the aspect
* has the highest precedence.</li>
* </ul>
*
* <p>Important: Note that unlike a normal comparator a return of 0 means
* we don't care about the ordering, not that the two elements must be sorted
* identically. Used with AspectJ PartialOrder class.
* <p>Important: This comparator is used with AspectJ's
* {@link org.aspectj.util.PartialOrder PartialOrder} sorting utility. Thus, unlike
* a normal {@link Comparator}, a return value of {@code 0} from this comparator
* means we don't care about the ordering, not that the two elements must be sorted
* identically.
*
* @author Adrian Colyer
* @author Juergen Hoeller
@@ -59,16 +61,16 @@ class AspectJPrecedenceComparator implements Comparator<Advisor> {
/**
* Create a default AspectJPrecedenceComparator.
* Create a default {@code AspectJPrecedenceComparator}.
*/
public AspectJPrecedenceComparator() {
this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
}
/**
* Create a AspectJPrecedenceComparator, using the given Comparator
* Create an {@code AspectJPrecedenceComparator}, using the given {@link Comparator}
* for comparing {@link org.springframework.aop.Advisor} instances.
* @param advisorComparator the Comparator to use for Advisors
* @param advisorComparator the {@code Comparator} to use for advisors
*/
public AspectJPrecedenceComparator(Comparator<? super Advisor> advisorComparator) {
Assert.notNull(advisorComparator, "Advisor comparator must not be null");
@@ -125,27 +127,21 @@ class AspectJPrecedenceComparator implements Comparator<Advisor> {
getAspectName(advisor1).equals(getAspectName(advisor2)));
}
private boolean hasAspectName(Advisor anAdvisor) {
return (anAdvisor instanceof AspectJPrecedenceInformation ||
anAdvisor.getAdvice() instanceof AspectJPrecedenceInformation);
private boolean hasAspectName(Advisor advisor) {
return (advisor instanceof AspectJPrecedenceInformation ||
advisor.getAdvice() instanceof AspectJPrecedenceInformation);
}
// pre-condition is that hasAspectName returned true
private String getAspectName(Advisor anAdvisor) {
AspectJPrecedenceInformation pi = AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
Assert.state(pi != null, "Unresolvable precedence information");
return pi.getAspectName();
private String getAspectName(Advisor advisor) {
AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(advisor);
Assert.state(precedenceInfo != null, () -> "Unresolvable AspectJPrecedenceInformation for " + advisor);
return precedenceInfo.getAspectName();
}
private int getAspectDeclarationOrder(Advisor anAdvisor) {
AspectJPrecedenceInformation precedenceInfo =
AspectJAopUtils.getAspectJPrecedenceInformationFor(anAdvisor);
if (precedenceInfo != null) {
return precedenceInfo.getDeclarationOrder();
}
else {
return 0;
}
private int getAspectDeclarationOrder(Advisor advisor) {
AspectJPrecedenceInformation precedenceInfo = AspectJAopUtils.getAspectJPrecedenceInformationFor(advisor);
return (precedenceInfo != null ? precedenceInfo.getDeclarationOrder() : 0);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2020 the original author 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,14 @@ public class AdviceEntry implements ParseState.Entry {
/**
* Creates a new instance of the {@link AdviceEntry} class.
* @param kind the kind of advice represented by this entry (before, after, around, etc.)
* Create a new {@code AdviceEntry} instance.
* @param kind the kind of advice represented by this entry (before, after, around)
*/
public AdviceEntry(String kind) {
this.kind = kind;
}
@Override
public String toString() {
return "Advice (" + this.kind + ")";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2020 the original author 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,14 @@ public class AdvisorEntry implements ParseState.Entry {
/**
* Creates a new instance of the {@link AdvisorEntry} class.
* Create a new {@code AdvisorEntry} instance.
* @param name the bean name of the advisor
*/
public AdvisorEntry(String name) {
this.name = name;
}
@Override
public String toString() {
return "Advisor '" + this.name + "'";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,12 +61,12 @@ public class AopNamespaceHandler extends NamespaceHandlerSupport {
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
// In 2.0 XSD as well as in 2.5+ XSDs
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
// Only in 2.0 XSD: moved to context namespace in 2.5+
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public class AspectEntry implements ParseState.Entry {
/**
* Create a new AspectEntry.
* Create a new {@code AspectEntry} instance.
* @param id the id of the aspect element
* @param ref the bean name referenced by this aspect element
*/
@@ -43,6 +43,7 @@ public class AspectEntry implements ParseState.Entry {
this.ref = ref;
}
@Override
public String toString() {
return "Aspect: " + (StringUtils.hasLength(this.id) ? "id='" + this.id + "'" : "ref='" + this.ref + "'");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,14 +28,16 @@ public class PointcutEntry implements ParseState.Entry {
private final String name;
/**
* Creates a new instance of the {@link PointcutEntry} class.
* Create a new {@code PointcutEntry} instance.
* @param name the bean name of the pointcut
*/
public PointcutEntry(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pointcut '" + this.name + "'";
@@ -189,7 +189,7 @@ public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
/**
* Determine a TargetSource for the given target (or TargetSource).
* @param target target. If this is an implementation of TargetSource it is
* @param target the target. If this is an implementation of TargetSource it is
* used as our TargetSource; otherwise it is wrapped in a SingletonTargetSource.
* @return a TargetSource for this object
*/
@@ -142,7 +142,7 @@ public interface Advised extends TargetClassAware {
/**
* Remove the advisor at the given index.
* @param index index of advisor to remove
* @param index the index of advisor to remove
* @throws AopConfigException if the index is invalid
*/
void removeAdvisor(int index) throws AopConfigException;
@@ -177,7 +177,7 @@ public interface Advised extends TargetClassAware {
* <p>Note that the given advice will apply to all invocations on the proxy,
* even to the {@code toString()} method! Use appropriate advice implementations
* or specify appropriate pointcuts to apply to a narrower set of methods.
* @param advice advice to add to the tail of the chain
* @param advice the advice to add to the tail of the chain
* @throws AopConfigException in case of invalid advice
* @see #addAdvice(int, Advice)
* @see org.springframework.aop.support.DefaultPointcutAdvisor
@@ -193,7 +193,7 @@ public interface Advised extends TargetClassAware {
* even to the {@code toString()} method! Use appropriate advice implementations
* or specify appropriate pointcuts to apply to a narrower set of methods.
* @param pos index from 0 (head)
* @param advice advice to add at the specified position in the advice chain
* @param advice the advice to add at the specified position in the advice chain
* @throws AopConfigException in case of invalid advice
*/
void addAdvice(int pos, Advice advice) throws AopConfigException;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author 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,6 +49,7 @@ import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.core.KotlinDetector;
import org.springframework.core.SmartClassLoader;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -236,7 +237,7 @@ class CglibAopProxy implements AopProxy, Serializable {
* validates it if not.
*/
private void validateClassIfNecessary(Class<?> proxySuperClass, @Nullable ClassLoader proxyClassLoader) {
if (logger.isWarnEnabled()) {
if (logger.isInfoEnabled()) {
synchronized (validatedClasses) {
if (!validatedClasses.containsKey(proxySuperClass)) {
doValidateClass(proxySuperClass, proxyClassLoader,
@@ -258,15 +259,17 @@ class CglibAopProxy implements AopProxy, Serializable {
int mod = method.getModifiers();
if (!Modifier.isStatic(mod) && !Modifier.isPrivate(mod)) {
if (Modifier.isFinal(mod)) {
if (implementsInterface(method, ifcs)) {
if (logger.isInfoEnabled() && implementsInterface(method, ifcs)) {
logger.info("Unable to proxy interface-implementing method [" + method + "] because " +
"it is marked as final: Consider using interface-based JDK proxies instead!");
}
logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " +
"Calls to this method will NOT be routed to the target instance and " +
"might lead to NPEs against uninitialized fields in the proxy instance.");
if (logger.isDebugEnabled()) {
logger.debug("Final method [" + method + "] cannot get proxied via CGLIB: " +
"Calls to this method will NOT be routed to the target instance and " +
"might lead to NPEs against uninitialized fields in the proxy instance.");
}
}
else if (!Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
else if (logger.isDebugEnabled() && !Modifier.isPublic(mod) && !Modifier.isProtected(mod) &&
proxyClassLoader != null && proxySuperClass.getClassLoader() != proxyClassLoader) {
logger.debug("Method [" + method + "] is package-visible across different ClassLoaders " +
"and cannot get proxied via CGLIB: Declare this method as public or protected " +
@@ -372,6 +375,22 @@ class CglibAopProxy implements AopProxy, Serializable {
return false;
}
/**
* Invoke the given method with a CGLIB MethodProxy if possible, falling back
* to a plain reflection invocation in case of a fast-class generation failure.
*/
@Nullable
private static Object invokeMethod(@Nullable Object target, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
try {
return methodProxy.invoke(target, args);
}
catch (CodeGenerationException ex) {
CglibMethodInvocation.logFastClassGenerationFailure(method);
return AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
}
/**
* Process a return value. Wraps a return of {@code this} if necessary to be the
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
@@ -422,7 +441,7 @@ class CglibAopProxy implements AopProxy, Serializable {
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object retVal = methodProxy.invoke(this.target, args);
Object retVal = invokeMethod(this.target, method, args, methodProxy);
return processReturnType(proxy, this.target, method, retVal);
}
}
@@ -447,7 +466,7 @@ class CglibAopProxy implements AopProxy, Serializable {
Object oldProxy = null;
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(this.target, args);
Object retVal = invokeMethod(this.target, method, args, methodProxy);
return processReturnType(proxy, this.target, method, retVal);
}
finally {
@@ -475,7 +494,7 @@ class CglibAopProxy implements AopProxy, Serializable {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object target = this.targetSource.getTarget();
try {
Object retVal = methodProxy.invoke(target, args);
Object retVal = invokeMethod(target, method, args, methodProxy);
return processReturnType(proxy, target, method, retVal);
}
finally {
@@ -505,7 +524,7 @@ class CglibAopProxy implements AopProxy, Serializable {
Object target = this.targetSource.getTarget();
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(target, args);
Object retVal = invokeMethod(target, method, args, methodProxy);
return processReturnType(proxy, target, method, retVal);
}
finally {
@@ -526,7 +545,7 @@ class CglibAopProxy implements AopProxy, Serializable {
private static class StaticDispatcher implements Dispatcher, Serializable {
@Nullable
private Object target;
private final Object target;
public StaticDispatcher(@Nullable Object target) {
this.target = target;
@@ -552,7 +571,7 @@ class CglibAopProxy implements AopProxy, Serializable {
}
@Override
public Object loadObject() throws Exception {
public Object loadObject() {
return this.advised;
}
}
@@ -676,13 +695,13 @@ class CglibAopProxy implements AopProxy, Serializable {
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
retVal = invokeMethod(target, method, argsToUse, methodProxy);
}
else {
// We need to create a method invocation...
@@ -734,10 +753,7 @@ class CglibAopProxy implements AopProxy, Serializable {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
// Only use method proxy for public methods not derived from java.lang.Object
this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
methodProxy : null);
this.methodProxy = (isMethodProxyCompatible(method) ? methodProxy : null);
}
@Override
@@ -750,10 +766,17 @@ class CglibAopProxy implements AopProxy, Serializable {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass()) ||
KotlinDetector.isKotlinType(getMethod().getDeclaringClass())) {
// Propagate original exception if declared on the target method
// (with callers expecting it). Always propagate it for Kotlin code
// since checked exceptions do not have to be explicitly declared there.
throw ex;
}
else {
// Checked exception thrown in the interceptor but not declared on the
// target method signature -> apply an UndeclaredThrowableException,
// aligned with standard JDK dynamic proxy behavior.
throw new UndeclaredThrowableException(ex);
}
}
@@ -766,10 +789,25 @@ class CglibAopProxy implements AopProxy, Serializable {
@Override
protected Object invokeJoinpoint() throws Throwable {
if (this.methodProxy != null) {
return this.methodProxy.invoke(this.target, this.arguments);
try {
return this.methodProxy.invoke(this.target, this.arguments);
}
catch (CodeGenerationException ex) {
logFastClassGenerationFailure(this.method);
}
}
else {
return super.invokeJoinpoint();
return super.invokeJoinpoint();
}
static boolean isMethodProxyCompatible(Method method) {
return (Modifier.isPublic(method.getModifiers()) &&
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method));
}
static void logFastClassGenerationFailure(Method method) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to generate CGLIB fast class for method: " + method);
}
}
}
@@ -872,15 +910,14 @@ class CglibAopProxy implements AopProxy, Serializable {
}
return AOP_PROXY;
}
Method key = method;
// Check to see if we have fixed interceptor to serve this method.
// Else use the AOP_PROXY.
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(key)) {
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Method has advice and optimizations are enabled: " + method);
}
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(key);
int index = this.fixedInterceptorMap.get(method);
return (index + this.fixedInterceptorOffset);
}
else {
@@ -959,11 +996,11 @@ class CglibAopProxy implements AopProxy, Serializable {
return true;
}
private boolean equalsAdviceClasses(Advisor a, Advisor b) {
private static boolean equalsAdviceClasses(Advisor a, Advisor b) {
return (a.getAdvice().getClass() == b.getAdvice().getClass());
}
private boolean equalsPointcuts(Advisor a, Advisor b) {
private static boolean equalsPointcuts(Advisor a, Advisor b) {
// If only one of the advisor (but not both) is PointcutAdvisor, then it is a mismatch.
// Takes care of the situations where an IntroductionAdvisor is used (see SPR-3959).
return (!(a instanceof PointcutAdvisor) ||
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -43,9 +43,11 @@ import org.springframework.aop.SpringProxy;
* @see AdvisedSupport#setProxyTargetClass
* @see AdvisedSupport#setInterfaces
*/
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
private static final long serialVersionUID = 7930414337282325166L;
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author 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,9 +21,7 @@ import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.Interceptor;
@@ -342,11 +340,8 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// an independent instance of the configuration.
// In this case, no proxy will have an instance of this object's configuration,
// but will have an independent copy.
if (logger.isTraceEnabled()) {
logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
}
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// The copy needs a fresh advisor chain, and a fresh TargetSource.
TargetSource targetSource = freshTargetSource();
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
@@ -359,9 +354,6 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
}
copy.setFrozen(this.freezeProxy);
if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
return getProxy(copy.createAopProxy());
}
@@ -429,11 +421,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
* are unaffected by such changes.
*/
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
if (this.advisorChainInitialized) {
return;
}
if (!ObjectUtils.isEmpty(this.interceptorNames)) {
if (!this.advisorChainInitialized && !ObjectUtils.isEmpty(this.interceptorNames)) {
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
@@ -447,16 +435,12 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// Materialize interceptor chain from bean names.
for (String name : this.interceptorNames) {
if (logger.isTraceEnabled()) {
logger.trace("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
addGlobalAdvisors((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
}
@@ -473,12 +457,12 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(name);
}
addAdvisorOnChainCreation(advice, name);
addAdvisorOnChainCreation(advice);
}
}
}
this.advisorChainInitialized = true;
this.advisorChainInitialized = true;
}
}
@@ -496,11 +480,10 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
if (logger.isDebugEnabled()) {
logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");
}
// Replace the placeholder with a fresh prototype instance resulting
// from a getBean() lookup
// Replace the placeholder with a fresh prototype instance resulting from a getBean lookup
if (this.beanFactory == null) {
throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
"- cannot resolve prototype advisor '" + pa.getBeanName() + "'");
throw new IllegalStateException("No BeanFactory available anymore (probably due to " +
"serialization) - cannot resolve prototype advisor '" + pa.getBeanName() + "'");
}
Object bean = this.beanFactory.getBean(pa.getBeanName());
Advisor refreshedAdvisor = namedBeanToAdvisor(bean);
@@ -517,28 +500,26 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
/**
* Add all global interceptors and pointcuts.
*/
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
private void addGlobalAdvisors(ListableBeanFactory beanFactory, String prefix) {
String[] globalAdvisorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class);
String[] globalInterceptorNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class);
List<Object> beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length);
Map<Object, String> names = new HashMap<>(beans.size());
for (String name : globalAdvisorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
for (String name : globalInterceptorNames) {
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
AnnotationAwareOrderComparator.sort(beans);
for (Object bean : beans) {
String name = names.get(bean);
if (name.startsWith(prefix)) {
addAdvisorOnChainCreation(bean, name);
if (globalAdvisorNames.length > 0 || globalInterceptorNames.length > 0) {
List<Object> beans = new ArrayList<>(globalAdvisorNames.length + globalInterceptorNames.length);
for (String name : globalAdvisorNames) {
if (name.startsWith(prefix)) {
beans.add(beanFactory.getBean(name));
}
}
for (String name : globalInterceptorNames) {
if (name.startsWith(prefix)) {
beans.add(beanFactory.getBean(name));
}
}
AnnotationAwareOrderComparator.sort(beans);
for (Object bean : beans) {
addAdvisorOnChainCreation(bean);
}
}
}
@@ -549,17 +530,11 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
* Because of these three possibilities, we can't type the signature
* more strongly.
* @param next advice, advisor or target object
* @param name bean name from which we obtained this object in our owning
* bean factory
*/
private void addAdvisorOnChainCreation(Object next, String name) {
private void addAdvisorOnChainCreation(Object next) {
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
if (logger.isTraceEnabled()) {
logger.trace("Adding advisor with name '" + name + "'");
}
addAdvisor(advisor);
addAdvisor(namedBeanToAdvisor(next));
}
/**
@@ -570,9 +545,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
*/
private TargetSource freshTargetSource() {
if (this.targetName == null) {
if (logger.isTraceEnabled()) {
logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");
}
// Not refreshing target: bean name not specified in 'interceptorNames'
return this.targetSource;
}
else {
@@ -600,8 +573,8 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
// We expected this to be an Advisor or Advice,
// but it wasn't. This is a configuration error.
throw new AopConfigException("Unknown advisor type " + next.getClass() +
"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry, " +
"which may also be target or TargetSource", ex);
"; can only include Advisor or Advice type beans in interceptorNames chain " +
"except for last entry which may also be target instance or TargetSource", ex);
}
}
@@ -612,7 +585,7 @@ public class ProxyFactoryBean extends ProxyCreatorSupport
protected void adviceChanged() {
super.adviceChanged();
if (this.singleton) {
logger.debug("Advice has changed; recaching singleton instance");
logger.debug("Advice has changed; re-caching singleton instance");
synchronized (this) {
this.singletonInstance = null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,9 +26,9 @@ import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.util.Assert;
/**
* Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}.
* Used internally by the AOP framework; application developers should not need
* to use this class directly.
* Interceptor to wrap a {@link MethodBeforeAdvice}.
* <p>Used internally by the AOP framework; application developers should not
* need to use this class directly.
*
* @author Rod Johnson
* @see AfterReturningAdviceInterceptor
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,11 +36,13 @@ import org.springframework.util.Assert;
* also override the inherited {@link #shouldSkip} method to exclude certain
* objects from auto-proxying.
*
* <p>Advisors or advices requiring ordering should implement the
* <p>Advisors or advices requiring ordering should be annotated with
* {@link org.springframework.core.annotation.Order @Order} or implement the
* {@link org.springframework.core.Ordered} interface. This class sorts
* Advisors by Ordered order value. Advisors that don't implement the
* Ordered interface will be considered as unordered; they will appear
* at the end of the advisor chain in undefined order.
* advisors using the {@link AnnotationAwareOrderComparator}. Advisors that are
* not annotated with {@code @Order} or don't implement the {@code Ordered}
* interface will be considered as unordered; they will appear at the end of the
* advisor chain in an undefined order.
*
* @author Rod Johnson
* @author Juergen Hoeller
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.aop.framework.autoproxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -449,7 +450,17 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
@@ -513,7 +524,10 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (specificInterceptors.length > 0) {
// specificInterceptors may equals PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS
allInterceptors.addAll(Arrays.asList(specificInterceptors));
}
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -103,7 +103,8 @@ public abstract class AbstractMonitoringInterceptor extends AbstractTraceInterce
if (this.logTargetClassInvocation && clazz.isInstance(invocation.getThis())) {
clazz = invocation.getThis().getClass();
}
return getPrefix() + clazz.getName() + '.' + method.getName() + getSuffix();
String className = clazz.getName();
return getPrefix() + className + '.' + method.getName() + getSuffix();
}
}
@@ -78,7 +78,7 @@ public abstract class AbstractExpressionPointcut implements ExpressionPointcut,
* Called when a new pointcut expression is set.
* The expression should be parsed at this point if possible.
* <p>This implementation is empty.
* @param expression expression to set
* @param expression the expression to set
* @throws IllegalArgumentException if the expression is invalid
* @see #setExpression
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,7 +71,8 @@ public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFil
if (introductionInfo != null) {
Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();
if (introducedInterfaces.length == 0) {
throw new IllegalArgumentException("IntroductionAdviceSupport implements no interfaces");
throw new IllegalArgumentException(
"IntroductionInfo defines no interfaces to introduce: " + introductionInfo);
}
for (Class<?> ifc : introducedInterfaces) {
addInterface(ifc);
@@ -66,7 +66,7 @@ public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut impleme
* before a proxy is used.
* <p><b>NB:</b> This method does not work after the proxy is in
* use, as advice chains will be cached.
* @param name name of the additional method that will match
* @param name the name of the additional method that will match
* @return this pointcut to allow for multiple additions in one line
*/
public NameMatchMethodPointcut addMethodName(String name) {
@@ -76,7 +76,7 @@ public class NameMatchMethodPointcutAdvisor extends AbstractGenericPointcutAdvis
* Add another eligible method name, in addition to those already named.
* Like the set methods, this method is for use when configuring proxies,
* before a proxy is used.
* @param name name of the additional method that will match
* @param name the name of the additional method that will match
* @return this pointcut to allow for multiple additions in one line
* @see NameMatchMethodPointcut#addMethodName
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -63,14 +64,16 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Abstract tests for AspectJAdvisorFactory.
* See subclasses for tests of concrete factories.
* Abstract tests for {@link AspectJAdvisorFactory} implementations.
*
* <p>See subclasses for tests of concrete factories.
*
* @author Rod Johnson
* @author Chris Beams
* @author Phillip Webb
* @author Sam Brannen
*/
public abstract class AbstractAspectJAdvisorFactoryTests {
abstract class AbstractAspectJAdvisorFactoryTests {
/**
* To be overridden by concrete test subclasses.
@@ -80,7 +83,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Test
public void testRejectsPerCflowAspect() {
void rejectsPerCflowAspect() {
assertThatExceptionOfType(AopConfigException.class).isThrownBy(() ->
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new PerCflowAspect(), "someBean")))
@@ -88,7 +91,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testRejectsPerCflowBelowAspect() {
void rejectsPerCflowBelowAspect() {
assertThatExceptionOfType(AopConfigException.class).isThrownBy(() ->
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new PerCflowBelowAspect(), "someBean")))
@@ -96,7 +99,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testPerTargetAspect() throws SecurityException, NoSuchMethodException {
void perTargetAspect() throws SecurityException, NoSuchMethodException {
TestBean target = new TestBean();
int realAge = 65;
target.setAge(realAge);
@@ -128,7 +131,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testMultiplePerTargetAspects() throws SecurityException, NoSuchMethodException {
void multiplePerTargetAspects() throws SecurityException, NoSuchMethodException {
TestBean target = new TestBean();
int realAge = 65;
target.setAge(realAge);
@@ -156,7 +159,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testMultiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException {
void multiplePerTargetAspectsWithOrderAnnotation() throws SecurityException, NoSuchMethodException {
TestBean target = new TestBean();
int realAge = 65;
target.setAge(realAge);
@@ -182,7 +185,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testPerThisAspect() throws SecurityException, NoSuchMethodException {
void perThisAspect() throws SecurityException, NoSuchMethodException {
TestBean target = new TestBean();
int realAge = 65;
target.setAge(realAge);
@@ -218,7 +221,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testPerTypeWithinAspect() throws SecurityException, NoSuchMethodException {
void perTypeWithinAspect() throws SecurityException, NoSuchMethodException {
TestBean target = new TestBean();
int realAge = 65;
target.setAge(realAge);
@@ -259,22 +262,22 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testNamedPointcutAspectWithFQN() {
testNamedPointcuts(new NamedPointcutAspectWithFQN());
void namedPointcutAspectWithFQN() {
namedPointcuts(new NamedPointcutAspectWithFQN());
}
@Test
public void testNamedPointcutAspectWithoutFQN() {
testNamedPointcuts(new NamedPointcutAspectWithoutFQN());
void namedPointcutAspectWithoutFQN() {
namedPointcuts(new NamedPointcutAspectWithoutFQN());
}
@Test
public void testNamedPointcutFromAspectLibrary() {
testNamedPointcuts(new NamedPointcutAspectFromLibrary());
void namedPointcutFromAspectLibrary() {
namedPointcuts(new NamedPointcutAspectFromLibrary());
}
@Test
public void testNamedPointcutFromAspectLibraryWithBinding() {
void namedPointcutFromAspectLibraryWithBinding() {
TestBean target = new TestBean();
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(new SingletonMetadataAwareAspectInstanceFactory(
@@ -285,7 +288,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
assertThat(target.getAge()).isEqualTo(20);
}
private void testNamedPointcuts(Object aspectInstance) {
private void namedPointcuts(Object aspectInstance) {
TestBean target = new TestBean();
int realAge = 65;
target.setAge(realAge);
@@ -297,7 +300,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testBindingWithSingleArg() {
void bindingWithSingleArg() {
TestBean target = new TestBean();
ITestBean itb = (ITestBean) createProxy(target,
getFixture().getAdvisors(
@@ -309,7 +312,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testBindingWithMultipleArgsDifferentlyOrdered() {
void bindingWithMultipleArgsDifferentlyOrdered() {
ManyValuedArgs target = new ManyValuedArgs();
ManyValuedArgs mva = (ManyValuedArgs) createProxy(target,
getFixture().getAdvisors(
@@ -329,7 +332,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
* In this case the introduction will be made.
*/
@Test
public void testIntroductionOnTargetNotImplementingInterface() {
void introductionOnTargetNotImplementingInterface() {
NotLockable notLockableTarget = new NotLockable();
assertThat(notLockableTarget instanceof Lockable).isFalse();
NotLockable notLockable1 = (NotLockable) createProxy(notLockableTarget,
@@ -358,7 +361,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testIntroductionAdvisorExcludedFromTargetImplementingInterface() {
void introductionAdvisorExcludedFromTargetImplementingInterface() {
assertThat(AopUtils.findAdvisorsThatCanApply(
getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeLockable(), "someBean")),
@@ -368,7 +371,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testIntroductionOnTargetImplementingInterface() {
void introductionOnTargetImplementingInterface() {
CannotBeUnlocked target = new CannotBeUnlocked();
Lockable proxy = (Lockable) createProxy(target,
// Ensure that we exclude
@@ -388,7 +391,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testIntroductionOnTargetExcludedByTypePattern() {
void introductionOnTargetExcludedByTypePattern() {
LinkedList<Object> target = new LinkedList<>();
List<?> proxy = (List<?>) createProxy(target,
AopUtils.findAdvisorsThatCanApply(
@@ -400,7 +403,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testIntroductionBasedOnAnnotationMatch_SPR5307() {
void introductionBasedOnAnnotationMatch_SPR5307() {
AnnotatedTarget target = new AnnotatedTargetImpl();
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new MakeAnnotatedTypeModifiable(), "someBean"));
@@ -414,7 +417,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
// TODO: Why does this test fail? It hasn't been run before, so it maybe never actually passed...
@Test
@Disabled
public void testIntroductionWithArgumentBinding() {
void introductionWithArgumentBinding() {
TestBean target = new TestBean();
List<Advisor> advisors = getFixture().getAdvisors(
@@ -448,11 +451,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testAspectMethodThrowsExceptionLegalOnSignature() {
void aspectMethodThrowsExceptionLegalOnSignature() {
TestBean target = new TestBean();
UnsupportedOperationException expectedException = new UnsupportedOperationException();
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean"));
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionThrowingAspect(expectedException), "someBean"));
assertThat(advisors.size()).as("One advice method was found").isEqualTo(1);
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
@@ -462,11 +465,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
// TODO document this behaviour.
// Is it different AspectJ behaviour, at least for checked exceptions?
@Test
public void testAspectMethodThrowsExceptionIllegalOnSignature() {
void aspectMethodThrowsExceptionIllegalOnSignature() {
TestBean target = new TestBean();
RemoteException expectedException = new RemoteException();
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionAspect(expectedException), "someBean"));
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionThrowingAspect(expectedException), "someBean"));
assertThat(advisors.size()).as("One advice method was found").isEqualTo(1);
ITestBean itb = (ITestBean) createProxy(target, advisors, ITestBean.class);
assertThatExceptionOfType(UndeclaredThrowableException.class).isThrownBy(
@@ -491,7 +494,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testTwoAdvicesOnOneAspect() {
void twoAdvicesOnOneAspect() {
TestBean target = new TestBean();
TwoAdviceAspect twoAdviceAspect = new TwoAdviceAspect();
List<Advisor> advisors = getFixture().getAdvisors(
@@ -506,25 +509,23 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testAfterAdviceTypes() throws Exception {
Echo target = new Echo();
ExceptionHandling afterReturningAspect = new ExceptionHandling();
void afterAdviceTypes() throws Exception {
InvocationTrackingAspect aspect = new InvocationTrackingAspect();
List<Advisor> advisors = getFixture().getAdvisors(
new SingletonMetadataAwareAspectInstanceFactory(afterReturningAspect, "someBean"));
Echo echo = (Echo) createProxy(target, advisors, Echo.class);
assertThat(afterReturningAspect.successCount).isEqualTo(0);
assertThat(echo.echo("")).isEqualTo("");
assertThat(afterReturningAspect.successCount).isEqualTo(1);
assertThat(afterReturningAspect.failureCount).isEqualTo(0);
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() ->
echo.echo(new FileNotFoundException()));
assertThat(afterReturningAspect.successCount).isEqualTo(1);
assertThat(afterReturningAspect.failureCount).isEqualTo(1);
assertThat(afterReturningAspect.afterCount).isEqualTo(afterReturningAspect.failureCount + afterReturningAspect.successCount);
new SingletonMetadataAwareAspectInstanceFactory(aspect, "exceptionHandlingAspect"));
Echo echo = (Echo) createProxy(new Echo(), advisors, Echo.class);
assertThat(aspect.invocations).isEmpty();
assertThat(echo.echo(42)).isEqualTo(42);
assertThat(aspect.invocations).containsExactly("around - start", "before", "after returning", "after", "around - end");
aspect.invocations.clear();
assertThatExceptionOfType(FileNotFoundException.class).isThrownBy(() -> echo.echo(new FileNotFoundException()));
assertThat(aspect.invocations).containsExactly("around - start", "before", "after throwing", "after", "around - end");
}
@Test
public void testFailureWithoutExplicitDeclarePrecedence() {
void failureWithoutExplicitDeclarePrecedence() {
TestBean target = new TestBean();
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
new NoDeclarePrecedenceShouldFail(), "someBean");
@@ -534,7 +535,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
}
@Test
public void testDeclarePrecedenceNotSupported() {
void declarePrecedenceNotSupported() {
TestBean target = new TestBean();
assertThatIllegalArgumentException().isThrownBy(() -> {
MetadataAwareAspectInstanceFactory aspectInstanceFactory = new SingletonMetadataAwareAspectInstanceFactory(
@@ -545,28 +546,28 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect("percflow(execution(* *(..)))")
public static class PerCflowAspect {
static class PerCflowAspect {
}
@Aspect("percflowbelow(execution(* *(..)))")
public static class PerCflowBelowAspect {
static class PerCflowBelowAspect {
}
@Aspect("pertarget(execution(* *.getSpouse()))")
@Order(10)
public static class PerTargetAspectWithOrderAnnotation10 {
static class PerTargetAspectWithOrderAnnotation10 {
public int count;
int count;
@Around("execution(int *.getAge())")
public int returnCountAsAge() {
int returnCountAsAge() {
return count++;
}
@Before("execution(void *.set*(int))")
public void countSetter() {
void countSetter() {
++count;
}
}
@@ -574,34 +575,34 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect("pertarget(execution(* *.getSpouse()))")
@Order(5)
public static class PerTargetAspectWithOrderAnnotation5 {
static class PerTargetAspectWithOrderAnnotation5 {
public int count;
int count;
@Around("execution(int *.getAge())")
public int returnCountAsAge() {
int returnCountAsAge() {
return count++;
}
@Before("execution(void *.set*(int))")
public void countSetter() {
void countSetter() {
++count;
}
}
@Aspect("pertypewithin(org.springframework.beans.testfixture.beans.IOther+)")
public static class PerTypeWithinAspect {
static class PerTypeWithinAspect {
public int count;
int count;
@Around("execution(int *.getAge())")
public int returnCountAsAge() {
int returnCountAsAge() {
return count++;
}
@Before("execution(void *.*(..))")
public void countAnythingVoid() {
void countAnythingVoid() {
++count;
}
}
@@ -611,7 +612,7 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
private int count;
public int getInstantiationCount() {
int getInstantiationCount() {
return this.count;
}
@@ -644,97 +645,96 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class NamedPointcutAspectWithFQN {
static class NamedPointcutAspectWithFQN {
@SuppressWarnings("unused")
private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
@Pointcut("execution(* getAge())")
public void getAge() {
void getAge() {
}
@Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.NamedPointcutAspectWithFQN.getAge()")
public int changeReturnValue(ProceedingJoinPoint pjp) {
int changeReturnValue(ProceedingJoinPoint pjp) {
return -1;
}
}
@Aspect
public static class NamedPointcutAspectWithoutFQN {
static class NamedPointcutAspectWithoutFQN {
@Pointcut("execution(* getAge())")
public void getAge() {
void getAge() {
}
@Around("getAge()")
public int changeReturnValue(ProceedingJoinPoint pjp) {
int changeReturnValue(ProceedingJoinPoint pjp) {
return -1;
}
}
@Aspect
public static class NamedPointcutAspectFromLibrary {
static class NamedPointcutAspectFromLibrary {
@Around("org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.propertyAccess()")
public int changeReturnType(ProceedingJoinPoint pjp) {
int changeReturnType(ProceedingJoinPoint pjp) {
return -1;
}
@Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x")
public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
pjp.proceed(new Object[] {x*2});
}
}
@Aspect
public static class Library {
static class Library {
@Pointcut("execution(!void get*())")
public void propertyAccess() {}
void propertyAccess() {}
@Pointcut("execution(* *(..)) && args(i)")
public void integerArgOperation(int i) {}
void integerArgOperation(int i) {}
}
@Aspect
public static class NamedPointcutAspectFromLibraryWithBinding {
static class NamedPointcutAspectFromLibraryWithBinding {
@Around(value="org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.Library.integerArgOperation(x)", argNames="x")
public void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
void doubleArg(ProceedingJoinPoint pjp, int x) throws Throwable {
pjp.proceed(new Object[] {x*2});
}
}
@Aspect
public static class BindingAspectWithSingleArg {
static class BindingAspectWithSingleArg {
@Pointcut(value="args(a)", argNames="a")
public void setAge(int a) {}
void setAge(int a) {}
@Around(value="setAge(age)",argNames="age")
// @ArgNames({"age"}) // AMC needs more work here? ignoring pjp arg... ok??
// argNames should be supported in Around as it is in Pointcut
public void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable {
void changeReturnType(ProceedingJoinPoint pjp, int age) throws Throwable {
pjp.proceed(new Object[] {age*2});
}
}
@Aspect
public static class ManyValuedArgs {
static class ManyValuedArgs {
public String mungeArgs(String a, int b, int c, String d, StringBuffer e) {
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")
public String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable {
String reverseAdvice(ProceedingJoinPoint pjp, int b, int c, String d, StringBuffer e, String a) throws Throwable {
assertThat(pjp.proceed()).isEqualTo(a + b+ c+ d+ e);
return a + b + c + d + e;
}
@@ -742,24 +742,24 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class ExceptionAspect {
static class ExceptionThrowingAspect {
private final Exception ex;
public ExceptionAspect(Exception ex) {
ExceptionThrowingAspect(Exception ex) {
this.ex = ex;
}
@Before("execution(* getAge())")
public void throwException() throws Exception {
void throwException() throws Exception {
throw ex;
}
}
public static class Echo {
static class Echo {
public Object echo(Object o) throws Exception {
Object echo(Object o) throws Exception {
if (o instanceof Exception) {
throw (Exception) o;
}
@@ -769,45 +769,62 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
public static class ExceptionHandling {
private static class InvocationTrackingAspect {
public int successCount;
List<String> invocations = new ArrayList<>();
public int failureCount;
public int afterCount;
@AfterReturning("execution(* echo(*))")
public void succeeded() {
++successCount;
@Pointcut("execution(* echo(*))")
void echo() {
}
@AfterThrowing("execution(* echo(*))")
public void failed() {
++failureCount;
@Around("echo()")
Object around(ProceedingJoinPoint joinPoint) throws Throwable {
invocations.add("around - start");
try {
return joinPoint.proceed();
}
finally {
invocations.add("around - end");
}
}
@After("execution(* echo(*))")
public void invoked() {
++afterCount;
@Before("echo()")
void before() {
invocations.add("before");
}
@AfterReturning("echo()")
void afterReturning() {
invocations.add("after returning");
}
@AfterThrowing("echo()")
void afterThrowing() {
invocations.add("after throwing");
}
@After("echo()")
void after() {
invocations.add("after");
}
}
@Aspect
public static class NoDeclarePrecedenceShouldFail {
static class NoDeclarePrecedenceShouldFail {
@Pointcut("execution(int *.getAge())")
public void getAge() {
void getAge() {
}
@Before("getAge()")
public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
throw new IllegalStateException();
}
@Around("getAge()")
public int preventExecution(ProceedingJoinPoint pjp) {
int preventExecution(ProceedingJoinPoint pjp) {
return 666;
}
}
@@ -815,19 +832,19 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
@DeclarePrecedence("test..*")
public static class DeclarePrecedenceShouldSucceed {
static class DeclarePrecedenceShouldSucceed {
@Pointcut("execution(int *.getAge())")
public void getAge() {
void getAge() {
}
@Before("getAge()")
public void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
void blowUpButDoesntMatterBecauseAroundAdviceWontLetThisBeInvoked() {
throw new IllegalStateException();
}
@Around("getAge()")
public int preventExecution(ProceedingJoinPoint pjp) {
int preventExecution(ProceedingJoinPoint pjp) {
return 666;
}
}
@@ -845,12 +862,12 @@ public abstract class AbstractAspectJAdvisorFactoryTests {
@Aspect
abstract class AbstractMakeModifiable {
public interface MutableModifiable extends Modifiable {
interface MutableModifiable extends Modifiable {
void markDirty();
}
public static class ModifiableImpl implements MutableModifiable {
static class ModifiableImpl implements MutableModifiable {
private boolean modified;
@@ -871,7 +888,7 @@ abstract class AbstractMakeModifiable {
}
@Before(value="execution(void set*(*)) && this(modifiable) && args(newValue)", argNames="modifiable,newValue")
public void recordModificationIfSetterArgumentDiffersFromOldValue(
void recordModificationIfSetterArgumentDiffersFromOldValue(
JoinPoint jp, MutableModifiable mixin, Object newValue) {
/*
@@ -933,7 +950,7 @@ class MakeITestBeanModifiable extends AbstractMakeModifiable {
@DeclareParents(value = "org.springframework.beans.testfixture.beans.ITestBean+",
defaultImpl=ModifiableImpl.class)
public static MutableModifiable mixin;
static MutableModifiable mixin;
}
@@ -948,7 +965,7 @@ class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable {
@DeclareParents(value = "(@org.springframework.aop.aspectj.annotation.Measured *)",
defaultImpl = DefaultLockable.class)
public static Lockable mixin;
static Lockable mixin;
}
@@ -960,10 +977,10 @@ class MakeAnnotatedTypeModifiable extends AbstractMakeModifiable {
class MakeLockable {
@DeclareParents(value = "org.springframework..*", defaultImpl = DefaultLockable.class)
public static Lockable mixin;
static Lockable mixin;
@Before(value="execution(void set*(*)) && this(mixin)", argNames="mixin")
public void checkNotLocked( Lockable mixin) {
void checkNotLocked( Lockable mixin) {
// Can also obtain the mixin (this) this way
//Lockable mixin = (Lockable) jp.getThis();
if (mixin.locked()) {
@@ -1032,11 +1049,11 @@ class NotLockable {
private int intValue;
public int getIntValue() {
int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
void setIntValue(int intValue) {
this.intValue = intValue;
}
@@ -1046,19 +1063,19 @@ class NotLockable {
@Aspect("perthis(execution(* *.getSpouse()))")
class PerThisAspect {
public int count;
int count;
// Just to check that this doesn't cause problems with introduction processing
@SuppressWarnings("unused")
private ITestBean fieldThatShouldBeIgnoredBySpringAtAspectJProcessing = new TestBean();
@Around("execution(int *.getAge())")
public int returnCountAsAge() {
int returnCountAsAge() {
return count++;
}
@Before("execution(void *.set*(int))")
public void countSetter() {
void countSetter() {
++count;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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 test.aop.PerTargetAspect;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcutTests;
import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionThrowingAspect;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.beans.testfixture.beans.TestBean;
@@ -44,7 +45,7 @@ public class AspectJPointcutAdvisorTests {
InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(
ajexp, TestBean.class.getMethod("getAge"), af,
new SingletonMetadataAwareAspectInstanceFactory(new AbstractAspectJAdvisorFactoryTests.ExceptionAspect(null), "someBean"),
new SingletonMetadataAwareAspectInstanceFactory(new ExceptionThrowingAspect(null), "someBean"),
1, "someBean");
assertThat(ajpa.getAspectMetadata().getPerClausePointcut()).isSameAs(Pointcut.TRUE);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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,7 +22,7 @@ import test.aop.PerTargetAspect;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionAspect;
import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionThrowingAspect;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -42,7 +42,7 @@ class AspectMetadataTests {
@Test
void singletonAspect() {
AspectMetadata am = new AspectMetadata(ExceptionAspect.class, "someBean");
AspectMetadata am = new AspectMetadata(ExceptionThrowingAspect.class, "someBean");
assertThat(am.isPerThisOrPerTarget()).isFalse();
assertThat(am.getPerClausePointcut()).isSameAs(Pointcut.TRUE);
assertThat(am.getAjType().getPerClause().getKind()).isEqualTo(PerClauseKind.SINGLETON);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,13 +17,14 @@
package org.springframework.aop.aspectj.annotation;
/**
* Tests for ReflectiveAtAspectJAdvisorFactory.
* Tests are inherited: we only set the test fixture here.
* Tests for {@link ReflectiveAspectJAdvisorFactory}.
*
* <p>Tests are inherited: we only set the test fixture here.
*
* @author Rod Johnson
* @since 2.0
*/
public class ReflectiveAspectJAdvisorFactoryTests extends AbstractAspectJAdvisorFactoryTests {
class ReflectiveAspectJAdvisorFactoryTests extends AbstractAspectJAdvisorFactoryTests {
@Override
protected AspectJAdvisorFactory getFixture() {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -183,7 +183,7 @@ public class ProxyFactoryTests {
}
@Test
public void testGetsAllInterfaces() throws Exception {
public void testGetsAllInterfaces() {
// Extend to get new interface
class TestBeanSubclass extends TestBean implements Comparable<Object> {
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,12 +83,12 @@ public class MethodMatchersTests {
MethodMatcher intersection = MethodMatchers.intersection(mm1, mm2);
assertThat(intersection.isRuntime()).as("Intersection is a dynamic matcher").isTrue();
assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class)).as("2Matched setAge method").isTrue();
assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Integer(5))).as("3Matched setAge method").isTrue();
assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, 5)).as("3Matched setAge method").isTrue();
// Knock out dynamic part
intersection = MethodMatchers.intersection(intersection, new TestDynamicMethodMatcherWhichDoesNotMatch());
assertThat(intersection.isRuntime()).as("Intersection is a dynamic matcher").isTrue();
assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class)).as("2Matched setAge method").isTrue();
assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Integer(5))).as("3 - not Matched setAge method").isFalse();
assertThat(intersection.matches(ITESTBEAN_SETAGE, TestBean.class, 5)).as("3 - not Matched setAge method").isFalse();
}
@Test
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -121,20 +121,20 @@ public class PointcutsTests {
@Test
public void testTrue() {
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class)).isTrue();
}
@Test
public void testMatches() {
assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class)).isFalse();
assertThat(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse();
assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse();
assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse();
assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse();
}
@@ -145,7 +145,7 @@ public class PointcutsTests {
@Test
public void testUnionOfSettersAndGetters() {
Pointcut union = Pointcuts.union(allClassGetterPointcut, allClassSetterPointcut);
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse();
}
@@ -153,7 +153,7 @@ public class PointcutsTests {
@Test
public void testUnionOfSpecificGetters() {
Pointcut union = Pointcuts.union(allClassGetAgePointcut, allClassGetNamePointcut);
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse();
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class)).isFalse();
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class)).isTrue();
@@ -161,13 +161,13 @@ public class PointcutsTests {
// Union with all setters
union = Pointcuts.union(union, allClassSetterPointcut);
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class)).isFalse();
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isTrue();
}
/**
@@ -176,16 +176,16 @@ public class PointcutsTests {
*/
@Test
public void testUnionOfAllSettersAndSubclassSetters() {
assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse();
assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, MyTestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse();
assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, MyTestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class)).isFalse();
Pointcut union = Pointcuts.union(myTestBeanSetterPointcut, allClassGetterPointcut);
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class)).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBean.class)).isTrue();
// Still doesn't match superclass setter
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, MyTestBean.class, new Integer(6))).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, MyTestBean.class, 6)).isTrue();
assertThat(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse();
}
/**
@@ -241,7 +241,7 @@ public class PointcutsTests {
@Test
public void testSimpleIntersection() {
Pointcut intersection = Pointcuts.intersection(allClassGetterPointcut, allClassSetterPointcut);
assertThat(Pointcuts.matches(intersection, TEST_BEAN_SET_AGE, TestBean.class, new Integer(6))).isFalse();
assertThat(Pointcuts.matches(intersection, TEST_BEAN_SET_AGE, TestBean.class, 6)).isFalse();
assertThat(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class)).isFalse();
assertThat(Pointcuts.matches(intersection, TEST_BEAN_ABSQUATULATE, TestBean.class)).isFalse();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@ import java.io.Serializable;
* @since 2.5.2
*/
public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends AbstractDependencyInjectionAspect {
/**
* Select initialization join point as object construction
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,22 +47,26 @@ import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
public aspect AnnotationBeanConfigurerAspect extends AbstractInterfaceDrivenDependencyInjectionAspect
implements BeanFactoryAware, InitializingBean, DisposableBean {
private BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport();
private final BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport();
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
this.beanConfigurerSupport.setBeanFactory(beanFactory);
}
@Override
public void afterPropertiesSet() {
this.beanConfigurerSupport.afterPropertiesSet();
}
@Override
public void configureBean(Object bean) {
this.beanConfigurerSupport.configureBean(bean);
}
@Override
public void destroy() {
this.beanConfigurerSupport.destroy();
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2020 the original author 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,8 @@ public abstract aspect AbstractTransactionAspect extends TransactionAspectSuppor
@Override
public void destroy() {
clearTransactionManagerCache(); // An aspect is basically a singleton
// An aspect is basically a singleton -> cleanup on destruction
clearTransactionManagerCache();
}
@SuppressAjWarnings("adviceDidNotMatch")
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2021 the original author 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,13 +22,18 @@ import org.springframework.contextsupport.testfixture.jcache.AbstractJCacheAnnot
/**
* @author Stephane Nicoll
* @author Sam Brannen
*/
public class JCacheAspectJNamespaceConfigTests extends AbstractJCacheAnnotationTests {
@Override
protected ApplicationContext getApplicationContext() {
return new GenericXmlApplicationContext(
"/org/springframework/cache/config/annotation-jcache-aspectj.xml");
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
// Disallow bean definition overriding to test https://github.com/spring-projects/spring-framework/pull/27499
context.setAllowBeanDefinitionOverriding(false);
context.load("/org/springframework/cache/config/annotation-jcache-aspectj.xml");
context.refresh();
return context;
}
}
+1
View File
@@ -25,6 +25,7 @@ sourceSets {
compileGroovy {
sourceCompatibility = 1.8
targetCompatibility = 1.8
options.compilerArgs += "-Werror"
}
// This module also builds Kotlin code and the compileKotlin task naturally depends on
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -115,7 +115,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
/**
* Create a new accessor for the given object.
* @param object object wrapped by this accessor
* @param object the object wrapped by this accessor
*/
protected AbstractNestablePropertyAccessor(Object object) {
registerDefaultEditors();
@@ -134,7 +134,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
/**
* Create a new accessor for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this accessor
* @param object the object wrapped by this accessor
* @param nestedPath the nested path of the object
* @param rootObject the root object at the top of the path
*/
@@ -146,7 +146,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
/**
* Create a new accessor for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this accessor
* @param object the object wrapped by this accessor
* @param nestedPath the nested path of the object
* @param parent the containing accessor (must not be {@code null})
*/
@@ -305,8 +305,10 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(tokens.actualName, newArray);
propValue = getPropertyValue(tokens.actualName);
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
String propName = tokens.canonicalName.substring(0, lastKeyIndex);
setPropertyValue(propName, newArray);
propValue = getPropertyValue(propName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
@@ -422,9 +424,12 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
}
return;
}
else {
throw createNotWritablePropertyException(tokens.canonicalName);
if (this.suppressNotWritablePropertyException) {
// Optimization for common ignoreUnknown=true scenario since the
// exception would be caught and swallowed higher up anyway...
return;
}
throw createNotWritablePropertyException(tokens.canonicalName);
}
Object oldValue = null;
@@ -737,7 +742,7 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
/**
* Create a new nested property accessor instance.
* Can be overridden in subclasses to create a PropertyAccessor subclass.
* @param object object wrapped by this PropertyAccessor
* @param object the object wrapped by this PropertyAccessor
* @param nestedPath the nested path of the object
* @return the nested PropertyAccessor instance
*/
@@ -806,7 +811,6 @@ public abstract class AbstractNestablePropertyAccessor extends AbstractPropertyA
* @param propertyPath property path, which may be nested
* @return a property accessor for the target bean
*/
@SuppressWarnings("unchecked") // avoid nested generic
protected AbstractNestablePropertyAccessor getPropertyAccessorForPropertyPath(String propertyPath) {
int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
// Handle nested properties recursively.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author 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 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
private boolean autoGrowNestedPaths = false;
boolean suppressNotWritablePropertyException = false;
@Override
public void setExtractOldValueForEditor(boolean extractOldValueForEditor) {
@@ -89,30 +91,41 @@ public abstract class AbstractPropertyAccessor extends TypeConverterSupport impl
List<PropertyAccessException> propertyAccessExceptions = null;
List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
for (PropertyValue pv : propertyValues) {
try {
// This method may throw any BeansException, which won't be caught
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
for (PropertyValue pv : propertyValues) {
// setPropertyValue may throw any BeansException, which won't be caught
// here, if there is a critical failure such as no matching field.
// We can attempt to deal only with less serious exceptions.
setPropertyValue(pv);
}
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
try {
setPropertyValue(pv);
}
// Otherwise, just ignore it and continue...
}
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
catch (NotWritablePropertyException ex) {
if (!ignoreUnknown) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
// Otherwise, just ignore it and continue...
}
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
catch (NullValueInNestedPathException ex) {
if (!ignoreInvalid) {
throw ex;
}
// Otherwise, just ignore it and continue...
}
propertyAccessExceptions.add(ex);
catch (PropertyAccessException ex) {
if (propertyAccessExceptions == null) {
propertyAccessExceptions = new ArrayList<>();
}
propertyAccessExceptions.add(ex);
}
}
}
finally {
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = false;
}
}
@@ -38,6 +38,7 @@ import kotlin.jvm.JvmClassMappingKt;
import kotlin.reflect.KFunction;
import kotlin.reflect.KParameter;
import kotlin.reflect.full.KClasses;
import kotlin.reflect.jvm.KCallablesJvm;
import kotlin.reflect.jvm.ReflectJvmMapping;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -82,7 +83,10 @@ public abstract class BeanUtils {
values.put(byte.class, (byte) 0);
values.put(short.class, (short) 0);
values.put(int.class, 0);
values.put(long.class, (long) 0);
values.put(long.class, 0L);
values.put(float.class, 0F);
values.put(double.class, 0D);
values.put(char.class, '\0');
DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values);
}
@@ -226,7 +230,6 @@ public abstract class BeanUtils {
* @since 5.0
* @see <a href="https://kotlinlang.org/docs/reference/classes.html#constructors">Kotlin docs</a>
*/
@SuppressWarnings("unchecked")
@Nullable
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
Assert.notNull(clazz, "Class must not be null");
@@ -441,8 +444,7 @@ public abstract class BeanUtils {
* @throws BeansException if PropertyDescriptor look fails
*/
public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {
CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
return cr.getPropertyDescriptors();
return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptors();
}
/**
@@ -453,11 +455,8 @@ public abstract class BeanUtils {
* @throws BeansException if PropertyDescriptor lookup fails
*/
@Nullable
public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName)
throws BeansException {
CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);
return cr.getPropertyDescriptor(propertyName);
public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) throws BeansException {
return CachedIntrospectionResults.forClass(clazz).getPropertyDescriptor(propertyName);
}
/**
@@ -510,6 +509,7 @@ public abstract class BeanUtils {
if (targetType == null || targetType.isArray() || unknownEditorTypes.contains(targetType)) {
return null;
}
ClassLoader cl = targetType.getClassLoader();
if (cl == null) {
try {
@@ -526,28 +526,34 @@ public abstract class BeanUtils {
return null;
}
}
String targetTypeName = targetType.getName();
String editorName = targetTypeName + "Editor";
try {
Class<?> editorClass = cl.loadClass(editorName);
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
if (logger.isInfoEnabled()) {
logger.info("Editor class [" + editorName +
"] does not implement [java.beans.PropertyEditor] interface");
if (editorClass != null) {
if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
if (logger.isInfoEnabled()) {
logger.info("Editor class [" + editorName +
"] does not implement [java.beans.PropertyEditor] interface");
}
unknownEditorTypes.add(targetType);
return null;
}
unknownEditorTypes.add(targetType);
return null;
return (PropertyEditor) instantiateClass(editorClass);
}
return (PropertyEditor) instantiateClass(editorClass);
// Misbehaving ClassLoader returned null instead of ClassNotFoundException
// - fall back to unknown editor type registration below
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("No property editor [" + editorName + "] found for type " +
targetTypeName + " according to 'Editor' suffix convention");
}
unknownEditorTypes.add(targetType);
return null;
// Ignore - fall back to unknown editor type registration below
}
if (logger.isTraceEnabled()) {
logger.trace("No property editor [" + editorName + "] found for type " +
targetTypeName + " according to 'Editor' suffix convention");
}
unknownEditorTypes.add(targetType);
return null;
}
/**
@@ -780,6 +786,11 @@ public abstract class BeanUtils {
if (kotlinConstructor == null) {
return ctor.newInstance(args);
}
if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers()))) {
KCallablesJvm.setAccessible(kotlinConstructor, true);
}
List<KParameter> parameters = kotlinConstructor.getParameters();
Map<KParameter, Object> argParameters = new HashMap<>(parameters.size());
Assert.isTrue(args.length <= parameters.size(),
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
/**
* Create a new BeanWrapperImpl for the given object.
* @param object object wrapped by this BeanWrapper
* @param object the object wrapped by this BeanWrapper
*/
public BeanWrapperImpl(Object object) {
super(object);
@@ -114,7 +114,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
/**
* Create a new BeanWrapperImpl for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this BeanWrapper
* @param object the object wrapped by this BeanWrapper
* @param nestedPath the nested path of the object
* @param rootObject the root object at the top of the path
*/
@@ -125,7 +125,7 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
/**
* Create a new BeanWrapperImpl for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this BeanWrapper
* @param object the object wrapped by this BeanWrapper
* @param nestedPath the nested path of the object
* @param parent the containing BeanWrapper (must not be {@code null})
*/
@@ -289,15 +289,15 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
@Override
@Nullable
public Object getValue() throws Exception {
final Method readMethod = this.pd.getReadMethod();
Method readMethod = this.pd.getReadMethod();
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(readMethod);
return null;
});
try {
return AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
readMethod.invoke(getWrappedInstance(), (Object[]) null), acc);
return AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
() -> readMethod.invoke(getWrappedInstance(), (Object[]) null), acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
@@ -310,8 +310,8 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
}
@Override
public void setValue(final @Nullable Object value) throws Exception {
final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
public void setValue(@Nullable Object value) throws Exception {
Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
this.pd.getWriteMethod());
if (System.getSecurityManager() != null) {
@@ -320,8 +320,8 @@ public class BeanWrapperImpl extends AbstractNestablePropertyAccessor implements
return null;
});
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
writeMethod.invoke(getWrappedInstance(), value), acc);
AccessController.doPrivileged((PrivilegedExceptionAction<Object>)
() -> writeMethod.invoke(getWrappedInstance(), value), acc);
}
catch (PrivilegedActionException ex) {
throw ex.getException();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@ import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.net.URL;
import java.security.ProtectionDomain;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -92,12 +94,14 @@ public final class CachedIntrospectionResults {
*/
public static final String IGNORE_BEANINFO_PROPERTY_NAME = "spring.beaninfo.ignore";
private static final PropertyDescriptor[] EMPTY_PROPERTY_DESCRIPTOR_ARRAY = {};
private static final boolean shouldIntrospectorIgnoreBeaninfoClasses =
SpringProperties.getFlag(IGNORE_BEANINFO_PROPERTY_NAME);
/** Stores the BeanInfoFactory instances. */
private static List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
private static final List<BeanInfoFactory> beanInfoFactories = SpringFactoriesLoader.loadFactories(
BeanInfoFactory.class, CachedIntrospectionResults.class.getClassLoader());
private static final Log logger = LogFactory.getLog(CachedIntrospectionResults.class);
@@ -253,7 +257,7 @@ public final class CachedIntrospectionResults {
private final BeanInfo beanInfo;
/** PropertyDescriptor objects keyed by property name String. */
private final Map<String, PropertyDescriptor> propertyDescriptorCache;
private final Map<String, PropertyDescriptor> propertyDescriptors;
/** TypeDescriptor objects keyed by PropertyDescriptor. */
private final ConcurrentMap<PropertyDescriptor, TypeDescriptor> typeDescriptorCache;
@@ -274,14 +278,22 @@ public final class CachedIntrospectionResults {
if (logger.isTraceEnabled()) {
logger.trace("Caching PropertyDescriptors for class [" + beanClass.getName() + "]");
}
this.propertyDescriptorCache = new LinkedHashMap<>();
this.propertyDescriptors = new LinkedHashMap<>();
// This call is slow so we do it once.
PropertyDescriptor[] pds = this.beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
if (Class.class == beanClass &&
("classLoader".equals(pd.getName()) || "protectionDomain".equals(pd.getName()))) {
// Ignore Class.getClassLoader() and getProtectionDomain() methods - nobody needs to bind to those
if (Class.class == beanClass && !("name".equals(pd.getName()) ||
(pd.getName().endsWith("Name") && String.class == pd.getPropertyType()))) {
// Only allow all name variants of Class properties
continue;
}
if (URL.class == beanClass && "content".equals(pd.getName())) {
// Only allow URL attribute introspection, not content resolution
continue;
}
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
// Ignore read-only properties such as ClassLoader - no need to bind to those
continue;
}
if (logger.isTraceEnabled()) {
@@ -291,7 +303,7 @@ public final class CachedIntrospectionResults {
"; editor [" + pd.getPropertyEditorClass().getName() + "]" : ""));
}
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptorCache.put(pd.getName(), pd);
this.propertyDescriptors.put(pd.getName(), pd);
}
// Explicitly check implemented interfaces for setter/getter methods as well,
@@ -313,13 +325,17 @@ public final class CachedIntrospectionResults {
for (Class<?> ifc : currClass.getInterfaces()) {
if (!ClassUtils.isJavaLanguageInterface(ifc)) {
for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {
PropertyDescriptor existingPd = this.propertyDescriptorCache.get(pd.getName());
PropertyDescriptor existingPd = this.propertyDescriptors.get(pd.getName());
if (existingPd == null ||
(existingPd.getReadMethod() == null && pd.getReadMethod() != null)) {
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
// against a declared read method, so we prefer read method descriptors here.
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
this.propertyDescriptorCache.put(pd.getName(), pd);
if (pd.getWriteMethod() == null && isInvalidReadOnlyPropertyType(pd.getPropertyType())) {
// Ignore read-only properties such as ClassLoader - no need to bind to those
continue;
}
this.propertyDescriptors.put(pd.getName(), pd);
}
}
introspectInterfaces(ifc, ifc);
@@ -327,6 +343,12 @@ public final class CachedIntrospectionResults {
}
}
private boolean isInvalidReadOnlyPropertyType(@Nullable Class<?> returnType) {
return (returnType != null && (AutoCloseable.class.isAssignableFrom(returnType) ||
ClassLoader.class.isAssignableFrom(returnType) ||
ProtectionDomain.class.isAssignableFrom(returnType)));
}
BeanInfo getBeanInfo() {
return this.beanInfo;
@@ -338,27 +360,19 @@ public final class CachedIntrospectionResults {
@Nullable
PropertyDescriptor getPropertyDescriptor(String name) {
PropertyDescriptor pd = this.propertyDescriptorCache.get(name);
PropertyDescriptor pd = this.propertyDescriptors.get(name);
if (pd == null && StringUtils.hasLength(name)) {
// Same lenient fallback checking as in Property...
pd = this.propertyDescriptorCache.get(StringUtils.uncapitalize(name));
pd = this.propertyDescriptors.get(StringUtils.uncapitalize(name));
if (pd == null) {
pd = this.propertyDescriptorCache.get(StringUtils.capitalize(name));
pd = this.propertyDescriptors.get(StringUtils.capitalize(name));
}
}
return (pd == null || pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
return pd;
}
PropertyDescriptor[] getPropertyDescriptors() {
PropertyDescriptor[] pds = new PropertyDescriptor[this.propertyDescriptorCache.size()];
int i = 0;
for (PropertyDescriptor pd : this.propertyDescriptorCache.values()) {
pds[i] = (pd instanceof GenericTypeAwarePropertyDescriptor ? pd :
buildGenericTypeAwarePropertyDescriptor(getBeanClass(), pd));
i++;
}
return pds;
return this.propertyDescriptors.values().toArray(EMPTY_PROPERTY_DESCRIPTOR_ARRAY);
}
private PropertyDescriptor buildGenericTypeAwarePropertyDescriptor(Class<?> beanClass, PropertyDescriptor pd) {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
/**
* Create a new DirectFieldAccessor for the given object.
* @param object object wrapped by this DirectFieldAccessor
* @param object the object wrapped by this DirectFieldAccessor
*/
public DirectFieldAccessor(Object object) {
super(object);
@@ -61,7 +61,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
/**
* Create a new DirectFieldAccessor for the given object,
* registering a nested path that the object is in.
* @param object object wrapped by this DirectFieldAccessor
* @param object the object wrapped by this DirectFieldAccessor
* @param nestedPath the nested path of the object
* @param parent the containing DirectFieldAccessor (must not be {@code null})
*/
@@ -92,8 +92,7 @@ public class DirectFieldAccessor extends AbstractNestablePropertyAccessor {
@Override
protected NotWritablePropertyException createNotWritablePropertyException(String propertyName) {
PropertyMatches matches = PropertyMatches.forField(propertyName, getRootClass());
throw new NotWritablePropertyException(
getRootClass(), getNestedPath() + propertyName,
throw new NotWritablePropertyException(getRootClass(), getNestedPath() + propertyName,
matches.buildErrorMessage(), matches.getPossibleMatches());
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,12 +60,13 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
@Nullable
private Class<?> propertyType;
@Nullable
private final Class<?> propertyEditorClass;
public GenericTypeAwarePropertyDescriptor(Class<?> beanClass, String propertyName,
@Nullable Method readMethod, @Nullable Method writeMethod, Class<?> propertyEditorClass)
throws IntrospectionException {
@Nullable Method readMethod, @Nullable Method writeMethod,
@Nullable Class<?> propertyEditorClass) throws IntrospectionException {
super(propertyName, null, null);
this.beanClass = beanClass;
@@ -137,7 +138,7 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
Set<Method> ambiguousCandidates = this.ambiguousWriteMethods;
if (ambiguousCandidates != null) {
this.ambiguousWriteMethods = null;
LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).warn("Invalid JavaBean property '" +
LogFactory.getLog(GenericTypeAwarePropertyDescriptor.class).debug("Non-unique JavaBean property '" +
getName() + "' being accessed! Ambiguous write methods found next to actually used [" +
this.writeMethod + "]: " + ambiguousCandidates);
}
@@ -156,6 +157,7 @@ final class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
}
@Override
@Nullable
public Class<?> getPropertyEditorClass() {
return this.propertyEditorClass;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,8 +23,9 @@ import org.springframework.lang.Nullable;
/**
* Common interface for classes that can access named properties
* (such as bean properties of an object or fields in an object)
* Serves as base interface for {@link BeanWrapper}.
* (such as bean properties of an object or fields in an object).
*
* <p>Serves as base interface for {@link BeanWrapper}.
*
* @author Juergen Hoeller
* @since 1.1
@@ -501,7 +501,7 @@ public class PropertyEditorRegistrySupport implements PropertyEditorRegistry {
if (endIndex != -1) {
String prefix = propertyPath.substring(0, startIndex);
String key = propertyPath.substring(startIndex, endIndex + 1);
String suffix = propertyPath.substring(endIndex + 1, propertyPath.length());
String suffix = propertyPath.substring(endIndex + 1);
// Strip the first key.
strippedPaths.add(nestedPath + prefix + suffix);
// Search for further keys to strip, with the first key stripped.
@@ -78,7 +78,7 @@ public interface PropertyValues extends Iterable<PropertyValue> {
/**
* Return the changes since the previous PropertyValues.
* Subclasses should also override {@code equals}.
* @param old old property values
* @param old the old property values
* @return the updated or new properties.
* Return empty PropertyValues if there are no changes.
* @see Object#equals
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,10 +41,10 @@ public class TypeMismatchException extends PropertyAccessException {
private String propertyName;
@Nullable
private transient Object value;
private final transient Object value;
@Nullable
private Class<?> requiredType;
private final Class<?> requiredType;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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,7 +22,8 @@ import org.springframework.lang.Nullable;
/**
* The root interface for accessing a Spring bean container.
* This is the basic client view of a bean container;
*
* <p>This is the basic client view of a bean container;
* further interfaces such as {@link ListableBeanFactory} and
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}
* are available for specific purposes.
@@ -130,7 +131,7 @@ public interface BeanFactory {
* Singleton or Prototype design pattern. Callers may retain references to
* returned objects in the case of Singleton beans.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
* @return an instance of the bean
* @throws NoSuchBeanDefinitionException if there is no bean with the specified name
@@ -145,7 +146,7 @@ public interface BeanFactory {
* required type. This means that ClassCastException can't be thrown on casting
* the result correctly, as can happen with {@link #getBean(String)}.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to retrieve
* @param requiredType type the bean must match; can be an interface or superclass
* @return an instance of the bean
@@ -258,7 +259,7 @@ public interface BeanFactory {
* to a scoped bean as well. Use the {@link #isPrototype} operation to explicitly
* check for independent instances.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
* @return whether this bean corresponds to a singleton instance
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
@@ -275,7 +276,7 @@ public interface BeanFactory {
* to a scoped bean as well. Use the {@link #isSingleton} operation to explicitly
* check for a shared singleton instance.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
* @return whether this bean will always deliver independent instances
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
@@ -290,7 +291,7 @@ public interface BeanFactory {
* More specifically, check whether a {@link #getBean} call for the given name
* would return an object that is assignable to the specified target type.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
* @param typeToMatch the type to match against (as a {@code ResolvableType})
* @return {@code true} if the bean type matches,
@@ -307,7 +308,7 @@ public interface BeanFactory {
* More specifically, check whether a {@link #getBean} call for the given name
* would return an object that is assignable to the specified target type.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
* @param typeToMatch the type to match against (as a {@code Class})
* @return {@code true} if the bean type matches,
@@ -326,7 +327,7 @@ public interface BeanFactory {
* as exposed by {@link FactoryBean#getObjectType()}. This may lead to the initialization
* of a previously uninitialized {@code FactoryBean} (see {@link #getType(String, boolean)}).
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
* @return the type of the bean, or {@code null} if not determinable
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
@@ -345,7 +346,7 @@ public interface BeanFactory {
* {@code allowFactoryBeanInit} flag, this may lead to the initialization of a previously
* uninitialized {@code FactoryBean} if no early type information is available.
* <p>Translates aliases back to the corresponding canonical bean name.
* Will ask the parent factory if the bean cannot be found in this factory instance.
* <p>Will ask the parent factory if the bean cannot be found in this factory instance.
* @param name the name of the bean to query
* @param allowFactoryBeanInit whether a {@code FactoryBean} may get initialized
* just for the purpose of determining its object type
@@ -360,7 +361,7 @@ public interface BeanFactory {
/**
* Return the aliases for the given bean name, if any.
* All of those aliases point to the same bean when used in a {@link #getBean} call.
* <p>All of those aliases point to the same bean when used in a {@link #getBean} call.
* <p>If the given name is an alias, the corresponding original bean name
* and other aliases (if any) will be returned, with the original bean name
* being the first element in the array.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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,10 +39,16 @@ import org.springframework.lang.Nullable;
*
* <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
* supposed to rely on annotation-driven injection or other reflective facilities.</b>
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in
* the bootstrap process, even ahead of any post-processor setup. If you need access
* {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
* bootstrap process, even ahead of any post-processor setup. If you need access to
* other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
*
* <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
* instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
* a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()}
* will <i>not</i> be called automatically. Instead, a FactoryBean should implement
* {@link DisposableBean} and delegate any such close call to the underlying object.
*
* <p>Finally, FactoryBean objects participate in the containing BeanFactory's
* synchronization of bean creation. There is usually no need for internal
* synchronization other than for purposes of lazy initialization within the
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author 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;
* They will ignore any singleton beans that have been registered by other means like
* {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}'s
* {@code registerSingleton} method, with the exception of
* {@code getBeanNamesOfType} and {@code getBeansOfType} which will check
* {@code getBeanNamesForType} and {@code getBeansOfType} which will check
* such manually registered singletons too. Of course, BeanFactory's {@code getBean}
* does allow transparent access to such special beans as well. However, in typical
* scenarios, all beans will be defined by external bean definitions anyway, so most
@@ -36,9 +36,11 @@ import java.lang.annotation.Target;
* annotation, they will be considered as candidates for autowiring. The constructor
* with the greatest number of dependencies that can be satisfied by matching beans
* in the Spring container will be chosen. If none of the candidates can be satisfied,
* then a primary/default constructor (if present) will be used. If a class only
* declares a single constructor to begin with, it will always be used, even if not
* annotated. An annotated constructor does not have to be public.
* then a primary/default constructor (if present) will be used. Similarly, if a
* class declares multiple constructors but none of them is annotated with
* {@code @Autowired}, then a primary/default constructor (if present) will be used.
* If a class only declares a single constructor to begin with, it will always be used,
* even if not annotated. An annotated constructor does not have to be public.
*
* <h3>Autowired Fields</h3>
* <p>Fields are injected right after construction of a bean, before any config methods
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -459,7 +459,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
return metadata;
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
@@ -613,7 +613,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private final boolean required;
private volatile boolean cached = false;
private volatile boolean cached;
@Nullable
private volatile Object cachedFieldValue;
@@ -628,46 +628,58 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
try {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
Object cachedFieldValue = null;
if (value != null || this.required) {
cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
this.cachedFieldValue = cachedFieldValue;
this.cached = true;
}
}
return value;
}
}
@@ -678,7 +690,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
private final boolean required;
private volatile boolean cached = false;
private volatile boolean cached;
@Nullable
private volatile Object[] cachedMethodArguments;
@@ -696,58 +708,16 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
// Shortcut for avoiding synchronization...
arguments = resolveCachedArguments(beanName);
try {
arguments = resolveCachedArguments(beanName);
}
catch (NoSuchBeanDefinitionException ex) {
// Unexpected removal of target bean for cached argument -> re-resolve
arguments = resolveMethodArguments(method, bean, beanName);
}
}
else {
int argumentCount = method.getParameterCount();
arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
}
else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
arguments = resolveMethodArguments(method, bean, beanName);
}
if (arguments != null) {
try {
@@ -772,6 +742,59 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
return arguments;
}
@Nullable
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
}
else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
return arguments;
}
}
@@ -26,9 +26,6 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -69,8 +66,6 @@ public class InjectionMetadata {
};
private static final Log logger = LogFactory.getLog(InjectionMetadata.class);
private final Class<?> targetClass;
private final Collection<InjectedElement> injectedElements;
@@ -110,9 +105,6 @@ public class InjectionMetadata {
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
checkedElements.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
this.checkedElements = checkedElements;
@@ -124,9 +116,6 @@ public class InjectionMetadata {
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
element.inject(target, beanName, pvs);
}
}
@@ -152,12 +141,12 @@ public class InjectionMetadata {
* Return an {@code InjectionMetadata} instance, possibly for empty elements.
* @param elements the elements to inject (possibly empty)
* @param clazz the target class
* @return a new {@link #InjectionMetadata(Class, Collection)} instance,
* or {@link #EMPTY} in case of no elements
* @return a new {@link #InjectionMetadata(Class, Collection)} instance
* @since 5.2
*/
public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) {
return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
return (elements.isEmpty() ? new InjectionMetadata(clazz, Collections.emptyList()) :
new InjectionMetadata(clazz, elements));
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,12 +41,11 @@ import java.lang.annotation.Target;
* regular constructors: i.e. lookup methods cannot get replaced on beans returned
* from factory methods where we cannot dynamically provide a subclass for them.
*
* <p><b>Concrete limitations in typical Spring configuration scenarios:</b>
* When used with component scanning or any other mechanism that filters out abstract
* beans, provide stub implementations of your lookup methods to be able to declare
* them as concrete classes. And please remember that lookup methods won't work on
* beans returned from {@code @Bean} methods in configuration classes; you'll have
* to resort to {@code @Inject Provider<TargetBean>} or the like instead.
* <p><b>Recommendations for typical Spring configuration scenarios:</b>
* When a concrete class may be needed in certain scenarios, consider providing stub
* implementations of your lookup methods. And please remember that lookup methods
* won't work on beans returned from {@code @Bean} methods in configuration classes;
* you'll have to resort to {@code @Inject Provider<TargetBean>} or the like instead.
*
* @author Juergen Hoeller
* @since 4.1

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