Compare commits

...

177 Commits

Author SHA1 Message Date
Spring Buildmaster f9b6e94e00 Release v5.3.9 2021-07-14 06:36:18 +00:00
Rossen Stoyanchev bb816c123c Use MessageSource in HandlerMethod for error reason
Closes gh-27156
2021-07-13 19:38:58 +01:00
Juergen Hoeller 33f3aa9b8a Upgrade to AspectJ 1.9.7 and EclipseLink 2.7.9 2021-07-13 18:29:34 +02:00
Rossen Stoyanchev e1f51cbce7 Check both https and wss in forwarded header checks
Closes gh-27097
2021-07-13 16:32:12 +01:00
Stephane Nicoll 6ec7cffc93 Upgrade to Kotlin 1.5.21
Closes gh-27110
2021-07-13 14:55:25 +02:00
Stephane Nicoll 4bc6f40ce8 Upgrade to Reactor 2020.0.9
Closes gh-27158
2021-07-13 14:29:59 +02:00
Arjen Poutsma bf2790498b Document ResourceBundle limitations
This commit adds a note to the documentation saying that ResourceBundle
does not support multiple bundles with the same base name.

Closes gh-27038
2021-07-13 13:45:03 +02:00
Rossen Stoyanchev 95d7f883ae Deprecate LastModified
See gh-27075
2021-07-13 12:11:20 +01:00
Rossen Stoyanchev 25131ebf6f Resource handler initialized only once
Closes gh-27153
2021-07-13 11:44:06 +01:00
Rossen Stoyanchev 0267b00a65 Minor update to Javadoc for HandlerInterceptor#postHandle
Closes gh-27122
2021-07-13 08:44:54 +01:00
Stephane Nicoll c6e644e5c3 Polish "Downcast to InetSocketAddress for Jetty 10"
This commit uses the target type where getRemoteAddress and
getLocalAddress are defined.

See gh-27120
2021-07-13 09:38:37 +02:00
Juergen Hoeller 62e916534f Introduce remaining policy setters from ScheduledThreadPoolExecutor
Closes gh-26719
2021-07-13 09:27:48 +02:00
Juergen Hoeller e1c0f3b067 CommonsMultipartResolver supports configurable HTTP methods
Closes gh-27161
2021-07-12 23:19:08 +02:00
Juergen Hoeller 1ff8da3635 StandardServletMultipartResolver provides strict Servlet compliance option
Closes gh-26826
2021-07-12 23:18:54 +02:00
Juergen Hoeller ed27ea7aa0 Restrict fallback multipart binding to POST requests with multipart/form-data
Closes gh-26999
See gh-26826
2021-07-12 17:55:49 +02:00
Juergen Hoeller 128689e79b Use entrySet iterator in getBodyFromServletRequestParameters
Closes gh-27081
2021-07-12 17:43:19 +02:00
Juergen Hoeller 475396b516 Exclude sealed interfaces from auto-proxying (for JDK 17 compatibility)
Closes gh-27027
2021-07-12 17:42:15 +02:00
Sviatoslav Hryb f3f0bd22c5 Fix content negotiation description 2021-07-12 15:23:35 +01:00
Rossen Stoyanchev 6d01d49b76 Downcast to InetSocketAddress for Jetty 10
Closes gh-27120
2021-07-12 15:04:14 +01:00
Stephane Nicoll a90ed957be Support ResolvableType in BeanDefinitionBuilder
Closes gh-27160
2021-07-12 14:07:25 +02:00
Stephane Nicoll 171b283e49 Start building against Reactor 2020.0.9 snapshots
See gh-27158
2021-07-12 09:36:50 +02:00
Stephane Nicoll 71202d62ed Upgrade to Kotlin Coroutines 1.5.1
Closes gh-27157
2021-07-12 09:11:44 +02:00
Stephane Nicoll ded9c4eb50 Merge pull request #27155 from izeye
* pr/27155:
  Add Javadoc since to BeanDefinitionBuilder.setSynthetic()

Closes gh-27155
2021-07-12 08:22:21 +02:00
Johnny Lim 925edf28fc Add Javadoc since to BeanDefinitionBuilder.setSynthetic()
See gh-27155
2021-07-12 08:22:09 +02:00
Stephane Nicoll 75d4465908 Merge pull request #27151 from HubertWo
* pr/27151:
  Fix link to Javadoc API
  Fix link to Javadoc API

Closes gh-27151
2021-07-11 09:10:17 +02:00
Stephane Nicoll 98685e8be7 Fix link to Javadoc API
See gh-27151
2021-07-11 09:09:46 +02:00
Hubert Wo e719bc2cda Fix link to Javadoc API
See gh-27151
2021-07-11 09:05:20 +02:00
Rossen Stoyanchev f9167c3df5 Improve Javadoc of ContentCachingRequestWrapper
Closes gh-27068
2021-07-09 20:34:22 +01:00
Rossen Stoyanchev fbf4724d78 Replace Jetty 9 only constant with explicit value
Closes gh-27121
2021-07-09 20:16:58 +01:00
Rossen Stoyanchev 39442143b7 Fix and improve docs on {*var} pattern
Closes gh-27132
2021-07-09 20:09:06 +01:00
Juergen Hoeller d3b1c4f62b Code alignment between ThreadPoolTaskExecutor and ThreadPoolTaskScheduler
See gh-26700
2021-07-09 15:19:25 +02:00
Filip Hrisafov 531174258c Apply dynamic changes in ThreadPoolTaskExecutor before setting local value
If the ThreadPoolTaskExecutor is dynamically changed with an invalid value
the state of the ThreadPoolTaskExecutor does no longer correctly represent
the state of the underlying ThreadPoolExecutor
2021-07-09 15:10:55 +02:00
diguage 564c6f7f86 improve the performance of iteration 2021-07-09 15:10:18 +02:00
Juergen Hoeller a07c7865a5 Lazy initialization of transaction UUID (with deprecated getter methods)
Includes removal of trace logging for individual synchronization steps.

Closes gh-26955
2021-07-09 15:07:30 +02:00
Juergen Hoeller 8680fdb8bc Polishing 2021-07-09 13:26:46 +02:00
Juergen Hoeller 4fe3ca1b82 DataClassRowMapper suppresses setter method calls for constructor-bound properties
Closes gh-26569
2021-07-09 13:26:39 +02:00
Juergen Hoeller c45c46dad7 Make proxyTargetClass=true with introduction advice work for JDK proxy targets
Closes gh-27044
2021-07-09 13:23:04 +02:00
Juergen Hoeller 74f91339e2 BeanCreationException message includes declaring class of constructor/factory method
Closes gh-27139
2021-07-09 13:22:50 +02:00
Juergen Hoeller acb2aec3dd Compatibility with HtmlUnit 2.51
Includes upgrade to Tomcat 9.0.50, Jetty 9.4.43, Jackson 2.12.4.

Closes gh-27147
2021-07-09 13:22:34 +02:00
Arjen Poutsma 297880d93e Reinstate abortOnCancel in JettyClientHttpRequest
This commit reinstates abortOnCancel in the ReactiveRequest builder,
which allows a cancel signal to abort the request.

See gh-26287 and gh-27112
2021-07-09 10:58:58 +02:00
Arjen Poutsma 9cbb5af622 Support request/response wrappers in JettyHttpHandlerAdapter
This commit makes JettyServerHttpRequest aware of
HttpServletRequestWrapper, and JettyServerHttpResponse aware of
HttpServletResponseWrapper.

Closes gh-27146
2021-07-08 16:39:35 +02:00
Stephane Nicoll fed1a426b6 Improve BeanDefinitionBuilder to handle the synthetic flag
Closes gh-27141
2021-07-07 16:13:19 +02:00
Stephane Nicoll cf78895ba0 Polish 2021-07-07 16:11:48 +02:00
Arjen Poutsma b9d65eef61 Dropping accidentally inserted copyright notice 2021-07-07 13:54:07 +02:00
Arjen Poutsma 8d747298de Fixing the build 2021-07-07 13:49:10 +02:00
Arjen Poutsma 76b1c0f1fc Various bug fixes in CronExpression
This commit makes various bug fixes in CronExpression and related files.

Closes gh-27136
2021-07-07 10:56:07 +02:00
Arjen Poutsma 94f56a2684 Improve Jetty 10 check on client-side
Before this commit, JettyClientHttpResponse checked for the presence of
a server-side class to determine whether it is running on Jetty 10.
Unfortunately, that class is not necessarily present when just using the
Jetty client.

This commit improves the Jetty 10 check, so that it also works when
the Jetty client is used without the server.

Closes gh-27136
2021-07-06 11:04:06 +02:00
Arjen Poutsma cb251347c3 Do not use internal API in JettyClientHttpConnector
This commit makes sure that we no longer use the internal API in the
Jetty support for the WebClient. With this change, we are able to
support both Jetty 9, 10, and 11.

Closes gh-27112
2021-07-06 11:04:06 +02:00
Stephane Nicoll 048954dc1d Merge pull request #27102 from diguage
* pr/27102:
  Update copyright year of changed file
  Simplify Comparator using method references

Closes gh-27102
2021-07-02 08:12:29 +02:00
Stephane Nicoll 403e1f2505 Update copyright year of changed file
See gh-27102
2021-07-02 08:11:41 +02:00
diguage f39c6d36c7 Simplify Comparator using method references
See gh-27102
2021-07-02 08:10:22 +02:00
Stephane Nicoll 83bcd409fc Merge pull request #27101 from diguage
* pr/27101:
  Update copyright year of changed file
  Delete unnecessary variable

Closes gh-27101
2021-07-02 08:09:37 +02:00
Stephane Nicoll 411745f4cb Update copyright year of changed file
See gh-27101
2021-07-02 08:09:07 +02:00
diguage 01df63b9cd Delete unnecessary variable
See gh-27101
2021-07-02 08:07:49 +02:00
Stephane Nicoll bde622880d Merge pull request #27113 from devorio
* pr/27113:
  Fix typo in core-beans.adoc

Closes gh-27113
2021-06-30 20:28:52 +02:00
devorio 6427a4b5c0 Fix typo in core-beans.adoc
See gh-27113
2021-06-30 20:27:55 +02:00
Sébastien Deleuze 66848cfd59 Revert "Upgrade to Kotlin 1.5.20"
This reverts commit d6df4a6577 because running
gradle generatePomFileForMavenJavaPublication throws a
kotlin.KotlinNullPointerException error with Kotlin 1.5.20.
2021-06-30 11:40:44 +02:00
Sébastien Deleuze 4863b5d4a8 Revert Mockito to 3.11.0
Revert Mockito upgrade done in 5d919dc094 because
Byte Buddy transitive upgrade from 1.11.1 to 1.11.3 seems to break Mockk tests
with java.security.AccessControlException related errors, so probably
better to wait Mockito using Byte buddy 1.11.5+ which seems to refine
this area, see https://github.com/raphw/byte-buddy/releases/tag/byte-buddy-1.11.5.
2021-06-30 11:05:31 +02:00
Sébastien Deleuze d6df4a6577 Upgrade to Kotlin 1.5.20
Closes gh-27110
2021-06-30 11:05:31 +02:00
Sébastien Deleuze dee0108e79 Upgrade to Mockk 1.11.0
Closes gh-27109
2021-06-30 11:05:31 +02:00
Sam Brannen 3ccbf1edeb Increase fudge factor in StopWatchTests 2021-06-30 10:43:52 +02:00
Stephane Nicoll 7f6f184acb Merge pull request #27105 from takumi34
* pr/27105:
  Update copyright year of changed file
  Fix typo in BeanDefinitionDsl.kt

Closes gh-27105
2021-06-29 19:28:16 +02:00
Stephane Nicoll b0f724a597 Update copyright year of changed file
See gh-27105
2021-06-29 19:27:57 +02:00
takumi34 9add04f800 Fix typo in BeanDefinitionDsl.kt
See gh-27105
2021-06-29 19:27:29 +02:00
Juergen Hoeller 5d919dc094 Upgrade to Tomcat 9.0.48, Jetty 9.4.42, Jetty Reactive HttpClient 1.1.9, JRuby 9.2.19, Protobuf 3.17.3, SnakeYAML 1.29, WebJars Locator 0.47, AssertJ 3.20.2, Mockito 3.11.2, Checkstyle 8.44 2021-06-28 14:25:55 +02:00
Sam Brannen a2ef6badc4 Use StringBuilder.append(char) where possible
To slightly improve performance, this commit switches to
StringBuilder.append(char) instead of StringBuilder.append(String)
whenever we append a single character to a StringBuilder.

Closes gh-27098
2021-06-25 10:44:28 +02:00
Sam Brannen ddbb7c1b5b Avoid use of Supplier in MergedAnnotationReadingVisitor.get 2021-06-24 16:41:28 +02:00
Sam Brannen 2bc7a3aa0a Implement equals, hashCode, & toString in BeanMethod and *Metadata types
Prior to this commit, ConfigurationClass implemented equals(),
hashCode(), and toString(), but BeanMethod did not.

This commit introduces equals(), hashCode(), and toString()
implementations in BeanMethod for consistency with ConfigurationClass
to make it possible to use BeanMethod instances to index additional
metadata as well.

In order to properly implement equals() in BeanMethod, the method
argument types are required, but these are not directly available in
BeanMethod. However, they are available via ASM when processing @Bean
methods. This commit therefore implements equals(), hashCode(), and
toString() in SimpleMethodMetadata which BeanMethod delegates to.

For completeness, this commit also implements equals(), hashCode(), and
toString() in StandardClassMetadata, StandardMethodMetadata, and
SimpleAnnotationMetadata.

Closes gh-27076
2021-06-24 16:41:28 +02:00
Sam Brannen 882004fc9b 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:41:28 +02:00
Sam Brannen 1bc236785c Polishing 2021-06-24 15:47:24 +02:00
Rossen Stoyanchev 300fed97c1 Upgrade to Reactor 2020.0.8 2021-06-23 15:34:24 +01:00
Arjen Poutsma 4f770ca860 Synchronoss should create temp directory lazily
The SynchronossPartHttpMessageReader should only create temp directory
when needed, not at startup.

Closes gh-27092
2021-06-23 15:59:46 +02:00
Sam Brannen d469f6215d Polishing 2021-06-22 19:54:05 +02:00
Sam Brannen 3214786757 Define global Asciidoc attributes once
This commit defines the doc-root and api-spring-framework attributes
once in docs.gradle instead of duplicating them in each *.adoc file.

This commit also introduces a new docs-spring-framework global
attribute.
2021-06-22 18:39:33 +02:00
Juergen Hoeller f69152c14e Add javadoc reference to MultipartFile.getResource()
See gh-27089
2021-06-22 15:27:19 +02:00
Juergen Hoeller 4bb88f3b1d Remove logging dependency in BeanUtils
Closes gh-27070
2021-06-22 15:26:48 +02:00
Juergen Hoeller edf0343cfe Upgrade to ASM master (including early support for Java 18 bytecode)
Closes gh-27069
2021-06-22 15:26:35 +02:00
Rossen Stoyanchev eb964542b4 Add doc-root to index.adoc
See gh-27015
2021-06-21 18:09:53 +01:00
Sam Brannen 4e8828dc10 Suppress warnings in ServletAnnotationControllerHandlerMethodTests 2021-06-21 18:55:52 +02:00
Sam Brannen a8102e6a41 Delete unused code in ConfigurationMethod 2021-06-21 18:31:43 +02:00
Sam Brannen 782d7169e4 Polish Javadoc for MethodMetadata 2021-06-21 18:04:37 +02:00
Sam Brannen 71995a9087 Introduce custom header for HTML5 ref docs
This commit disables the automatic header generation from Asciidoc's
default template and replaces it with a custom header that omits the
"Version" label before the revision number. The revision number is also
displayed in a simple span tag in order to reduce the amount of
vertical space taken by the header.
2021-06-21 17:52:18 +02:00
Rossen Stoyanchev f9bcb99040 Minor layout refactoring of index asciidoc page
Closes gh-27015
2021-06-21 16:19:17 +01:00
Jay Bryant 791134c53c Link the HTML to the PDF docs and vice-versa
See gh-27015
2021-06-21 16:19:08 +01:00
Sam Brannen df588e030f Avoid duplicated documentation of validation annotations
See gh-27042, gh-27043, gh-27050
2021-06-15 17:30:41 +02:00
Sam Brannen b677206159 Polish Javadoc 2021-06-15 17:22:11 +02:00
Sviatoslav Hryb e04ca3d671 Improve RequestPartMethodArgumentResolver Javadoc
Closes gh-27043
2021-06-15 17:06:53 +02:00
Sviatoslav Hryb 2fc47d8752 Improve RequestResponseBodyMethodProcessor Javadoc
Closes gh-27042
2021-06-15 17:04:18 +02:00
Sam Brannen 3676084472 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:16:20 +02:00
Sam Brannen bcb0580492 Polish DefaultPathContainerTests 2021-06-15 13:35:45 +02:00
duan847 3c8074b669 Fix assertion in XmlBeanFactoryTests
Closes gh-27058
2021-06-14 18:49:55 +02:00
Vasiliy Kudriavtsev 4a13928a27 Avoid creating unnessary wrapper for empty map 2021-06-11 16:36:04 +01:00
Rossen Stoyanchev 20d9a1e844 Upgrade to RSocket 1.1.1 2021-06-09 11:01:53 +01:00
Spring Buildmaster 8b1302bbe2 Next development version (v5.3.9-SNAPSHOT) 2021-06-09 07:50:04 +00:00
Brian Clozel c7c35aff42 Fix missing attribute in reference documentation
This commit adds the missing `spring-framework-main-code` asciidoctor
attribute in the reference documentation.

Fixes gh-27041
2021-06-09 09:21:28 +02:00
Sam Brannen 000b6a7e95 Polish @ResponseStatus javadoc and StatusAssertionTests 2021-06-08 18:55:05 +02:00
Sam Brannen f3db6b996d Polish contribution
See gh-27031
2021-06-08 18:55:05 +02:00
Rossen Stoyanchev a42540e64a Multipart writer detects custom Jackson encoder
Closes gh-27017
2021-06-08 17:41:04 +01:00
Rossen Stoyanchev cc2b980e5c Update MockMvc default for suffixPattern matching
Closes gh-27030
2021-06-08 17:41:04 +01:00
Sviatoslav Hryb aa2bfd4b62 Document that class-level @ResponseStatus is inherited by @ExceptionHandler methods
Closes gh-27031
2021-06-08 18:39:18 +02:00
Sam Brannen 29fa9c1728 Polish contribution
See gh-27034
2021-06-08 17:52:07 +02:00
Beca-se 39660710f6 Cross-ref additional *Aware APIs in BeanFactory Javadoc
Closes gh-27034
2021-06-08 17:47:47 +02:00
Brian Clozel e35fe33b72 Revisit fix for gh-26905 in UriComponentsBuilder
This commit revisits the recently updated `PORT_PATTERN` in
`UriComponentsBuilder`. The fix introduced in gh-26905 fails with
ambiguous URL patterns, especially when the port and path parts of the
pattern are hard to differentiate, for example
"https://localhost:{port}{path}".

This commit reinstates the previous behavior without undoing the actual
fix. The only limitation introduced here is the fact that only a single
pattern variable is allowed for the port pattern part.

Fixes gh-27039
2021-06-08 15:26:13 +02:00
Juergen Hoeller 23f396a231 Nullability refinements 2021-06-08 14:23:06 +02:00
izeye 090e394fb5 Clean up @SuppressWarnings("ConstantConditions") 2021-06-08 13:47:00 +02:00
Sviatoslav Hryb 708e61a7ef Fix WebMvcConfigurationSupport javadoc 2021-06-08 12:50:22 +02:00
Gabriel e24b2e6b5d Add awaitExchangeOrNull extension function to reactive webclient
Closes gh-26778
2021-06-08 12:06:53 +02:00
Sébastien Deleuze aff0d8efe7 Upgrade to Kotlin Serialization 1.2.1 2021-06-08 11:44:03 +02:00
Sébastien Deleuze e3e4e49319 Upgrade to Kotlin 1.5.10
Closes gh-27035
2021-06-08 11:44:03 +02:00
Sébastien Deleuze 5420d7113b Polish Kotlin reference documentation 2021-06-08 11:44:03 +02:00
Sébastien Deleuze 6251222a23 Remove jackson-module-kotlin warning
Closes gh-26962
2021-06-08 11:44:03 +02:00
Brian Clozel 05eca05671 Close resources in HttpComponents client connector
Prior to this commit, the `HttpComponentsClientHttpConnector`
implementation could accept or create a default `HttpClient` instance
but not expose it as part of its API. This effectively prevents
applications from properly closing the associated resources when
disposing of the connector.

This commit implements the `Closeable` interface on the connector to
allow this use case.

Closes gh-27032
2021-06-08 11:22:30 +02:00
izeye 3fa4e4168d Remove redundant Collections.unmodifiableList() 2021-06-08 10:39:23 +02:00
Sam Brannen f0f450a18d Polishing 2021-06-07 13:24:46 +02:00
Juergen Hoeller f854803e18 Upgrade to Hibernate ORM 5.4.32, RxJava 3.0.13, Aalto 1.3, Gson 2.8.7, Protobuf 3.17.2, XStream 1.4.17, ActiveMQ 5.16.2, HSQLDB 2.5.2, JRuby 9.2.17, Mockito 3.11, HtmlUnit 2.50, Checkstyle 8.43 2021-06-07 12:28:38 +02:00
Juergen Hoeller d29d4d45aa Upgrade to ASM master
Closes gh-27023
2021-06-07 12:28:17 +02:00
Sam Brannen 432fdad7d0 Polish contribution
See gh-26982
2021-06-04 15:32:29 +02:00
nhavuong 345d8186d4 Add more test cases for SimpleAliasRegistry
Closes gh-26982
2021-06-04 15:18:46 +02:00
Sam Brannen ad63a534cb Polish @CookieValue Javadoc 2021-06-04 15:14:42 +02:00
Сергей Цыпанов c9d341e9c0 Simplify String construction in StringUtils.changeFirstCharacterCase()
Closes gh-27012
2021-06-04 11:49:59 +02:00
Angel Aguilera 950b183715 Adjust expected IdentityHashMap sizes in ClassUtils
Proposed change aimed to keep coherence between variable declaration 
and static initialization code, which stores 9 values, not 8, in these
two maps.

Closes gh-27016
2021-06-04 10:48:44 +02:00
Rossen Stoyanchev 821ecb4cfd Update Javadoc for CookieValue
See gh-26989
2021-06-02 17:28:28 +01:00
Rossen Stoyanchev 1c17305d7b Check for null in allowedOrigin list
Closes gh-26987
2021-06-02 17:14:28 +01:00
jbotuck 491d1c4c78 issue-26994 add missing ) to kotlin example 2021-06-02 12:51:37 +01:00
Brian Clozel 7dbbf364f7 Make FlightRecorderApplicationStartup thread safe
Prior to this commit, in some cases application context startup steps
could be created concurrently, which could cause issues with the current
implementation tracking the parent/child relationship between steps.

This commit ensures that the flight recorder implementation is using
thread safe collection implementations for that.

Fixes gh-26941
2021-06-01 15:11:23 +02:00
Brian Clozel 5204d736f3 Return static DefaultApplicationStartup step
This commit ensures that `DefaultApplicationStartup` returns a static
step for each call to avoid allocations.

Closes gh-26939
2021-06-01 15:06:19 +02:00
Sam Brannen e0690335fc Polish Javadoc in spring-context-indexer 2021-05-31 16:24:09 +02:00
Arjen Poutsma 5cbbbed377 Use given name in MultipartBodyBuilder::part
Make sure that we use the parameter name in MultipartBodyBuilder::part
when adding a Part, instead of using the name specified in the
'Content-Disposition' header that might have been in the part's headers.

Closes gh-27007
2021-05-31 15:17:12 +02:00
Arjen Poutsma 6f2fe5ddcb (Re)introduce CronExpression::isValidExpression
This commit introduces CronExpression::isValidExpression, which was also
present on the deprecated CronSequenceGenerator.

Closes: gh-26996
2021-05-31 14:28:55 +02:00
Sam Brannen da9ee06e05 Improve @Transactional docs regarding method visibility
Closes gh-27003
2021-05-30 17:10:01 +02:00
Sviatoslav Hryb 4c28266eb6 Fix @Transactional docs regarding method visibility
Closes gh-27001
2021-05-30 13:48:31 +02:00
Juergen Hoeller b3dcb64ff1 Generic bean type resolution for lookup methods
Closes gh-26998
2021-05-28 17:23:52 +02:00
Juergen Hoeller b18f8771c8 Upgrade to R2DBC Arabba-SR10, Netty 4.1.65, Undertow 2.2.8, Jetty 9.4.41, Jetty Reactive HttpClient 1.1.8, Apache HttpClient 5.1 2021-05-28 14:31:15 +02:00
Stephane Nicoll 93244e9f9d Merge pull request #26980 from hunjipo
* pr/26980:
  Fix typo in code example

Closes gh-26980
2021-05-27 08:43:41 +02:00
hunjipo f45a852aca Fix typo in code example
See gh-26980
2021-05-27 08:37:44 +02:00
Arjen Poutsma 4203e90655 Fix CronExpression roll-forward issue
This commit makes sure that BitsCronField rolls the date forward in
cases where we cannot find a next bit to elapse to.

Closes: gh-26964
2021-05-26 16:46:15 +02:00
Sam Brannen 1e2e114e3c Polish contribution
See gh-26871
2021-05-26 14:46:32 +02:00
Michael Edwards 0e73213144 Add ApplicationEvent constructor for specifying timestamp
Closes gh-26871
2021-05-26 14:32:41 +02:00
Sam Brannen 1e1045ba42 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:21:08 +02:00
Rossen Stoyanchev 8d17bcea5b Validate top-level SockJS URL
Closes gh-26933
2021-05-26 11:26:02 +01:00
Stephane Nicoll 597b31b1fc Merge pull request #26973 from dregimbal
* pr/26973:
  Update copyright year of changed file
  Fix typo

Closes gh-26973
2021-05-26 08:50:38 +02:00
Stephane Nicoll 4049951c03 Update copyright year of changed file
See gh-26973
2021-05-26 08:50:15 +02:00
Dillon Regimbal 89441ea006 Fix typo
See gh-26973
2021-05-26 08:49:48 +02:00
Rossen Stoyanchev de1ba79c55 Switch to non-blocking thread after WebSession creation
See gh-26958
2021-05-24 16:27:56 +01:00
Sam Brannen ffbc537835 Polish ConcurrentBeanWrapperTests 2021-05-23 18:50:50 +02:00
Elvys Soares 9295bcc4a4 Refactor ConcurrentBeanWrapperTests to use @RepeatedTest
Closes gh-26968
2021-05-23 18:40:36 +02:00
Sam Brannen 746b1b2fe1 Polishing 2021-05-23 18:27:31 +02:00
izeye ab2c78a9d5 Fix broken Javadoc tags
Closes gh-26967
2021-05-23 18:09:34 +02:00
Brian Clozel ac0e71745b Set best matching pattern attribute in WebMvc.fn
Prior to this commit, the `RouterFunctionMapping` WebFlux.fn variant
would set the `HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE` as an
exchange attribute. This is useful for instrumentation purposes.
The WebMvc.fn variant would not do the same; this would lead to
"UNKNOWN" path metrics tags.

This commit ensures that the `RouterFunctionMapping` WebMvc.fn variant
does set the `BEST_MATCHING_PATTERN_ATTRIBUTE` and
`BEST_MATCHING_HANDLER_ATTRIBUTE` request attributes.

Closes gh-26963
2021-05-21 11:54:06 +02:00
izeye f65cbe0992 Polish PORT_PATTERN in UriComponentsBuilder 2021-05-20 18:20:57 +01:00
Johnny Lim a2e5d9a14f Polishing
Closes gh-26960
2021-05-20 15:49:13 +02:00
Christoph Dreis 360f555e77 Introduce ResponseEntity.internalServerError()
Closes gh-26952
2021-05-18 16:57:20 +02:00
Sam Brannen 7c756027a0 Deprecate internal APIs in ScriptUtils in spring-jdbc
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, this commit formally deprecates the following methods
in ScriptUtils in spring-jdbc.

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

Closes gh-26947
2021-05-18 15:43:54 +02:00
Sam Brannen 4c642ccdcd Logically reorganize methods in ScriptUtils
See gh-26947
2021-05-18 14:56:49 +02:00
Sam Brannen fab7b1cebe Polish ScriptUtils internals in spring-r2dbc
See gh-26947
2021-05-18 14:29:18 +02:00
Rossen Stoyanchev 101ed17b6f Polishing contribution
Closes gh-26927
2021-05-17 17:28:16 +01:00
Ruslan Akhundov 66588bae92 CorsConfiguration supports port pattern and port lists
See gh-26927
2021-05-17 17:28:16 +01:00
Sam Brannen d33545bdce Avoid duplicate comment processing in ScriptUtils in spring-r2dbc
See gh-26947
2021-05-17 13:15:44 +02:00
Sam Brannen e8e157ebf8 Polish ScriptUtils in spring-r2dbc 2021-05-17 12:49:46 +02:00
Sam Brannen 7f5904c68b Remove internal APIs from ScriptUtils in spring-r2dbc
Prior to this commit, many of the utility methods in ScriptUtils in
spring-r2dbc were public by accident: they were copied from ScriptUtils
in spring-jdbc without changing the visibility when spring-r2dbc was
introduced in Spring Framework. 5.3 GA.

This commit corrects this mistake by removing internal APIs from
ScriptUtils in spring-r2dbc from the public contract.

See gh-26947
2021-05-17 12:15:30 +02:00
Sam Brannen 66e488850b Ignore comments when searching for statement delimiter in ScriptUtils
This commit picks up where 569ce840cf left off, by correctly invoking
the new containsStatementSeparator(...) method from
executeSqlScript(...) in ScriptUtils in spring-r2dbc.

See gh-26911
2021-05-17 12:07:04 +02:00
Sébastien Deleuze 3dba3691a7 Upgrade to Coroutines 1.5.0
This commit upgrades to Coroutines 1.5.0 while retaining
Coroutines 1.4.x compatibility.

Closes gh-26897
2021-05-17 11:37:02 +02:00
Sam Brannen c80c4e001a Add missing author tags and sync SQL script support for JDBC & R2DBC 2021-05-16 17:18:56 +02:00
Sam Brannen 8da049b613 Update Javadoc URL for Apache HttpComponents Client 2021-05-16 15:22:37 +02:00
Sam Brannen 1acd832759 Fix link in @EventListener's id Javadoc 2021-05-16 15:08:33 +02:00
Sam Brannen 261927b72a Stop using deprecated Netty feature in ReactorHttpsServer 2021-05-16 15:03:42 +02:00
Sam Brannen 24aa7f546b Upgrade to JUnit 5.7.2
Closes gh-26946
2021-05-16 15:00:45 +02:00
Sam Brannen 4cfad25468 Polish ScriptUtils implementations 2021-05-14 15:15:12 +02:00
Sam Brannen 569ce840cf Ignore comments when searching for statement delimiter in ScriptUtils
Prior to this commit, the implementations of
ScriptUtils.containsSqlScriptDelimiters() in spring-jdbc and
spring-r2dbc 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:23:27 +02:00
Sam Brannen fae484855b Fix grammar in inline comment in HttpStatus
See gh-26842
2021-05-13 16:21:45 +02:00
Qimiao Chen cab20d1202 Fix punctuation in Custom Cache Resolution section of ref docs
Closes gh-26938
2021-05-13 15:30:58 +02:00
Sam Brannen e2bf513563 Remove accidental dependency on Spring 5.2.x in spring-r2dbc tests 2021-05-12 13:43:36 +02:00
Sam Brannen 84e56bb5d9 Sync ScriptUtilsUnitTests implementations to simplify maintenance 2021-05-12 12:54:35 +02:00
Sam Brannen 6f5e66f00c Add missing tests for multiple comment prefixes in R2DBC ScriptUtils
See gh-23289
2021-05-12 12:23:54 +02:00
Sam Brannen cda72e4a70 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 implementations in
spring-jdbc and spring-r2dbc.

Closes gh-26935
2021-05-12 12:07:55 +02:00
Sam Brannen e31a4c4c77 Polishing 2021-05-12 11:31:15 +02:00
Spring Buildmaster 4809632f44 Next development version (v5.3.8-SNAPSHOT) 2021-05-12 05:50:28 +00:00
325 changed files with 4438 additions and 2455 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ to start a discussion first or have already created an issue, once a pull reques
created, we will close the issue as superseded by the pull request, and the discussion
about the issue will continue under the pull request.
1. Always check out the `master` branch and submit pull requests against it
1. Always check out the `main` branch and submit pull requests against it
(for target version see [settings.gradle](settings.gradle)).
Backports to prior versions will be considered on a case-by-case basis and reflected as
the fix version in the issue tracker.
+40 -40
View File
@@ -1,7 +1,7 @@
plugins {
id 'io.spring.dependency-management' version '1.0.9.RELEASE' apply false
id 'io.spring.nohttp' version '0.0.5.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.5.0' apply false
id 'org.jetbrains.kotlin.jvm' version '1.5.21' apply false
id 'org.jetbrains.dokka' version '0.10.1' apply false
id 'org.asciidoctor.jvm.convert' version '3.1.0'
id 'org.asciidoctor.jvm.pdf' version '3.1.0'
@@ -10,7 +10,7 @@ plugins {
id "com.github.ben-manes.versions" version '0.28.0'
id "com.github.johnrengelman.shadow" version "6.1.0" apply false
id "me.champeau.jmh" version "0.6.4" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.5.0" apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.5.21" apply false
id "org.unbroken-dome.xjc" version '2.0.0' apply false
}
@@ -27,16 +27,16 @@ configure(allprojects) { project ->
dependencyManagement {
imports {
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.3"
mavenBom "io.netty:netty-bom:4.1.63.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.7"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR9"
mavenBom "io.rsocket:rsocket-bom:1.1.0"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.40.v20210413"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.0"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.3"
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.0"
mavenBom "org.junit:junit-bom:5.7.1"
mavenBom "com.fasterxml.jackson:jackson-bom:2.12.4"
mavenBom "io.netty:netty-bom:4.1.65.Final"
mavenBom "io.projectreactor:reactor-bom:2020.0.9"
mavenBom "io.r2dbc:r2dbc-bom:Arabba-SR10"
mavenBom "io.rsocket:rsocket-bom:1.1.1"
mavenBom "org.eclipse.jetty:jetty-bom:9.4.43.v20210629"
mavenBom "org.jetbrains.kotlin:kotlin-bom:1.5.21"
mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.5.1"
mavenBom "org.jetbrains.kotlinx:kotlinx-serialization-bom:1.2.1"
mavenBom "org.junit:junit-bom:5.7.2"
}
dependencies {
dependencySet(group: 'org.apache.logging.log4j', version: '2.14.1') {
@@ -51,7 +51,7 @@ configure(allprojects) { project ->
}
dependency "com.google.code.findbugs:jsr305:3.0.2"
dependencySet(group: 'org.aspectj', version: '1.9.6') {
dependencySet(group: 'org.aspectj', version: '1.9.7') {
entry 'aspectjrt'
entry 'aspectjtools'
entry 'aspectjweaver'
@@ -67,18 +67,18 @@ 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.21"
dependency "io.reactivex.rxjava3:rxjava:3.0.12"
dependency "io.reactivex.rxjava3:rxjava:3.0.13"
dependency "io.projectreactor.tools:blockhound:1.0.4.RELEASE"
dependency "com.caucho:hessian:4.0.63"
dependency "com.fasterxml:aalto-xml:1.2.2"
dependency "com.fasterxml:aalto-xml:1.3.0"
dependency("com.fasterxml.woodstox:woodstox-core:6.2.6") {
exclude group: "stax", name: "stax-api"
}
dependency "com.google.code.gson:gson:2.8.6"
dependency "com.google.protobuf:protobuf-java-util:3.15.8"
dependency "com.google.code.gson:gson:2.8.7"
dependency "com.google.protobuf:protobuf-java-util:3.17.3"
dependency "com.googlecode.protobuf-java-format:protobuf-java-format:1.4"
dependency("com.thoughtworks.xstream:xstream:1.4.16") {
dependency("com.thoughtworks.xstream:xstream:1.4.17") {
exclude group: "xpp3", name: "xpp3_min"
exclude group: "xmlpull", name: "xmlpull"
}
@@ -91,7 +91,7 @@ configure(allprojects) { project ->
entry 'jibx-run'
}
dependency "org.ogce:xpp3:1.1.6"
dependency "org.yaml:snakeyaml:1.28"
dependency "org.yaml:snakeyaml:1.29"
dependency "com.h2database:h2:1.4.200"
dependency "com.github.ben-manes.caffeine:caffeine:2.9.1"
@@ -100,7 +100,7 @@ configure(allprojects) { project ->
dependency "commons-io:commons-io:2.5"
dependency "io.vavr:vavr:0.10.3"
dependency "net.sf.jopt-simple:jopt-simple:5.0.4"
dependencySet(group: 'org.apache.activemq', version: '5.16.1') {
dependencySet(group: 'org.apache.activemq', version: '5.16.2') {
entry 'activemq-broker'
entry('activemq-kahadb-store') {
exclude group: "org.springframework", name: "spring-context"
@@ -116,29 +116,29 @@ configure(allprojects) { project ->
dependency "org.apache.poi:poi-ooxml:4.1.2"
dependency "org.apache-extras.beanshell:bsh:2.0b6"
dependency "org.freemarker:freemarker:2.3.31"
dependency "org.hsqldb:hsqldb:2.5.1"
dependency "org.hsqldb:hsqldb:2.5.2"
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.31.Final"
dependency "org.hibernate:hibernate-core:5.4.32.Final"
dependency "org.hibernate:hibernate-validator:6.2.0.Final"
dependency "org.webjars:webjars-locator-core:0.46"
dependency "org.webjars:webjars-locator-core:0.47"
dependency "org.webjars:underscorejs:1.8.3"
dependencySet(group: 'org.apache.tomcat', version: '9.0.45') {
dependencySet(group: 'org.apache.tomcat', version: '9.0.50') {
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.45') {
dependencySet(group: 'org.apache.tomcat.embed', version: '9.0.50') {
entry 'tomcat-embed-core'
entry 'tomcat-embed-websocket'
}
dependencySet(group: 'io.undertow', version: '2.2.7.Final') {
dependencySet(group: 'io.undertow', version: '2.2.8.Final') {
entry 'undertow-core'
entry('undertow-websockets-jsr') {
exclude group: "org.jboss.spec.javax.websocket", name: "jboss-websocket-api_1.1_spec"
@@ -159,11 +159,11 @@ configure(allprojects) { project ->
dependency("org.apache.httpcomponents:httpasyncclient:4.1.4") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency 'org.apache.httpcomponents.client5:httpclient5:5.0.3'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.0.3'
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.6"
dependency 'org.apache.httpcomponents.client5:httpclient5:5.1'
dependency 'org.apache.httpcomponents.core5:httpcore5-reactive:5.1.1'
dependency "org.eclipse.jetty:jetty-reactive-httpclient:1.1.9"
dependency "org.jruby:jruby:9.2.16.0"
dependency "org.jruby:jruby:9.2.19.0"
dependency "org.python:jython-standalone:2.7.1"
dependency "org.mozilla:rhino:1.7.11"
@@ -189,25 +189,25 @@ configure(allprojects) { project ->
dependency "org.testng:testng:7.4.0"
dependency "org.hamcrest:hamcrest:2.1"
dependency "org.awaitility:awaitility:3.1.6"
dependency "org.assertj:assertj-core:3.19.0"
dependency "org.assertj:assertj-core:3.20.2"
dependencySet(group: 'org.xmlunit', version: '2.8.2') {
entry 'xmlunit-assertj'
entry('xmlunit-matchers') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
}
dependencySet(group: 'org.mockito', version: '3.9.0') {
dependencySet(group: 'org.mockito', version: '3.11.0') {
entry('mockito-core') {
exclude group: "org.hamcrest", name: "hamcrest-core"
}
entry 'mockito-junit-jupiter'
}
dependency "io.mockk:mockk:1.10.2"
dependency "io.mockk:mockk:1.11.0"
dependency("net.sourceforge.htmlunit:htmlunit:2.49.1") {
dependency("net.sourceforge.htmlunit:htmlunit:2.51.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:htmlunit-driver:2.49.1") {
dependency("org.seleniumhq.selenium:htmlunit-driver:2.51.0") {
exclude group: "commons-logging", name: "commons-logging"
}
dependency("org.seleniumhq.selenium:selenium-java:3.141.59") {
@@ -236,7 +236,7 @@ configure(allprojects) { project ->
dependency "com.ibm.websphere:uow:6.0.2.17"
dependency "com.jamonapi:jamon:2.82"
dependency "joda-time:joda-time:2.10.10"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.8"
dependency "org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.9"
dependency "org.javamoney:moneta:1.3"
dependency "com.sun.activation:javax.activation:1.2.0"
@@ -316,7 +316,7 @@ configure([rootProject] + javaProjects) { project ->
kotlinOptions {
languageVersion = "1.3"
apiVersion = "1.3"
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings"]
freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings", "-Xopt-in=kotlin.RequiresOptIn"]
allWarningsAsErrors = true
}
}
@@ -336,7 +336,7 @@ configure([rootProject] + javaProjects) { project ->
}
checkstyle {
toolVersion = "8.42"
toolVersion = "8.44"
configDirectory.set(rootProject.file("src/checkstyle"))
}
@@ -375,10 +375,10 @@ configure([rootProject] + javaProjects) { project ->
"https://fasterxml.github.io/jackson-core/javadoc/2.10/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.10/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.10/",
"https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/",
"https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
"https://junit.org/junit5/docs/5.7.1/api/"
"https://junit.org/junit5/docs/5.7.2/api/"
] as String[]
}
+1 -1
View File
@@ -1,4 +1,4 @@
version=5.3.7-SNAPSHOT
version=5.3.9
org.gradle.jvmargs=-Xmx1536M
org.gradle.caching=true
org.gradle.parallel=true
+13 -1
View File
@@ -103,9 +103,12 @@ dokka {
externalDocumentationLink {
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
}
/*
This link causes errors, removing to fix the build.
externalDocumentationLink {
url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
}
*/
externalDocumentationLink {
url = new URL("https://r2dbc.io/spec/0.8.3.RELEASE/api/")
}
@@ -127,6 +130,8 @@ task extractDocResources(type: Copy, dependsOn: downloadResources) {
}
asciidoctorj {
def docRoot = 'https://docs.spring.io'
def docsSpringFramework = "${docRoot}/spring-framework/docs/${project.version}"
version = '2.4.1'
fatalWarnings ".*"
options doctype: 'book', eruby: 'erubis'
@@ -143,7 +148,11 @@ asciidoctorj {
'highlightjs-theme': 'googlecode',
stylesdir: 'css/',
stylesheet: 'stylesheet.css',
'spring-version': project.version
'spring-version': project.version,
'spring-framework-main-code': 'https://github.com/spring-projects/spring-framework/tree/main',
'doc-root': docRoot,
'docs-spring-framework': docsSpringFramework,
'api-spring-framework': "${docsSpringFramework}/javadoc-api/org/springframework"
])
}
@@ -154,6 +163,9 @@ asciidoctorj {
asciidoctor {
baseDirFollowsSourceDir()
configurations 'asciidoctorExt'
attributes([
noheader: '' // custom header in docinfo-header.html
])
sources {
include '*.adoc'
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -625,7 +625,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
StringBuilder sb = new StringBuilder();
if (bodyStart >= 0 && bodyStart != (currentToken.length() - 1)) {
sb.append(currentToken.substring(bodyStart + 1));
sb.append(" ");
sb.append(' ');
}
numTokensConsumed++;
int currentIndex = startIndex + numTokensConsumed;
@@ -645,7 +645,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
toAppend = toAppend.substring(1);
}
sb.append(toAppend);
sb.append(" ");
sb.append(' ');
currentIndex++;
numTokensConsumed++;
}
@@ -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.
@@ -547,7 +547,7 @@ public class AspectJExpressionPointcut extends AbstractExpressionPointcut
StringBuilder sb = new StringBuilder("AspectJExpressionPointcut: (");
for (int i = 0; i < this.pointcutParameterTypes.length; i++) {
sb.append(this.pointcutParameterTypes[i].getName());
sb.append(" ");
sb.append(' ');
sb.append(this.pointcutParameterNames[i]);
if ((i+1) < this.pointcutParameterTypes.length) {
sb.append(", ");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -255,19 +255,19 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
StringBuilder sb = new StringBuilder();
if (includeModifier) {
sb.append(Modifier.toString(getModifiers()));
sb.append(" ");
sb.append(' ');
}
if (includeReturnTypeAndArgs) {
appendType(sb, getReturnType(), useLongReturnAndArgumentTypeName);
sb.append(" ");
sb.append(' ');
}
appendType(sb, getDeclaringType(), useLongTypeName);
sb.append(".");
sb.append('.');
sb.append(getMethod().getName());
sb.append("(");
sb.append('(');
Class<?>[] parametersTypes = getParameterTypes();
appendTypes(sb, parametersTypes, includeReturnTypeAndArgs, useLongReturnAndArgumentTypeName);
sb.append(")");
sb.append(')');
return sb.toString();
}
@@ -278,7 +278,7 @@ public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint,
for (int size = types.length, i = 0; i < size; i++) {
appendType(sb, types[i], useLongReturnAndArgumentTypeName);
if (i < size - 1) {
sb.append(",");
sb.append(',');
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -19,7 +19,9 @@ package org.springframework.aop.framework;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;
@@ -29,7 +31,9 @@ import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.core.DecoratingProxy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* Utility methods for AOP proxy factories.
@@ -44,6 +48,11 @@ import org.springframework.util.ObjectUtils;
*/
public abstract class AopProxyUtils {
// JDK 17 Class.isSealed() method available?
@Nullable
private static final Method isSealedMethod = ClassUtils.getMethodIfAvailable(Class.class, "isSealed");
/**
* Obtain the singleton target object behind the given proxy, if any.
* @param candidate the (potential) proxy to check
@@ -130,34 +139,23 @@ public abstract class AopProxyUtils {
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
List<Class<?>> proxiedInterfaces = new ArrayList<>(specifiedInterfaces.length + 3);
for (Class<?> ifc : specifiedInterfaces) {
// Only non-sealed interfaces are actually eligible for JDK proxying (on JDK 17)
if (isSealedMethod == null || Boolean.FALSE.equals(ReflectionUtils.invokeMethod(isSealedMethod, ifc))) {
proxiedInterfaces.add(ifc);
}
}
if (addAdvised) {
nonUserIfcCount++;
if (!advised.isInterfaceProxied(SpringProxy.class)) {
proxiedInterfaces.add(SpringProxy.class);
}
if (addDecoratingProxy) {
nonUserIfcCount++;
if (!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)) {
proxiedInterfaces.add(Advised.class);
}
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
if (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)) {
proxiedInterfaces.add(DecoratingProxy.class);
}
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
return proxiedInterfaces;
return ClassUtils.toClassArray(proxiedInterfaces);
}
/**
@@ -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;
@@ -440,7 +441,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);
}
@@ -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.
@@ -137,7 +137,7 @@ public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcu
StringBuilder sb = new StringBuilder(getClass().getName());
sb.append(": advice ");
if (this.adviceBeanName != null) {
sb.append("bean '").append(this.adviceBeanName).append("'");
sb.append("bean '").append(this.adviceBeanName).append('\'');
}
else {
sb.append(this.advice);
@@ -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);
@@ -191,9 +191,9 @@ public abstract class AbstractBeanFactoryBasedTargetSource implements TargetSour
@Override
public String toString() {
StringBuilder sb = new StringBuilder(getClass().getSimpleName());
sb.append(" for target bean '").append(this.targetBeanName).append("'");
sb.append(" for target bean '").append(this.targetBeanName).append('\'');
if (this.targetClass != null) {
sb.append(" of type [").append(this.targetClass.getName()).append("]");
sb.append(" of type [").append(this.targetClass.getName()).append(']');
}
return sb.toString();
}
@@ -276,14 +276,14 @@ public class AspectJAdviceParameterNameDiscovererTests {
private static String format(String[] names) {
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append('(');
for (int i = 0; i < names.length; i++) {
sb.append(names[i]);
if ((i + 1) < names.length) {
sb.append(",");
sb.append(',');
}
}
sb.append(")");
sb.append(')');
return sb.toString();
}
@@ -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
@@ -240,6 +240,16 @@ public class ProxyFactoryTests {
assertThat(factory.countAdvicesOfType(NopInterceptor.class) == 2).isTrue();
}
@Test
public void testSealedInterfaceExclusion() {
// String implements ConstantDesc on JDK 12+, sealed as of JDK 17
ProxyFactory factory = new ProxyFactory(new String());
NopInterceptor di = new NopInterceptor();
factory.addAdvice(0, di);
Object proxy = factory.getProxy();
assertThat(proxy).isInstanceOf(CharSequence.class);
}
/**
* Should see effect immediately on behavior.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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,8 +41,6 @@ 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;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.KotlinDetector;
@@ -75,8 +73,6 @@ import org.springframework.util.StringUtils;
*/
public abstract class BeanUtils {
private static final Log logger = LogFactory.getLog(BeanUtils.class);
private static final ParameterNameDiscoverer parameterNameDiscoverer =
new DefaultParameterNameDiscoverer();
@@ -551,9 +547,6 @@ public abstract class BeanUtils {
}
catch (Throwable ex) {
// e.g. AccessControlException on Google App Engine
if (logger.isDebugEnabled()) {
logger.debug("Could not access system ClassLoader: " + ex);
}
return null;
}
}
@@ -564,10 +557,6 @@ public abstract class BeanUtils {
Class<?> editorClass = cl.loadClass(editorName);
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;
}
@@ -579,10 +568,6 @@ public abstract class BeanUtils {
catch (ClassNotFoundException ex) {
// 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;
}
@@ -247,14 +247,14 @@ class TypeConverterDelegate {
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
StringBuilder msg = new StringBuilder();
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append('\'');
if (propertyName != null) {
msg.append(" for property '").append(propertyName).append("'");
msg.append(" for property '").append(propertyName).append('\'');
}
if (editor != null) {
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
"] returned inappropriate value of type '").append(
ClassUtils.getDescriptiveType(convertedValue)).append("'");
ClassUtils.getDescriptiveType(convertedValue)).append('\'');
throw new IllegalArgumentException(msg.toString());
}
else {
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -84,7 +84,7 @@ import org.springframework.lang.Nullable;
* (only applicable when running in a web application context)
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
* <li>InitializingBean's {@code afterPropertiesSet}
* <li>a custom init-method definition
* <li>a custom {@code init-method} definition
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
* </ol>
*
@@ -92,7 +92,7 @@ import org.springframework.lang.Nullable;
* <ol>
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
* <li>DisposableBean's {@code destroy}
* <li>a custom destroy-method definition
* <li>a custom {@code destroy-method} definition
* </ol>
*
* @author Rod Johnson
@@ -102,6 +102,8 @@ import org.springframework.lang.Nullable;
* @see BeanNameAware#setBeanName
* @see BeanClassLoaderAware#setBeanClassLoader
* @see BeanFactoryAware#setBeanFactory
* @see org.springframework.context.EnvironmentAware#setEnvironment
* @see org.springframework.context.EmbeddedValueResolverAware#setEmbeddedValueResolver
* @see org.springframework.context.ResourceLoaderAware#setResourceLoader
* @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
* @see org.springframework.context.MessageSourceAware#setMessageSource
@@ -111,6 +113,7 @@ import org.springframework.lang.Nullable;
* @see InitializingBean#afterPropertiesSet
* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
* @see DisposableBean#destroy
* @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -217,13 +217,13 @@ public class RequiredAnnotationBeanPostProcessor implements SmartInstantiationAw
sb.append(" and");
}
else {
sb.append(",");
sb.append(',');
}
}
sb.append(" '").append(propertyName).append("'");
sb.append(" '").append(propertyName).append('\'');
}
sb.append(size == 1 ? " is" : " are");
sb.append(" required for bean '").append(beanName).append("'");
sb.append(" required for bean '").append(beanName).append('\'');
return sb.toString();
}
@@ -489,9 +489,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp
resolveConstructorArguments(args, 2, hasClosureArgument ? args.length - 1 : args.length);
this.currentBeanDefinition = new GroovyBeanDefinitionWrapper(beanName, (Class<?>) args[1], constructorArgs);
Map<?, ?> namedArgs = (Map<?, ?>) args[0];
for (Object key : namedArgs.keySet()) {
String propName = (String) key;
setProperty(propName, namedArgs.get(propName));
for (Map.Entry<?, ?> entity : namedArgs.entrySet()) {
String propName = (String) entity.getKey();
setProperty(propName, entity.getValue());
}
}
// factory method syntax
@@ -1241,7 +1241,7 @@ public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccess
@Override
public String toString() {
StringBuilder sb = new StringBuilder("class [");
sb.append(getBeanClassName()).append("]");
sb.append(getBeanClassName()).append(']');
sb.append("; scope=").append(this.scope);
sb.append("; abstract=").append(this.abstractFlag);
sb.append("; lazyInit=").append(this.lazyInit);
@@ -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,6 +21,7 @@ import java.util.function.Supplier;
import org.springframework.beans.factory.config.AutowiredPropertyMarker;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
@@ -102,7 +103,7 @@ public final class BeanDefinitionBuilder {
* @param beanClass the {@code Class} of the bean that the definition is being created for
*/
public static BeanDefinitionBuilder rootBeanDefinition(Class<?> beanClass) {
return rootBeanDefinition(beanClass, null);
return rootBeanDefinition(beanClass, (String) null);
}
/**
@@ -117,6 +118,30 @@ public final class BeanDefinitionBuilder {
return builder;
}
/**
* Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
* @param beanType the {@link ResolvableType type} of the bean that the definition is being created for
* @param instanceSupplier a callback for creating an instance of the bean
* @since 5.3.9
*/
public static <T> BeanDefinitionBuilder rootBeanDefinition(ResolvableType beanType, Supplier<T> instanceSupplier) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setTargetType(beanType);
beanDefinition.setInstanceSupplier(instanceSupplier);
return new BeanDefinitionBuilder(beanDefinition);
}
/**
* Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
* @param beanClass the {@code Class} of the bean that the definition is being created for
* @param instanceSupplier a callback for creating an instance of the bean
* @since 5.3.9
* @see #rootBeanDefinition(ResolvableType, Supplier)
*/
public static <T> BeanDefinitionBuilder rootBeanDefinition(Class<T> beanClass, Supplier<T> instanceSupplier) {
return rootBeanDefinition(ResolvableType.forClass(beanClass), instanceSupplier);
}
/**
* Create a new {@code BeanDefinitionBuilder} used to construct a {@link ChildBeanDefinition}.
* @param parentName the name of the parent bean
@@ -331,6 +356,16 @@ public final class BeanDefinitionBuilder {
return this;
}
/**
* Set whether this bean is 'synthetic', that is, not defined by
* the application itself.
* @since 5.3.9
*/
public BeanDefinitionBuilder setSynthetic(boolean synthetic) {
this.beanDefinition.setSynthetic(synthetic);
return this;
}
/**
* Apply the given customizers to the underlying bean definition.
* @since 5.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -35,6 +35,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.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -244,8 +245,10 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
return (bean.equals(null) ? null : bean);
}
else {
return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
this.owner.getBean(method.getReturnType()));
// Find target bean matching the (potentially generic) method return type
ResolvableType genericReturnType = ResolvableType.forMethodReturnType(method);
return (argsToUse != null ? this.owner.getBeanProvider(genericReturnType).getObject(argsToUse) :
this.owner.getBeanProvider(genericReturnType).getObject());
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -277,12 +277,12 @@ class ConstructorResolver {
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"Could not resolve matching constructor on bean class [" + mbd.getBeanClassName() + "] " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"Ambiguous constructor matches found on bean class [" + mbd.getBeanClassName() + "] " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
@@ -608,7 +608,7 @@ class ConstructorResolver {
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
"No matching factory method found on class [" + factoryClass.getName() + "]: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
@@ -619,12 +619,12 @@ class ConstructorResolver {
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
"Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" +
factoryClass.getName() + "]: needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"Ambiguous factory method matches found on class [" + factoryClass.getName() + "] " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
@@ -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.
@@ -19,17 +19,25 @@ package org.springframework.beans.factory.support;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
* Represents an override of a method that looks up an object in the same IoC context.
* Represents an override of a method that looks up an object in the same IoC context,
* either by bean name or by bean type (based on the declared method return type).
*
* <p>Methods eligible for lookup override must not have arguments.
* <p>Methods eligible for lookup override may declare arguments in which case the
* given arguments are passed to the bean retrieval operation.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 1.1
* @see org.springframework.beans.factory.BeanFactory#getBean(String)
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
* @see org.springframework.beans.factory.BeanFactory#getBean(String, Object...)
* @see org.springframework.beans.factory.BeanFactory#getBean(Class, Object...)
* @see org.springframework.beans.factory.BeanFactory#getBeanProvider(ResolvableType)
*/
public class LookupOverride extends MethodOverride {
@@ -43,8 +51,8 @@ public class LookupOverride extends MethodOverride {
/**
* Construct a new LookupOverride.
* @param methodName the name of the method to override
* @param beanName the name of the bean in the current {@code BeanFactory}
* that the overridden method should return (may be {@code null})
* @param beanName the name of the bean in the current {@code BeanFactory} that the
* overridden method should return (may be {@code null} for type-based bean retrieval)
*/
public LookupOverride(String methodName, @Nullable String beanName) {
super(methodName);
@@ -53,9 +61,9 @@ public class LookupOverride extends MethodOverride {
/**
* Construct a new LookupOverride.
* @param method the method to override
* @param beanName the name of the bean in the current {@code BeanFactory}
* that the overridden method should return (may be {@code null})
* @param method the method declaration to override
* @param beanName the name of the bean in the current {@code BeanFactory} that the
* overridden method should return (may be {@code null} for type-based bean retrieval)
*/
public LookupOverride(Method method, @Nullable String beanName) {
super(method.getName());
@@ -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.
@@ -19,9 +19,8 @@ package org.springframework.beans.factory.support;
import java.lang.reflect.Method;
/**
* Interface to be implemented by classes that can reimplement any method
* on an IoC-managed object: the <b>Method Injection</b> form of
* Dependency Injection.
* Interface to be implemented by classes that can reimplement any method on an
* IoC-managed object: the <b>Method Injection</b> form of Dependency Injection.
*
* <p>Such methods may be (but need not be) abstract, in which case the
* container will create a concrete subclass to instantiate.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -25,7 +25,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Extension of MethodOverride that represents an arbitrary
* Extension of {@link MethodOverride} that represents an arbitrary
* override of a method by the IoC container.
*
* <p>Any non-final method can be overridden, irrespective of its
@@ -45,7 +45,7 @@ public class ReplaceOverride extends MethodOverride {
/**
* Construct a new ReplaceOverride.
* @param methodName the name of the method to override
* @param methodReplacerBeanName the bean name of the MethodReplacer
* @param methodReplacerBeanName the bean name of the {@link MethodReplacer}
*/
public ReplaceOverride(String methodName, String methodReplacerBeanName) {
super(methodName);
@@ -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.
@@ -18,14 +18,14 @@ package org.springframework.beans;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -36,23 +36,21 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Chris Beams
* @since 08.03.2004
*/
public class ConcurrentBeanWrapperTests {
class ConcurrentBeanWrapperTests {
private final Log logger = LogFactory.getLog(getClass());
private Set<TestRun> set = Collections.synchronizedSet(new HashSet<TestRun>());
private final Set<TestRun> set = ConcurrentHashMap.newKeySet();
private Throwable ex = null;
@Test
public void testSingleThread() {
for (int i = 0; i < 100; i++) {
performSet();
}
@RepeatedTest(100)
void testSingleThread() {
performSet();
}
@Test
public void testConcurrent() {
void testConcurrent() {
for (int i = 0; i < 10; i++) {
TestRun run = new TestRun(this);
set.add(run);
@@ -82,7 +80,7 @@ public class ConcurrentBeanWrapperTests {
Properties p = (Properties) System.getProperties().clone();
assertThat(p.size() != 0).as("The System properties must not be empty").isTrue();
assertThat(p).as("The System properties must not be empty").isNotEmpty();
for (Iterator<?> i = p.entrySet().iterator(); i.hasNext();) {
i.next();
@@ -111,7 +109,7 @@ public class ConcurrentBeanWrapperTests {
private ConcurrentBeanWrapperTests test;
public TestRun(ConcurrentBeanWrapperTests test) {
TestRun(ConcurrentBeanWrapperTests test) {
this.test = test;
}
@@ -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.
@@ -31,6 +31,7 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.ro
* invoking a factory method is not instructive to the user and rather misleading.
*
* @author Chris Beams
* @author Juergen Hoeller
*/
public class Spr5475Tests {
@@ -40,7 +41,8 @@ public class Spr5475Tests {
rootBeanDefinition(Foo.class)
.setFactoryMethod("noArgFactory")
.addConstructorArgValue("bogusArg").getBeanDefinition(),
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String)'. " +
"Error creating bean with name 'foo': No matching factory method found on class " +
"[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(String)'. " +
"Check that a method with the specified name and arguments exists and that it is static.");
}
@@ -51,7 +53,8 @@ public class Spr5475Tests {
.setFactoryMethod("noArgFactory")
.addConstructorArgValue("bogusArg1")
.addConstructorArgValue("bogusArg2".getBytes()).getBeanDefinition(),
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(String,byte[])'. " +
"Error creating bean with name 'foo': No matching factory method found on class " +
"[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(String,byte[])'. " +
"Check that a method with the specified name and arguments exists and that it is static.");
}
@@ -65,7 +68,8 @@ public class Spr5475Tests {
def.setConstructorArgumentValues(cav);
assertExceptionMessageForMisconfiguredFactoryMethod(def,
"Error creating bean with name 'foo': No matching factory method found: factory method 'noArgFactory(CharSequence,byte[])'. " +
"Error creating bean with name 'foo': No matching factory method found on class " +
"[org.springframework.beans.factory.Spr5475Tests$Foo]: factory method 'noArgFactory(CharSequence,byte[])'. " +
"Check that a method with the specified name and arguments exists and that it is static.");
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -121,6 +121,18 @@ public class LookupAnnotationTests {
assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
}
@Test
public void testWithGenericBean() {
beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
assertThat(bean).isNotNull();
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
}
public static abstract class AbstractBean {
@@ -147,4 +159,26 @@ public class LookupAnnotationTests {
AbstractBean abstractBean;
}
public static class NumberStore<T extends Number> {
}
public static class DoubleStore extends NumberStore<Double> {
}
public static class FloatStore extends NumberStore<Float> {
}
public static abstract class NumberBean {
@Lookup
public abstract NumberStore<Double> getDoubleStore();
@Lookup
public abstract NumberStore<Float> getFloatStore();
}
}
@@ -141,6 +141,7 @@ class YamlProcessorTests {
}
@Test
@SuppressWarnings("unchecked")
void standardTypesSupportedByDefault() throws Exception {
setYaml("value: !!set\n ? first\n ? second");
this.processor.process((properties, map) -> {
@@ -17,22 +17,25 @@
package org.springframework.beans.factory.support;
import java.util.Arrays;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.ResolvableType;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Rod Johnson
* @author Juergen Hoeller
* @author Stephane Nicoll
*/
public class BeanDefinitionBuilderTests {
class BeanDefinitionBuilderTests {
@Test
public void beanClassWithSimpleProperty() {
void builderWithBeanClassWithSimpleProperty() {
String[] dependsOn = new String[] { "A", "B", "C" };
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class);
bdb.setScope(BeanDefinition.SCOPE_PROTOTYPE);
@@ -49,7 +52,7 @@ public class BeanDefinitionBuilderTests {
}
@Test
public void beanClassWithFactoryMethod() {
void builderWithBeanClassAndFactoryMethod() {
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class, "create");
RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();
assertThat(rbd.hasBeanClass()).isTrue();
@@ -58,7 +61,7 @@ public class BeanDefinitionBuilderTests {
}
@Test
public void beanClassName() {
void builderWithBeanClassName() {
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class.getName());
RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();
assertThat(rbd.hasBeanClass()).isFalse();
@@ -66,7 +69,7 @@ public class BeanDefinitionBuilderTests {
}
@Test
public void beanClassNameWithFactoryMethod() {
void builderWithBeanClassNameAndFactoryMethod() {
BeanDefinitionBuilder bdb = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class.getName(), "create");
RootBeanDefinition rbd = (RootBeanDefinition) bdb.getBeanDefinition();
assertThat(rbd.hasBeanClass()).isFalse();
@@ -74,4 +77,78 @@ public class BeanDefinitionBuilderTests {
assertThat(rbd.getFactoryMethodName()).isEqualTo("create");
}
@Test
void builderWithResolvableTypeAndInstanceSupplier() {
ResolvableType type = ResolvableType.forClassWithGenerics(Function.class, Integer.class, String.class);
Function<Integer, String> function = i -> "value " + i;
RootBeanDefinition rbd = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(type, () -> function).getBeanDefinition();
assertThat(rbd.getResolvableType()).isEqualTo(type);
assertThat(rbd.getInstanceSupplier()).isNotNull();
assertThat(rbd.getInstanceSupplier().get()).isInstanceOf(Function.class);
}
@Test
void builderWithBeanClassAndInstanceSupplier() {
RootBeanDefinition rbd = (RootBeanDefinition) BeanDefinitionBuilder
.rootBeanDefinition(String.class, () -> "test").getBeanDefinition();
assertThat(rbd.getResolvableType().resolve()).isEqualTo(String.class);
assertThat(rbd.getInstanceSupplier()).isNotNull();
assertThat(rbd.getInstanceSupplier().get()).isEqualTo("test");
}
@Test
void builderWithAutowireMode() {
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE).getBeanDefinition().getAutowireMode())
.isEqualTo(RootBeanDefinition.AUTOWIRE_BY_TYPE);
}
@Test
void builderWithDependencyCheck() {
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_ALL)
.getBeanDefinition().getDependencyCheck())
.isEqualTo(RootBeanDefinition.DEPENDENCY_CHECK_ALL);
}
@Test
void builderWithDependsOn() {
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class).addDependsOn("test")
.addDependsOn("test2").getBeanDefinition().getDependsOn())
.containsExactly("test", "test2");
}
@Test
void builderWithPrimary() {
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
.setPrimary(true).getBeanDefinition().isPrimary()).isTrue();
}
@Test
void builderWithRole() {
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition().getRole())
.isEqualTo(BeanDefinition.ROLE_INFRASTRUCTURE);
}
@Test
void builderWithSynthetic() {
assertThat(BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
.setSynthetic(true).getBeanDefinition().isSynthetic()).isTrue();
}
@Test
void builderWithCustomizers() {
BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(TestBean.class)
.applyCustomizers(builder -> {
builder.setFactoryMethodName("create");
builder.setRole(BeanDefinition.ROLE_SUPPORT);
})
.applyCustomizers(builder -> builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE))
.getBeanDefinition();
assertThat(beanDefinition.getFactoryMethodName()).isEqualTo("create");
assertThat(beanDefinition.getRole()).isEqualTo(BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
@@ -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.
@@ -36,7 +36,7 @@ public class LookupMethodTests {
@BeforeEach
public void setUp() {
public void setup() {
beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("lookupMethodTests.xml", getClass()));
@@ -83,8 +83,8 @@ public class LookupMethodTests {
public void testWithThreeArgsShouldFail() {
AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
assertThat(bean).isNotNull();
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor").isThrownBy(() ->
bean.getThreeArguments("name", 1, 2));
assertThatExceptionOfType(AbstractMethodError.class).as("does not have a three arg constructor")
.isThrownBy(() -> bean.getThreeArguments("name", 1, 2));
}
@Test
@@ -97,6 +97,21 @@ public class LookupMethodTests {
assertThat(expected.isJedi()).isTrue();
}
@Test
public void testWithGenericBean() {
RootBeanDefinition bd = new RootBeanDefinition(NumberBean.class);
bd.getMethodOverrides().addOverride(new LookupOverride("getDoubleStore", null));
bd.getMethodOverrides().addOverride(new LookupOverride("getFloatStore", null));
beanFactory.registerBeanDefinition("numberBean", bd);
beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
assertThat(bean).isNotNull();
assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
}
public static abstract class AbstractBean {
@@ -111,4 +126,24 @@ public class LookupMethodTests {
public abstract TestBean getThreeArguments(String name, int age, int anotherArg);
}
public static class NumberStore<T extends Number> {
}
public static class DoubleStore extends NumberStore<Double> {
}
public static class FloatStore extends NumberStore<Float> {
}
public static abstract class NumberBean {
public abstract NumberStore<Double> getDoubleStore();
public abstract NumberStore<Float> getFloatStore();
}
}
@@ -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.
@@ -244,7 +244,7 @@ public class QualifierAnnotationAutowireBeanFactoryTests {
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
private static @interface TestQualifier {
private @interface TestQualifier {
}
}
@@ -36,7 +36,7 @@ import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
/**
* Annotation {@link Processor} that writes {@link CandidateComponentsMetadata}
* Annotation {@link Processor} that writes a {@link CandidateComponentsMetadata}
* file for spring components.
*
* @author Stephane Nicoll
@@ -26,7 +26,7 @@ import javax.lang.model.element.ElementKind;
/**
* A {@link StereotypesProvider} implementation that extracts the stereotypes
* flagged by the {@value INDEXED_ANNOTATION} annotation. This implementation
* flagged by the {@value #INDEXED_ANNOTATION} annotation. This implementation
* honors stereotypes defined this way on meta-annotations.
*
* @author Stephane Nicoll
@@ -24,7 +24,7 @@ import javax.lang.model.element.ElementKind;
/**
* A {@link StereotypesProvider} implementation that provides the
* {@value STEREOTYPE} stereotype for each package-info.
* {@value #STEREOTYPE} stereotype for each package-info.
*
* @author Stephane Nicoll
* @since 5.0
@@ -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.
@@ -24,8 +24,8 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
/**
* A {@link StereotypesProvider} that extract a stereotype for each
* {@code javax.*} annotation placed on a class or interface.
* A {@link StereotypesProvider} that extracts a stereotype for each
* {@code javax.*} annotation <i>present</i> on a class or interface.
*
* @author Stephane Nicoll
* @since 5.0
@@ -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.
@@ -22,7 +22,7 @@ import javax.lang.model.element.Element;
/**
* Provide the list of stereotypes that match an {@link Element}.
* If an element has one more stereotypes, it is referenced in the index
* <p>If an element has one or more stereotypes, it is referenced in the index
* of candidate components and each stereotype can be queried individually.
*
* @author Stephane Nicoll
@@ -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.
@@ -138,7 +138,7 @@ abstract class AbstractJCacheOperation<A extends Annotation> implements JCacheOp
@Override
public String toString() {
return getOperationDescription().append("]").toString();
return getOperationDescription().append(']').toString();
}
/**
@@ -148,7 +148,7 @@ abstract class AbstractJCacheOperation<A extends Annotation> implements JCacheOp
protected StringBuilder getOperationDescription() {
StringBuilder result = new StringBuilder();
result.append(getClass().getSimpleName());
result.append("[");
result.append('[');
result.append(this.methodDetails);
return result;
}
@@ -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.
@@ -71,9 +71,9 @@ public class CacheEvictOperation extends CacheOperation {
@Override
protected StringBuilder getOperationDescription() {
StringBuilder sb = super.getOperationDescription();
sb.append(",");
sb.append(',');
sb.append(this.cacheWide);
sb.append(",");
sb.append(',');
sb.append(this.beforeInvocation);
return sb;
}
@@ -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.
@@ -216,13 +216,13 @@ public abstract class CacheOperation implements BasicOperation {
*/
protected StringBuilder getOperationDescription() {
StringBuilder result = new StringBuilder(getClass().getSimpleName());
result.append("[").append(this.name);
result.append('[').append(this.name);
result.append("] caches=").append(this.cacheNames);
result.append(" | key='").append(this.key);
result.append("' | keyGenerator='").append(this.keyGenerator);
result.append("' | cacheManager='").append(this.cacheManager);
result.append("' | cacheResolver='").append(this.cacheResolver);
result.append("' | condition='").append(this.condition).append("'");
result.append("' | condition='").append(this.condition).append('\'');
return result;
}
@@ -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.
@@ -66,7 +66,7 @@ public class CachePutOperation extends CacheOperation {
StringBuilder sb = super.getOperationDescription();
sb.append(" | unless='");
sb.append(this.unless);
sb.append("'");
sb.append('\'');
return sb;
}
@@ -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.
@@ -79,10 +79,10 @@ public class CacheableOperation extends CacheOperation {
StringBuilder sb = super.getOperationDescription();
sb.append(" | unless='");
sb.append(this.unless);
sb.append("'");
sb.append('\'');
sb.append(" | sync='");
sb.append(this.sync);
sb.append("'");
sb.append('\'');
return sb;
}
@@ -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.
@@ -16,6 +16,7 @@
package org.springframework.context;
import java.time.Clock;
import java.util.EventObject;
/**
@@ -37,18 +38,37 @@ public abstract class ApplicationEvent extends EventObject {
/**
* Create a new {@code ApplicationEvent}.
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
* set to {@link System#currentTimeMillis()}.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
* @see #ApplicationEvent(Object, Clock)
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Create a new {@code ApplicationEvent} with its {@link #getTimestamp() timestamp}
* set to the value returned by {@link Clock#millis()} in the provided {@link Clock}.
* <p>This constructor is typically used in testing scenarios.
* @param source the object on which the event initially occurred or with
* which the event is associated (never {@code null})
* @param clock a clock which will provide the timestamp
* @since 5.3.8
* @see #ApplicationEvent(Object)
*/
public ApplicationEvent(Object source, Clock clock) {
super(source);
this.timestamp = clock.millis();
}
/**
* Return the system time in milliseconds when the event occurred.
* Return the time in milliseconds when the event occurred.
* @see #ApplicationEvent(Object)
* @see #ApplicationEvent(Object, Clock)
*/
public final long getTimestamp() {
return this.timestamp;
@@ -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.
@@ -19,13 +19,15 @@ package org.springframework.context.annotation;
import org.springframework.beans.factory.parsing.Problem;
import org.springframework.beans.factory.parsing.ProblemReporter;
import org.springframework.core.type.MethodMetadata;
import org.springframework.lang.Nullable;
/**
* Represents a {@link Configuration @Configuration} class method marked with the
* {@link Bean @Bean} annotation.
* Represents a {@link Configuration @Configuration} class method annotated with
* {@link Bean @Bean}.
*
* @author Chris Beams
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
* @see ConfigurationClass
* @see ConfigurationClassParser
@@ -33,7 +35,7 @@ import org.springframework.core.type.MethodMetadata;
*/
final class BeanMethod extends ConfigurationMethod {
public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
super(metadata, configurationClass);
}
@@ -52,12 +54,28 @@ final class BeanMethod extends ConfigurationMethod {
}
}
@Override
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof BeanMethod) &&
this.metadata.equals(((BeanMethod) obj).metadata)));
}
@Override
public int hashCode() {
return this.metadata.hashCode();
}
@Override
public String toString() {
return "BeanMethod: " + this.metadata;
}
private class NonOverridableMethodError extends Problem {
public NonOverridableMethodError() {
NonOverridableMethodError() {
super(String.format("@Bean method '%s' must not be private or final; change the method's modifiers to continue",
getMetadata().getMethodName()), getResourceLocation());
}
}
}
@@ -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.
@@ -36,7 +36,7 @@ import org.springframework.util.ClassUtils;
/**
* Represents a user-defined {@link Configuration @Configuration} class.
* Includes a set of {@link Bean} methods, including all such methods
* <p>Includes a set of {@link Bean} methods, including all such methods
* defined in the ancestry of the class, in a 'flattened-out' manner.
*
* @author Chris Beams
@@ -74,7 +74,7 @@ final class ConfigurationClass {
* @param beanName must not be {@code null}
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(MetadataReader metadataReader, String beanName) {
ConfigurationClass(MetadataReader metadataReader, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
@@ -89,7 +89,7 @@ final class ConfigurationClass {
* @param importedBy the configuration class importing this one or {@code null}
* @since 3.1.1
*/
public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
this.importedBy.add(importedBy);
@@ -101,7 +101,7 @@ final class ConfigurationClass {
* @param beanName name of the {@code @Configuration} class bean
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(Class<?> clazz, String beanName) {
ConfigurationClass(Class<?> clazz, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
this.metadata = AnnotationMetadata.introspect(clazz);
this.resource = new DescriptiveResource(clazz.getName());
@@ -116,7 +116,7 @@ final class ConfigurationClass {
* @param importedBy the configuration class importing this one (or {@code null})
* @since 3.1.1
*/
public ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
ConfigurationClass(Class<?> clazz, @Nullable ConfigurationClass importedBy) {
this.metadata = AnnotationMetadata.introspect(clazz);
this.resource = new DescriptiveResource(clazz.getName());
this.importedBy.add(importedBy);
@@ -128,7 +128,7 @@ final class ConfigurationClass {
* @param beanName name of the {@code @Configuration} class bean
* @see ConfigurationClass#ConfigurationClass(Class, ConfigurationClass)
*/
public ConfigurationClass(AnnotationMetadata metadata, String beanName) {
ConfigurationClass(AnnotationMetadata metadata, String beanName) {
Assert.notNull(beanName, "Bean name must not be null");
this.metadata = metadata;
this.resource = new DescriptiveResource(metadata.getClassName());
@@ -136,19 +136,19 @@ final class ConfigurationClass {
}
public AnnotationMetadata getMetadata() {
AnnotationMetadata getMetadata() {
return this.metadata;
}
public Resource getResource() {
Resource getResource() {
return this.resource;
}
public String getSimpleName() {
String getSimpleName() {
return ClassUtils.getShortName(getMetadata().getClassName());
}
public void setBeanName(String beanName) {
void setBeanName(String beanName) {
this.beanName = beanName;
}
@@ -171,7 +171,7 @@ final class ConfigurationClass {
* Merge the imported-by declarations from the given configuration class into this one.
* @since 4.0.5
*/
public void mergeImportedBy(ConfigurationClass otherConfigClass) {
void mergeImportedBy(ConfigurationClass otherConfigClass) {
this.importedBy.addAll(otherConfigClass.importedBy);
}
@@ -181,35 +181,35 @@ final class ConfigurationClass {
* @since 4.0.5
* @see #isImported()
*/
public Set<ConfigurationClass> getImportedBy() {
Set<ConfigurationClass> getImportedBy() {
return this.importedBy;
}
public void addBeanMethod(BeanMethod method) {
void addBeanMethod(BeanMethod method) {
this.beanMethods.add(method);
}
public Set<BeanMethod> getBeanMethods() {
Set<BeanMethod> getBeanMethods() {
return this.beanMethods;
}
public void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
void addImportedResource(String importedResource, Class<? extends BeanDefinitionReader> readerClass) {
this.importedResources.put(importedResource, readerClass);
}
public void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
void addImportBeanDefinitionRegistrar(ImportBeanDefinitionRegistrar registrar, AnnotationMetadata importingClassMetadata) {
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
public Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> getImportBeanDefinitionRegistrars() {
Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> getImportBeanDefinitionRegistrars() {
return this.importBeanDefinitionRegistrars;
}
public Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
Map<String, Class<? extends BeanDefinitionReader>> getImportedResources() {
return this.importedResources;
}
public void validate(ProblemReporter problemReporter) {
void validate(ProblemReporter problemReporter) {
// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
@@ -244,7 +244,7 @@ final class ConfigurationClass {
*/
private class FinalConfigurationProblem extends Problem {
public FinalConfigurationProblem() {
FinalConfigurationProblem() {
super(String.format("@Configuration class '%s' may not be final. Remove the final modifier to continue.",
getSimpleName()), new Location(getResource(), getMetadata()));
}
@@ -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.
@@ -51,18 +51,9 @@ abstract class ConfigurationMethod {
return new Location(this.configurationClass.getResource(), this.metadata);
}
String getFullyQualifiedMethodName() {
return this.metadata.getDeclaringClassName() + "#" + this.metadata.getMethodName();
void validate(ProblemReporter problemReporter) {
}
static String getShortMethodName(String fullyQualifiedMethodName) {
return fullyQualifiedMethodName.substring(fullyQualifiedMethodName.indexOf('#') + 1);
}
public void validate(ProblemReporter problemReporter) {
}
@Override
public String toString() {
return String.format("[%s:name=%s,declaringClass=%s]",
@@ -396,7 +396,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
* @param message error message to append the HandlerMethod details to
*/
protected String getDetailedErrorMessage(Object bean, String message) {
StringBuilder sb = new StringBuilder(message).append("\n");
StringBuilder sb = new StringBuilder(message).append('\n');
sb.append("HandlerMethod details: \n");
sb.append("Bean [").append(bean.getClass().getName()).append("]\n");
sb.append("Method [").append(this.method.toGenericString()).append("]\n");
@@ -426,7 +426,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(bean, message));
sb.append("Resolved arguments: \n");
for (int i = 0; i < resolvedArgs.length; i++) {
sb.append("[").append(i).append("] ");
sb.append('[').append(i).append("] ");
if (resolvedArgs[i] == null) {
sb.append("[null] \n");
}
@@ -84,6 +84,7 @@ import org.springframework.core.annotation.AliasFor;
* @author Sam Brannen
* @since 4.2
* @see EventListenerMethodProcessor
* @see org.springframework.transaction.event.TransactionalEventListener
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@@ -133,7 +134,7 @@ public @interface EventListener {
* An optional identifier for the listener, defaulting to the fully-qualified
* signature of the declaring method (e.g. "mypackage.MyClass.myMethod()").
* @since 5.3.5
* @see org.springframework.context.ApplicationListener#getListenerId()
* @see SmartApplicationListener#getListenerId()
* @see ApplicationEventMulticaster#removeApplicationListeners(Predicate)
*/
String id() default "";
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -205,12 +205,12 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
}
}
result.append("]\n");
result.append("}");
result.append('}');
if (it.hasNext()) {
result.append(",\n");
}
}
result.append("]");
result.append(']');
return result.toString();
}
@@ -112,10 +112,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
*/
public void setCorePoolSize(int corePoolSize) {
synchronized (this.poolSizeMonitor) {
this.corePoolSize = corePoolSize;
if (this.threadPoolExecutor != null) {
this.threadPoolExecutor.setCorePoolSize(corePoolSize);
}
this.corePoolSize = corePoolSize;
}
}
@@ -135,10 +135,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
*/
public void setMaxPoolSize(int maxPoolSize) {
synchronized (this.poolSizeMonitor) {
this.maxPoolSize = maxPoolSize;
if (this.threadPoolExecutor != null) {
this.threadPoolExecutor.setMaximumPoolSize(maxPoolSize);
}
this.maxPoolSize = maxPoolSize;
}
}
@@ -158,10 +158,10 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
*/
public void setKeepAliveSeconds(int keepAliveSeconds) {
synchronized (this.poolSizeMonitor) {
this.keepAliveSeconds = keepAliveSeconds;
if (this.threadPoolExecutor != null) {
this.threadPoolExecutor.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS);
}
this.keepAliveSeconds = keepAliveSeconds;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -53,6 +53,8 @@ import org.springframework.util.concurrent.ListenableFutureTask;
* @since 3.0
* @see #setPoolSize
* @see #setRemoveOnCancelPolicy
* @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
* @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
* @see #setThreadFactory
* @see #setErrorHandler
*/
@@ -64,6 +66,10 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
private volatile boolean removeOnCancelPolicy;
private volatile boolean continueExistingPeriodicTasksAfterShutdownPolicy;
private volatile boolean executeExistingDelayedTasksAfterShutdownPolicy = true;
@Nullable
private volatile ErrorHandler errorHandler;
@@ -84,26 +90,54 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
*/
public void setPoolSize(int poolSize) {
Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher");
this.poolSize = poolSize;
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setCorePoolSize(poolSize);
}
this.poolSize = poolSize;
}
/**
* Set the remove-on-cancel mode on {@link ScheduledThreadPoolExecutor}.
* <p>Default is {@code false}. If set to {@code true}, the target executor will be
* switched into remove-on-cancel mode (if possible, with a soft fallback otherwise).
* switched into remove-on-cancel mode (if possible).
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
* @see ScheduledThreadPoolExecutor#setRemoveOnCancelPolicy
*/
public void setRemoveOnCancelPolicy(boolean removeOnCancelPolicy) {
this.removeOnCancelPolicy = removeOnCancelPolicy;
public void setRemoveOnCancelPolicy(boolean flag) {
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(removeOnCancelPolicy);
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(flag);
}
else if (removeOnCancelPolicy && this.scheduledExecutor != null) {
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
this.removeOnCancelPolicy = flag;
}
/**
* Set whether to continue existing periodic tasks even when this executor has been shutdown.
* <p>Default is {@code false}. If set to {@code true}, the target executor will be
* switched into continuing periodic tasks (if possible).
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
* @since 5.3.9
* @see ScheduledThreadPoolExecutor#setContinueExistingPeriodicTasksAfterShutdownPolicy
*/
public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean flag) {
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setContinueExistingPeriodicTasksAfterShutdownPolicy(flag);
}
this.continueExistingPeriodicTasksAfterShutdownPolicy = flag;
}
/**
* Set whether to execute existing delayed tasks even when this executor has been shutdown.
* <p>Default is {@code true}. If set to {@code false}, the target executor will be
* switched into dropping remaining tasks (if possible).
* <p><b>This setting can be modified at runtime, for example through JMX.</b>
* @since 5.3.9
* @see ScheduledThreadPoolExecutor#setExecuteExistingDelayedTasksAfterShutdownPolicy
*/
public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean flag) {
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setExecuteExistingDelayedTasksAfterShutdownPolicy(flag);
}
this.executeExistingDelayedTasksAfterShutdownPolicy = flag;
}
/**
@@ -135,12 +169,16 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
if (this.removeOnCancelPolicy) {
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
((ScheduledThreadPoolExecutor) this.scheduledExecutor).setRemoveOnCancelPolicy(true);
if (this.scheduledExecutor instanceof ScheduledThreadPoolExecutor) {
ScheduledThreadPoolExecutor scheduledPoolExecutor = (ScheduledThreadPoolExecutor) this.scheduledExecutor;
if (this.removeOnCancelPolicy) {
scheduledPoolExecutor.setRemoveOnCancelPolicy(true);
}
else {
logger.debug("Could not apply remove-on-cancel policy - not a ScheduledThreadPoolExecutor");
if (this.continueExistingPeriodicTasksAfterShutdownPolicy) {
scheduledPoolExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
}
if (!this.executeExistingDelayedTasksAfterShutdownPolicy) {
scheduledPoolExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
}
}
@@ -201,18 +239,6 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
return getScheduledThreadPoolExecutor().getPoolSize();
}
/**
* Return the current setting for the remove-on-cancel mode.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
*/
public boolean isRemoveOnCancelPolicy() {
if (this.scheduledExecutor == null) {
// Not initialized yet: return our setting for the time being.
return this.removeOnCancelPolicy;
}
return getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy();
}
/**
* Return the number of currently active threads.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
@@ -227,6 +253,21 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
return getScheduledThreadPoolExecutor().getActiveCount();
}
/**
* Return the current setting for the remove-on-cancel mode.
* <p>Requires an underlying {@link ScheduledThreadPoolExecutor}.
* @deprecated as of 5.3.9, in favor of direct
* {@link #getScheduledThreadPoolExecutor()} access
*/
@Deprecated
public boolean isRemoveOnCancelPolicy() {
if (this.scheduledExecutor == null) {
// Not initialized yet: return our setting for the time being.
return this.removeOnCancelPolicy;
}
return getScheduledThreadPoolExecutor().getRemoveOnCancelPolicy();
}
// SchedulingTaskExecutor implementation
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -192,6 +192,11 @@ final class BitsCronField extends CronField {
while (current != next && count++ < CronExpression.MAX_ATTEMPTS) {
temporal = type().elapseUntil(temporal, next);
current = type().get(temporal);
next = nextSetBit(current);
if (next == -1) {
temporal = type().rollForward(temporal);
next = nextSetBit(0);
}
}
if (count >= CronExpression.MAX_ATTEMPTS) {
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -66,8 +66,9 @@ public final class CronExpression {
CronField daysOfWeek,
String expression) {
// reverse order, to make big changes first
// to make sure we end up at 0 nanos, we add an extra field
this.fields = new CronField[]{CronField.zeroNanos(), seconds, minutes, hours, daysOfMonth, months, daysOfWeek};
this.fields = new CronField[]{daysOfWeek, months, daysOfMonth, hours, minutes, seconds, CronField.zeroNanos()};
this.expression = expression;
}
@@ -202,6 +203,25 @@ public final class CronExpression {
}
}
/**
* Determine whether the given string represents a valid cron expression.
* @param expression the expression to evaluate
* @return {@code true} if the given expression is a valid cron expression
* @since 5.3.8
*/
public static boolean isValidExpression(@Nullable String expression) {
if (expression == null) {
return false;
}
try {
parse(expression);
return true;
}
catch (IllegalArgumentException ex) {
return false;
}
}
private static String resolveMacros(String expression) {
expression = expression.trim();
@@ -230,9 +230,7 @@ abstract class CronField {
* Elapse the given temporal for the difference between the current
* value of this field and the goal value. Typically, the returned
* temporal will have the given goal as the current value for this type,
* but this is not the case for {@link #DAY_OF_MONTH}. For instance,
* if {@code goal} is 31, and {@code temporal} is April 16th,
* this method returns May 1st, because April 31st does not exist.
* but this is not the case for {@link #DAY_OF_MONTH}.
* @param temporal the temporal to elapse
* @param goal the goal value
* @param <T> the type of temporal
@@ -247,8 +245,9 @@ abstract class CronField {
return cast(temporal.with(this.field, goal));
}
else {
// goal is invalid, eg. 29th Feb, lets try to get as close as possible
return this.field.getBaseUnit().addTo(temporal, goal - current);
// goal is invalid, eg. 29th Feb, so roll forward
long amount = range.getMaximum() - current + 1;
return this.field.getBaseUnit().addTo(temporal, amount);
}
}
else {
@@ -334,6 +334,9 @@ final class QuartzCronField extends CronField {
// We ended up before the start, roll forward and try again
temporal = this.rollForwardType.rollForward(temporal);
result = adjust(temporal);
if (result != null) {
result = type().reset(result);
}
}
}
return result;
@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.validation.support;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.ui.ConcurrentModel;
import org.springframework.validation.BindingResult;
@@ -36,17 +37,19 @@ import org.springframework.validation.BindingResult;
* @author Rossen Stoyanchev
* @since 5.0
* @see BindingResult
* @see BindingAwareModelMap
*/
@SuppressWarnings("serial")
public class BindingAwareConcurrentModel extends ConcurrentModel {
@Override
public Object put(String key, Object value) {
@Nullable
public Object put(String key, @Nullable Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}
private void removeBindingResultIfNecessary(String key, Object value) {
private void removeBindingResultIfNecessary(String key, @Nullable Object value) {
if (!key.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
String resultKey = BindingResult.MODEL_KEY_PREFIX + key;
BindingResult result = (BindingResult) get(resultKey);
@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.validation.support;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.validation.BindingResult;
@@ -39,7 +40,7 @@ import org.springframework.validation.BindingResult;
public class BindingAwareModelMap extends ExtendedModelMap {
@Override
public Object put(String key, Object value) {
public Object put(String key, @Nullable Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}
@@ -50,7 +51,7 @@ public class BindingAwareModelMap extends ExtendedModelMap {
super.putAll(map);
}
private void removeBindingResultIfNecessary(Object key, Object value) {
private void removeBindingResultIfNecessary(Object key, @Nullable Object value) {
if (key instanceof String) {
String attributeName = (String) key;
if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
@@ -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.
@@ -1110,7 +1110,7 @@ open class BeanDefinitionDsl internal constructor (private val init: BeanDefinit
}
/**
* Return an provider for the specified bean, allowing for lazy on-demand retrieval
* Return a provider for the specified bean, allowing for lazy on-demand retrieval
* of instances, including availability and uniqueness options.
* @see org.springframework.beans.factory.BeanFactory.getBeanProvider
*/
@@ -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.
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanFactory;
@@ -219,7 +220,7 @@ public class AutoProxyCreatorTests {
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("proxyFactoryBean", "false");
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs);
sac.registerSingleton("testAutoProxyCreator", IntroductionTestAutoProxyCreator.class, pvs);
sac.registerSingleton("noInterfaces", NoInterfaces.class);
sac.registerSingleton("containerCallbackInterfacesOnly", ContainerCallbackInterfacesOnly.class);
@@ -248,9 +249,9 @@ public class AutoProxyCreatorTests {
singletonNoInterceptor.getName();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(0);
singletonToBeProxied.getAge();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(1);
prototypeToBeProxied.getSpouse();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(2);
prototypeToBeProxied.getSpouse();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(4);
}
@Test
@@ -404,7 +405,7 @@ public class AutoProxyCreatorTests {
else if (name.endsWith("ToBeProxied")) {
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) {
return new Object[] {this.testInterceptor};
return getAdvicesAndAdvisors();
}
else {
return DO_NOT_PROXY;
@@ -414,6 +415,10 @@ public class AutoProxyCreatorTests {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
}
protected Object[] getAdvicesAndAdvisors() {
return new Object[] {this.testInterceptor};
}
}
@@ -426,6 +431,17 @@ public class AutoProxyCreatorTests {
}
@SuppressWarnings("serial")
public static class IntroductionTestAutoProxyCreator extends TestAutoProxyCreator {
protected Object[] getAdvicesAndAdvisors() {
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(this.testInterceptor);
advisor.addInterface(Serializable.class);
return new Object[] {this.testInterceptor, advisor};
}
}
/**
* Interceptor that counts the number of non-finalize method calls.
*/
@@ -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.
@@ -47,8 +47,9 @@ import static org.springframework.util.ClassUtils.convertClassNameToResourcePath
public class QualifierAnnotationTests {
private static final String CLASSNAME = QualifierAnnotationTests.class.getName();
private static final String CONFIG_LOCATION =
format("classpath:%s-context.xml", convertClassNameToResourcePath(CLASSNAME));
format("classpath:%s-context.xml", convertClassNameToResourcePath(CLASSNAME));
@Test
@@ -146,7 +146,7 @@ class XmlBeanFactoryTests {
assertThat(emmasJenks != georgiasJenks).as("Emma and georgia think they have a different boyfriend").isTrue();
assertThat(emmasJenks.getName().equals("Andrew")).as("Emmas jenks has right name").isTrue();
assertThat(emmasJenks != xbf.getBean("jenks")).as("Emmas doesn't equal new ref").isTrue();
assertThat(emmasJenks.getName().equals("Andrew")).as("Georgias jenks has right name").isTrue();
assertThat(georgiasJenks.getName().equals("Andrew")).as("Georgias jenks has right name").isTrue();
assertThat(emmasJenks.equals(georgiasJenks)).as("They are object equal").isTrue();
assertThat(emmasJenks.equals(xbf.getBean("jenks"))).as("They object equal direct ref").isTrue();
}
@@ -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.
@@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests regarding overloading and overriding of bean methods.
* Related to SPR-6618.
* <p>Related to SPR-6618.
*
* @author Chris Beams
* @author Phillip Webb
@@ -41,7 +41,7 @@ public class BeanMethodPolymorphismTests {
@Test
public void beanMethodDetectedOnSuperClass() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean("testBean", TestBean.class);
assertThat(ctx.getBean("testBean", TestBean.class)).isNotNull();
}
@Test
@@ -0,0 +1,202 @@
/*
* 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.
* 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.context.annotation;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link ConfigurationClassParser}, {@link ConfigurationClass},
* and {@link BeanMethod}.
*
* @author Sam Brannen
* @since 5.3.9
*/
class ConfigurationClassAndBeanMethodTests {
@Test
void verifyEquals() throws Exception {
ConfigurationClass configurationClass1 = newConfigurationClass(Config1.class);
ConfigurationClass configurationClass2 = newConfigurationClass(Config1.class);
ConfigurationClass configurationClass3 = newConfigurationClass(Config2.class);
assertThat(configurationClass1.equals(null)).isFalse();
assertThat(configurationClass1).isNotSameAs(configurationClass2);
assertThat(configurationClass1.equals(configurationClass1)).isTrue();
assertThat(configurationClass2.equals(configurationClass2)).isTrue();
assertThat(configurationClass1.equals(configurationClass2)).isTrue();
assertThat(configurationClass2.equals(configurationClass1)).isTrue();
assertThat(configurationClass1.equals(configurationClass3)).isFalse();
assertThat(configurationClass3.equals(configurationClass2)).isFalse();
// ---------------------------------------------------------------------
List<BeanMethod> beanMethods1 = getBeanMethods(configurationClass1);
BeanMethod beanMethod_1_0 = beanMethods1.get(0);
BeanMethod beanMethod_1_1 = beanMethods1.get(1);
BeanMethod beanMethod_1_2 = beanMethods1.get(2);
List<BeanMethod> beanMethods2 = getBeanMethods(configurationClass2);
BeanMethod beanMethod_2_0 = beanMethods2.get(0);
BeanMethod beanMethod_2_1 = beanMethods2.get(1);
BeanMethod beanMethod_2_2 = beanMethods2.get(2);
List<BeanMethod> beanMethods3 = getBeanMethods(configurationClass3);
BeanMethod beanMethod_3_0 = beanMethods3.get(0);
BeanMethod beanMethod_3_1 = beanMethods3.get(1);
BeanMethod beanMethod_3_2 = beanMethods3.get(2);
assertThat(beanMethod_1_0.equals(null)).isFalse();
assertThat(beanMethod_1_0).isNotSameAs(beanMethod_2_0);
assertThat(beanMethod_1_0.equals(beanMethod_1_0)).isTrue();
assertThat(beanMethod_1_0.equals(beanMethod_2_0)).isTrue();
assertThat(beanMethod_1_1.equals(beanMethod_2_1)).isTrue();
assertThat(beanMethod_1_2.equals(beanMethod_2_2)).isTrue();
assertThat(beanMethod_1_0.getMetadata().getMethodName()).isEqualTo(beanMethod_3_0.getMetadata().getMethodName());
assertThat(beanMethod_1_0.equals(beanMethod_3_0)).isFalse();
assertThat(beanMethod_1_1.equals(beanMethod_3_1)).isFalse();
assertThat(beanMethod_1_2.equals(beanMethod_3_2)).isFalse();
}
@Test
void verifyHashCode() throws Exception {
ConfigurationClass configurationClass1 = newConfigurationClass(Config1.class);
ConfigurationClass configurationClass2 = newConfigurationClass(Config1.class);
ConfigurationClass configurationClass3 = newConfigurationClass(Config2.class);
assertThat(configurationClass1).hasSameHashCodeAs(configurationClass2);
assertThat(configurationClass1).doesNotHaveSameHashCodeAs(configurationClass3);
// ---------------------------------------------------------------------
List<BeanMethod> beanMethods1 = getBeanMethods(configurationClass1);
BeanMethod beanMethod_1_0 = beanMethods1.get(0);
BeanMethod beanMethod_1_1 = beanMethods1.get(1);
BeanMethod beanMethod_1_2 = beanMethods1.get(2);
List<BeanMethod> beanMethods2 = getBeanMethods(configurationClass2);
BeanMethod beanMethod_2_0 = beanMethods2.get(0);
BeanMethod beanMethod_2_1 = beanMethods2.get(1);
BeanMethod beanMethod_2_2 = beanMethods2.get(2);
List<BeanMethod> beanMethods3 = getBeanMethods(configurationClass3);
BeanMethod beanMethod_3_0 = beanMethods3.get(0);
BeanMethod beanMethod_3_1 = beanMethods3.get(1);
BeanMethod beanMethod_3_2 = beanMethods3.get(2);
assertThat(beanMethod_1_0).hasSameHashCodeAs(beanMethod_2_0);
assertThat(beanMethod_1_1).hasSameHashCodeAs(beanMethod_2_1);
assertThat(beanMethod_1_2).hasSameHashCodeAs(beanMethod_2_2);
assertThat(beanMethod_1_0).doesNotHaveSameHashCodeAs(beanMethod_3_0);
assertThat(beanMethod_1_1).doesNotHaveSameHashCodeAs(beanMethod_3_1);
assertThat(beanMethod_1_2).doesNotHaveSameHashCodeAs(beanMethod_3_2);
}
@Test
void verifyToString() throws Exception {
ConfigurationClass configurationClass = newConfigurationClass(Config1.class);
assertThat(configurationClass.toString())
.startsWith("ConfigurationClass: beanName 'Config1', class path resource");
List<BeanMethod> beanMethods = getBeanMethods(configurationClass);
String prefix = "BeanMethod: " + Config1.class.getName();
assertThat(beanMethods.get(0).toString()).isEqualTo(prefix + ".bean0()");
assertThat(beanMethods.get(1).toString()).isEqualTo(prefix + ".bean1(java.lang.String)");
assertThat(beanMethods.get(2).toString()).isEqualTo(prefix + ".bean2(java.lang.String,java.lang.Integer)");
}
private static ConfigurationClass newConfigurationClass(Class<?> clazz) throws Exception {
ConfigurationClassParser parser = newParser();
parser.parse(clazz.getName(), clazz.getSimpleName());
assertThat(parser.getConfigurationClasses()).hasSize(1);
return parser.getConfigurationClasses().iterator().next();
}
private static ConfigurationClassParser newParser() {
return new ConfigurationClassParser(
new CachingMetadataReaderFactory(),
new FailFastProblemReporter(),
new StandardEnvironment(),
new DefaultResourceLoader(),
new AnnotationBeanNameGenerator(),
new DefaultListableBeanFactory());
}
private static List<BeanMethod> getBeanMethods(ConfigurationClass configurationClass) {
List<BeanMethod> beanMethods = configurationClass.getBeanMethods().stream()
.sorted(Comparator.comparing(beanMethod -> beanMethod.getMetadata().getMethodName()))
.collect(Collectors.toList());
assertThat(beanMethods).hasSize(3);
return beanMethods;
}
static class Config1 {
@Bean
String bean0() {
return "";
}
@Bean
String bean1(String text) {
return "";
}
@Bean
String bean2(String text, Integer num) {
return "";
}
}
static class Config2 {
@Bean
String bean0() {
return "";
}
@Bean
String bean1(String text) {
return "";
}
@Bean
String bean2(String text, Integer num) {
return "";
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -16,21 +16,100 @@
package org.springframework.scheduling.concurrent;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* @author Juergen Hoeller
* @since 5.0.5
*/
class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
private final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
@Override
protected AsyncListenableTaskExecutor buildExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix(this.threadNamePrefix);
executor.setMaxPoolSize(1);
executor.afterPropertiesSet();
return executor;
}
@Test
void modifyCorePoolSizeWhileRunning() {
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
executor.setCorePoolSize(0);
assertThat(executor.getCorePoolSize()).isEqualTo(0);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(0);
}
@Test
void modifyCorePoolSizeWithInvalidValueWhileRunning() {
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
assertThatThrownBy(() -> executor.setCorePoolSize(-1))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getCorePoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getCorePoolSize()).isEqualTo(1);
}
@Test
void modifyMaxPoolSizeWhileRunning() {
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
executor.setMaxPoolSize(5);
assertThat(executor.getMaxPoolSize()).isEqualTo(5);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(5);
}
@Test
void modifyMaxPoolSizeWithInvalidValueWhileRunning() {
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
assertThatThrownBy(() -> executor.setMaxPoolSize(0))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getMaxPoolSize()).isEqualTo(1);
assertThat(executor.getThreadPoolExecutor().getMaximumPoolSize()).isEqualTo(1);
}
@Test
void modifyKeepAliveSecondsWhileRunning() {
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
executor.setKeepAliveSeconds(10);
assertThat(executor.getKeepAliveSeconds()).isEqualTo(10);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(10);
}
@Test
void modifyKeepAliveSecondsWithInvalidValueWhileRunning() {
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
assertThatThrownBy(() -> executor.setKeepAliveSeconds(-10))
.isInstanceOf(IllegalArgumentException.class);
assertThat(executor.getKeepAliveSeconds()).isEqualTo(60);
assertThat(executor.getThreadPoolExecutor().getKeepAliveTime(TimeUnit.SECONDS)).isEqualTo(60);
}
}
@@ -51,6 +51,16 @@ class CronExpressionTests {
}
};
@Test
public void isValidExpression() {
assertThat(CronExpression.isValidExpression(null)).isFalse();
assertThat(CronExpression.isValidExpression("")).isFalse();
assertThat(CronExpression.isValidExpression("*")).isFalse();
assertThat(CronExpression.isValidExpression("* * * * *")).isFalse();
assertThat(CronExpression.isValidExpression("* * * * * * *")).isFalse();
assertThat(CronExpression.isValidExpression("* * * * * *")).isTrue();
}
@Test
void matchAll() {
@@ -497,6 +507,29 @@ class CronExpressionTests {
assertThat(actual.getDayOfMonth()).isEqualTo(13);
}
@Test
public void everyTenDays() {
CronExpression cronExpression = CronExpression.parse("0 15 12 */10 1-8 5");
LocalDateTime last = LocalDateTime.parse("2021-04-30T12:14:59");
LocalDateTime expected = LocalDateTime.parse("2021-05-21T12:15");
LocalDateTime actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.parse("2021-06-11T12:15");
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
last = actual;
expected = LocalDateTime.parse("2022-01-21T12:15");
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
}
@Test
void yearly() {
CronExpression expression = CronExpression.parse("@yearly");
@@ -1286,6 +1319,21 @@ class CronExpressionTests {
assertThat(actual).isEqualTo(expected);
}
@Test
public void various() {
CronExpression cronExpression = CronExpression.parse("3-57 13-28 17,18 1,15 3-12 6#1");
LocalDateTime last = LocalDateTime.of(2022, 9, 15, 17, 44, 11);
LocalDateTime expected = LocalDateTime.of(2022, 10, 1, 17, 13, 3);
LocalDateTime actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
cronExpression = CronExpression.parse("*/28 56 22 */6 * *");
last = LocalDateTime.of(2022, 2, 27, 8, 0, 42);
expected = LocalDateTime.of(2022, 3, 1, 22, 56, 0);
actual = cronExpression.next(last);
assertThat(actual).isNotNull();
assertThat(actual).isEqualTo(expected);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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,10 +17,7 @@
@file:JvmName("CoroutinesUtils")
package org.springframework.core
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.reactive.awaitSingleOrNull
import kotlinx.coroutines.reactor.asFlux
@@ -48,6 +45,8 @@ internal fun <T: Any> deferredToMono(source: Deferred<T>) =
* @author Sebastien Deleuze
* @since 5.2
*/
@Suppress("DEPRECATION")
@OptIn(DelicateCoroutinesApi::class)
internal fun <T: Any> monoToDeferred(source: Mono<T>) =
GlobalScope.async(Dispatchers.Unconfined) { source.awaitSingleOrNull() }
@@ -88,6 +88,9 @@ public class ClassReader {
*/
static final int EXPAND_ASM_INSNS = 256;
/** The maximum size of array to allocate. */
private static final int MAX_BUFFER_SIZE = 1024 * 1024;
/** The size of the temporary byte array used to read class input streams chunk by chunk. */
private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
@@ -191,7 +194,7 @@ public class ClassReader {
this.b = classFileBuffer;
// Check the class' major_version. This field is after the magic and minor_version fields, which
// use 4 and 2 bytes respectively.
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V17) {
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V18) {
throw new IllegalArgumentException(
"Unsupported class file major version " + readShort(classFileOffset + 6));
}
@@ -310,13 +313,19 @@ public class ClassReader {
if (inputStream == null) {
throw new IOException("Class not found");
}
int bufferSize = calculateBufferSize(inputStream);
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
byte[] data = new byte[bufferSize];
int bytesRead;
while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
int readCount = 0;
while ((bytesRead = inputStream.read(data, 0, bufferSize)) != -1) {
outputStream.write(data, 0, bytesRead);
readCount++;
}
outputStream.flush();
if (readCount == 1) {
return data;
}
return outputStream.toByteArray();
} finally {
if (close) {
@@ -325,6 +334,20 @@ public class ClassReader {
}
}
private static int calculateBufferSize(final InputStream inputStream) throws IOException {
int expectedLength = inputStream.available();
/*
* Some implementations can return 0 while holding available data
* (e.g. new FileInputStream("/proc/a_file"))
* Also in some pathological cases a very small number might be returned,
* and in this case we use default size
*/
if (expectedLength < 256) {
return INPUT_STREAM_DATA_CHUNK_SIZE;
}
return Math.min(expectedLength, MAX_BUFFER_SIZE);
}
// -----------------------------------------------------------------------------------------------
// Accessors
// -----------------------------------------------------------------------------------------------
@@ -3456,7 +3479,6 @@ public class ClassReader {
private int[] readBootstrapMethodsAttribute(final int maxStringLength) {
char[] charBuffer = new char[maxStringLength];
int currentAttributeOffset = getFirstAttributeOffset();
int[] currentBootstrapMethodOffsets = null;
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
// Read the attribute_info's attribute_name and attribute_length fields.
String attributeName = readUTF8(currentAttributeOffset, charBuffer);
@@ -3464,17 +3486,17 @@ public class ClassReader {
currentAttributeOffset += 6;
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
// Read the num_bootstrap_methods field and create an array of this size.
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
int[] result = new int[readUnsignedShort(currentAttributeOffset)];
// Compute and store the offset of each 'bootstrap_methods' array field entry.
int currentBootstrapMethodOffset = currentAttributeOffset + 2;
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
for (int j = 0; j < result.length; ++j) {
result[j] = currentBootstrapMethodOffset;
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
currentBootstrapMethodOffset +=
4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
}
return currentBootstrapMethodOffsets;
return result;
}
currentAttributeOffset += attributeLength;
}
@@ -30,8 +30,8 @@ package org.springframework.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in the following order:
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
* visitPermittedSubclass} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
* visitAttribute} )* ( {@code visitNestMember} | [ {@code * visitPermittedSubclass} ] | {@code
* visitInnerClass} | {@code visitRecordComponent} | {@code visitField} | {@code visitMethod} )*
* {@code visitEnd}.
*
@@ -79,7 +79,7 @@ public class ClassWriter extends ClassVisitor {
/**
* The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {}@link Opcodes#ACC_RECORD}, which are
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {@link Opcodes#ACC_RECORD}, which are
* removed when generating the ClassFile structure.
*/
private int accessFlags;
@@ -282,6 +282,7 @@ public interface Opcodes {
int V15 = 0 << 16 | 59;
int V16 = 0 << 16 | 60;
int V17 = 0 << 16 | 61;
int V18 = 0 << 16 | 62;
/**
* Version flag indicating that the class is using 'preview' features.
@@ -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.
@@ -324,7 +324,7 @@ public class Constants {
for (int i = 0; i < propertyName.length(); i++) {
char c = propertyName.charAt(i);
if (Character.isUpperCase(c)) {
parsedPrefix.append("_");
parsedPrefix.append('_');
parsedPrefix.append(c);
}
else {
@@ -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.
@@ -394,9 +394,11 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
sb.append(entry.getKey());
sb.append('=');
sb.append(valueToString(entry.getValue()));
sb.append(entries.hasNext() ? ", " : "");
if (entries.hasNext()) {
sb.append(", ");
}
}
sb.append("}");
sb.append('}');
return sb.toString();
}
@@ -177,17 +177,17 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
private String annotationToString() {
String string = this.string;
if (string == null) {
StringBuilder builder = new StringBuilder("@").append(this.type.getName()).append("(");
StringBuilder builder = new StringBuilder("@").append(this.type.getName()).append('(');
for (int i = 0; i < this.attributes.size(); i++) {
Method attribute = this.attributes.get(i);
if (i > 0) {
builder.append(", ");
}
builder.append(attribute.getName());
builder.append("=");
builder.append('=');
builder.append(toString(getAttributeValue(attribute)));
}
builder.append(")");
builder.append(')');
string = builder.toString();
this.string = string;
}
@@ -206,7 +206,7 @@ final class SynthesizedMergedAnnotationInvocationHandler<A extends Annotation> i
}
builder.append(toString(Array.get(value, i)));
}
builder.append("]");
builder.append(']');
return builder.toString();
}
return String.valueOf(value);
@@ -513,7 +513,7 @@ public class TypeDescriptor implements Serializable {
public String toString() {
StringBuilder builder = new StringBuilder();
for (Annotation ann : getAnnotations()) {
builder.append("@").append(ann.annotationType().getName()).append(' ');
builder.append('@').append(ann.annotationType().getName()).append(' ');
}
builder.append(getResolvableType());
return builder.toString();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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,7 @@ public abstract class DataBufferUtils {
//---------------------------------------------------------------------
/**
* Obtain a {@link InputStream} from the given supplier, and read it into a
* Obtain an {@link InputStream} from the given supplier, and read it into a
* {@code Flux} of {@code DataBuffer}s. Closes the input stream when the
* Flux is terminated.
* @param inputStreamSupplier the supplier for the input stream to read from
@@ -125,7 +125,7 @@ public abstract class DataBufferUtils {
}
/**
* Obtain a {@code AsynchronousFileChannel} from the given supplier, and
* Obtain an {@code AsynchronousFileChannel} from the given supplier, and
* read it into a {@code Flux} of {@code DataBuffer}s, starting at the given
* position. Closes the channel when the Flux is terminated.
* @param channelSupplier the supplier for the channel to read from
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -29,16 +29,16 @@ import java.util.function.Supplier;
*/
class DefaultApplicationStartup implements ApplicationStartup {
private static final DefaultStartupStep DEFAULT_STARTUP_STEP = new DefaultStartupStep();
@Override
public DefaultStartupStep start(String name) {
return new DefaultStartupStep();
return DEFAULT_STARTUP_STEP;
}
static class DefaultStartupStep implements StartupStep {
boolean recorded = false;
private final DefaultTags TAGS = new DefaultTags();
@Override
@@ -63,23 +63,17 @@ class DefaultApplicationStartup implements ApplicationStartup {
@Override
public StartupStep tag(String key, String value) {
if (this.recorded) {
throw new IllegalArgumentException();
}
return this;
}
@Override
public StartupStep tag(String key, Supplier<String> value) {
if (this.recorded) {
throw new IllegalArgumentException();
}
return this;
}
@Override
public void end() {
this.recorded = true;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -16,8 +16,9 @@
package org.springframework.core.metrics.jfr;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.metrics.StartupStep;
@@ -37,24 +38,23 @@ import org.springframework.core.metrics.StartupStep;
*/
public class FlightRecorderApplicationStartup implements ApplicationStartup {
private long currentSequenceId;
private final AtomicLong currentSequenceId = new AtomicLong(0);
private final Deque<Long> currentSteps;
public FlightRecorderApplicationStartup() {
this.currentSequenceId = 0;
this.currentSteps = new ArrayDeque<>();
this.currentSteps.offerFirst(0L);
this.currentSteps = new ConcurrentLinkedDeque<>();
this.currentSteps.offerFirst(this.currentSequenceId.get());
}
@Override
public StartupStep start(String name) {
FlightRecorderStartupStep step = new FlightRecorderStartupStep(++this.currentSequenceId, name,
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirst());
this.currentSteps.offerFirst(this.currentSequenceId);
return step;
long sequenceId = this.currentSequenceId.incrementAndGet();
this.currentSteps.offerFirst(sequenceId);
return new FlightRecorderStartupStep(sequenceId, name,
this.currentSteps.getFirst(), committedStep -> this.currentSteps.removeFirstOccurrence(sequenceId));
}
}
@@ -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.
@@ -18,7 +18,7 @@ package org.springframework.core.type;
/**
* Interface that defines abstract access to the annotations of a specific
* class, in a form that does not require that class to be loaded yet.
* method, in a form that does not require that method's class to be loaded yet.
*
* @author Juergen Hoeller
* @author Mark Pollack
@@ -32,42 +32,42 @@ package org.springframework.core.type;
public interface MethodMetadata extends AnnotatedTypeMetadata {
/**
* Return the name of the method.
* Get the name of the underlying method.
*/
String getMethodName();
/**
* Return the fully-qualified name of the class that declares this method.
* Get the fully-qualified name of the class that declares the underlying method.
*/
String getDeclaringClassName();
/**
* Return the fully-qualified name of this method's declared return type.
* Get the fully-qualified name of the underlying method's declared return type.
* @since 4.2
*/
String getReturnTypeName();
/**
* Return whether the underlying method is effectively abstract:
* i.e. marked as abstract on a class or declared as a regular,
* Determine whether the underlying method is effectively abstract:
* i.e. marked as abstract in a class or declared as a regular,
* non-default method in an interface.
* @since 4.2
*/
boolean isAbstract();
/**
* Return whether the underlying method is declared as 'static'.
* Determine whether the underlying method is declared as 'static'.
*/
boolean isStatic();
/**
* Return whether the underlying method is marked as 'final'.
* Determine whether the underlying method is marked as 'final'.
*/
boolean isFinal();
/**
* Return whether the underlying method is overridable,
* i.e. not marked as static, final or private.
* Determine whether the underlying method is overridable,
* i.e. not marked as static, final, or private.
*/
boolean isOverridable();
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -165,12 +165,12 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return annotatedMethods != null ? annotatedMethods : Collections.emptySet();
}
private boolean isAnnotatedMethod(Method method, String annotationName) {
private static boolean isAnnotatedMethod(Method method, String annotationName) {
return !method.isBridge() && method.getAnnotations().length > 0 &&
AnnotatedElementUtils.isAnnotated(method, annotationName);
}
static AnnotationMetadata from(Class<?> introspectedClass) {
return new StandardAnnotationMetadata(introspectedClass, true);
}
@@ -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.
@@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
* to introspect a given {@code Class}.
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 2.5
*/
public class StandardClassMetadata implements ClassMetadata {
@@ -119,4 +120,20 @@ public class StandardClassMetadata implements ClassMetadata {
return StringUtils.toStringArray(memberClassNames);
}
@Override
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof StandardClassMetadata) &&
getIntrospectedClass().equals(((StandardClassMetadata) obj).getIntrospectedClass())));
}
@Override
public int hashCode() {
return getIntrospectedClass().hashCode();
}
@Override
public String toString() {
return getClassName();
}
}
@@ -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.
@@ -36,6 +36,7 @@ import org.springframework.util.MultiValueMap;
* @author Mark Pollack
* @author Chris Beams
* @author Phillip Webb
* @author Sam Brannen
* @since 3.0
*/
public class StandardMethodMetadata implements MethodMetadata {
@@ -150,4 +151,20 @@ public class StandardMethodMetadata implements MethodMetadata {
annotationName, classValuesAsString, false);
}
@Override
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof StandardMethodMetadata) &&
this.introspectedMethod.equals(((StandardMethodMetadata) obj).introspectedMethod)));
}
@Override
public int hashCode() {
return this.introspectedMethod.hashCode();
}
@Override
public String toString() {
return this.introspectedMethod.toString();
}
}
@@ -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.
@@ -23,7 +23,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.SpringAsmInfo;
@@ -121,7 +120,7 @@ class MergedAnnotationReadingVisitor<A extends Annotation> extends AnnotationVis
@SuppressWarnings("unchecked")
@Nullable
static <A extends Annotation> AnnotationVisitor get(@Nullable ClassLoader classLoader,
@Nullable Supplier<Object> sourceSupplier, String descriptor, boolean visible,
@Nullable Object source, String descriptor, boolean visible,
Consumer<MergedAnnotation<A>> consumer) {
if (!visible) {
@@ -133,7 +132,6 @@ class MergedAnnotationReadingVisitor<A extends Annotation> extends AnnotationVis
return null;
}
Object source = (sourceSupplier != null ? sourceSupplier.get() : null);
try {
Class<A> annotationType = (Class<A>) ClassUtils.forName(typeName, classLoader);
return new MergedAnnotationReadingVisitor<>(classLoader, source, annotationType, consumer);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -31,6 +31,7 @@ import org.springframework.lang.Nullable;
* {@link SimpleAnnotationMetadataReadingVisitor}.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2
*/
final class SimpleAnnotationMetadata implements AnnotationMetadata {
@@ -156,4 +157,20 @@ final class SimpleAnnotationMetadata implements AnnotationMetadata {
return this.annotations;
}
@Override
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof SimpleAnnotationMetadata) &&
this.className.equals(((SimpleAnnotationMetadata) obj).className)));
}
@Override
public int hashCode() {
return this.className.hashCode();
}
@Override
public String toString() {
return this.className;
}
}
@@ -117,7 +117,7 @@ final class SimpleAnnotationMetadataReadingVisitor extends ClassVisitor {
@Override
@Nullable
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
return MergedAnnotationReadingVisitor.get(this.classLoader, this::getSource,
return MergedAnnotationReadingVisitor.get(this.classLoader, getSource(),
descriptor, visible, this.annotations::add);
}
@@ -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.
@@ -19,12 +19,13 @@ package org.springframework.core.type.classreading;
import org.springframework.asm.Opcodes;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.MethodMetadata;
import org.springframework.lang.Nullable;
/**
* {@link MethodMetadata} created from a
* {@link SimpleMethodMetadataReadingVisitor}.
* {@link MethodMetadata} created from a {@link SimpleMethodMetadataReadingVisitor}.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2
*/
final class SimpleMethodMetadata implements MethodMetadata {
@@ -37,16 +38,20 @@ final class SimpleMethodMetadata implements MethodMetadata {
private final String returnTypeName;
// The source implements equals(), hashCode(), and toString() for the underlying method.
private final Object source;
private final MergedAnnotations annotations;
public SimpleMethodMetadata(String methodName, int access, String declaringClassName,
String returnTypeName, MergedAnnotations annotations) {
SimpleMethodMetadata(String methodName, int access, String declaringClassName,
String returnTypeName, Object source, MergedAnnotations annotations) {
this.methodName = methodName;
this.access = access;
this.declaringClassName = declaringClassName;
this.returnTypeName = returnTypeName;
this.source = source;
this.annotations = annotations;
}
@@ -86,7 +91,7 @@ final class SimpleMethodMetadata implements MethodMetadata {
return !isStatic() && !isFinal() && !isPrivate();
}
public boolean isPrivate() {
private boolean isPrivate() {
return (this.access & Opcodes.ACC_PRIVATE) != 0;
}
@@ -95,4 +100,20 @@ final class SimpleMethodMetadata implements MethodMetadata {
return this.annotations;
}
@Override
public boolean equals(@Nullable Object obj) {
return ((this == obj) || ((obj instanceof SimpleMethodMetadata) &&
this.source.equals(((SimpleMethodMetadata) obj).source)));
}
@Override
public int hashCode() {
return this.source.hashCode();
}
@Override
public String toString() {
return this.source.toString();
}
}
@@ -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.
@@ -32,6 +32,7 @@ import org.springframework.lang.Nullable;
* ASM method visitor that creates {@link SimpleMethodMetadata}.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 5.2
*/
final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
@@ -43,7 +44,7 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
private final int access;
private final String name;
private final String methodName;
private final String descriptor;
@@ -56,13 +57,13 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
SimpleMethodMetadataReadingVisitor(@Nullable ClassLoader classLoader, String declaringClassName,
int access, String name, String descriptor, Consumer<SimpleMethodMetadata> consumer) {
int access, String methodName, String descriptor, Consumer<SimpleMethodMetadata> consumer) {
super(SpringAsmInfo.ASM_VERSION);
this.classLoader = classLoader;
this.declaringClassName = declaringClassName;
this.access = access;
this.name = name;
this.methodName = methodName;
this.descriptor = descriptor;
this.consumer = consumer;
}
@@ -71,7 +72,7 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
@Override
@Nullable
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
return MergedAnnotationReadingVisitor.get(this.classLoader, this::getSource,
return MergedAnnotationReadingVisitor.get(this.classLoader, getSource(),
descriptor, visible, this.annotations::add);
}
@@ -80,8 +81,8 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
if (!this.annotations.isEmpty()) {
String returnTypeName = Type.getReturnType(this.descriptor).getClassName();
MergedAnnotations annotations = MergedAnnotations.of(this.annotations);
SimpleMethodMetadata metadata = new SimpleMethodMetadata(this.name,
this.access, this.declaringClassName, returnTypeName, annotations);
SimpleMethodMetadata metadata = new SimpleMethodMetadata(this.methodName, this.access,
this.declaringClassName, returnTypeName, getSource(), annotations);
this.consumer.accept(metadata);
}
}
@@ -89,7 +90,7 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
private Object getSource() {
Source source = this.source;
if (source == null) {
source = new Source(this.declaringClassName, this.name, this.descriptor);
source = new Source(this.declaringClassName, this.methodName, this.descriptor);
this.source = source;
}
return source;
@@ -103,16 +104,16 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
private final String declaringClassName;
private final String name;
private final String methodName;
private final String descriptor;
@Nullable
private String toStringValue;
Source(String declaringClassName, String name, String descriptor) {
Source(String declaringClassName, String methodName, String descriptor) {
this.declaringClassName = declaringClassName;
this.name = name;
this.methodName = methodName;
this.descriptor = descriptor;
}
@@ -120,7 +121,7 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
public int hashCode() {
int result = 1;
result = 31 * result + this.declaringClassName.hashCode();
result = 31 * result + this.name.hashCode();
result = 31 * result + this.methodName.hashCode();
result = 31 * result + this.descriptor.hashCode();
return result;
}
@@ -135,7 +136,7 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
}
Source otherSource = (Source) other;
return (this.declaringClassName.equals(otherSource.declaringClassName) &&
this.name.equals(otherSource.name) && this.descriptor.equals(otherSource.descriptor));
this.methodName.equals(otherSource.methodName) && this.descriptor.equals(otherSource.descriptor));
}
@Override
@@ -144,14 +145,17 @@ final class SimpleMethodMetadataReadingVisitor extends MethodVisitor {
if (value == null) {
StringBuilder builder = new StringBuilder();
builder.append(this.declaringClassName);
builder.append(".");
builder.append(this.name);
builder.append('.');
builder.append(this.methodName);
Type[] argumentTypes = Type.getArgumentTypes(this.descriptor);
builder.append("(");
for (Type type : argumentTypes) {
builder.append(type.getClassName());
builder.append('(');
for (int i = 0; i < argumentTypes.length; i++) {
if (i != 0) {
builder.append(',');
}
builder.append(argumentTypes[i].getClassName());
}
builder.append(")");
builder.append(')');
value = builder.toString();
this.toStringValue = value;
}
@@ -88,13 +88,13 @@ public abstract class ClassUtils {
* Map with primitive wrapper type as key and corresponding primitive
* type as value, for example: Integer.class -> int.class.
*/
private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(8);
private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(9);
/**
* Map with primitive type as key and corresponding wrapper
* type as value, for example: int.class -> Integer.class.
*/
private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(8);
private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(9);
/**
* Map with primitive type name as key and corresponding primitive
@@ -1322,7 +1322,7 @@ public abstract class ClassUtils {
* Note that, despite being synthetic, bridge methods ({@link Method#isBridge()}) are considered
* as user-level methods since they are eventually pointing to a user-declared generic method.
* @param method the method to check
* @return {@code true} if the method can be considered as user-declared; [@code false} otherwise
* @return {@code true} if the method can be considered as user-declared; {@code false} otherwise
*/
public static boolean isUserLevelMethod(Method method) {
Assert.notNull(method, "Method must not be null");
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -302,7 +302,7 @@ public class StopWatch {
for (TaskInfo task : getTaskInfo()) {
sb.append(nf.format(task.getTimeNanos())).append(" ");
sb.append(pf.format((double) task.getTimeNanos() / getTotalTimeNanos())).append(" ");
sb.append(task.getTaskName()).append("\n");
sb.append(task.getTaskName()).append('\n');
}
}
return sb.toString();
@@ -320,7 +320,7 @@ public class StopWatch {
for (TaskInfo task : getTaskInfo()) {
sb.append("; [").append(task.getTaskName()).append("] took ").append(task.getTimeNanos()).append(" ns");
long percent = Math.round(100.0 * task.getTimeNanos() / getTotalTimeNanos());
sb.append(" = ").append(percent).append("%");
sb.append(" = ").append(percent).append('%');
}
}
else {
@@ -566,7 +566,7 @@ public abstract class StringUtils {
char[] chars = str.toCharArray();
chars[0] = updatedChar;
return new String(chars, 0, chars.length);
return new String(chars);
}
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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,13 +21,18 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit tests for {@link SimpleAliasRegistry}.
*
* @author Juergen Hoeller
* @author Nha Vuong
* @author Sam Brannen
*/
class SimpleAliasRegistryTests {
private final SimpleAliasRegistry registry = new SimpleAliasRegistry();
@Test
void aliasChaining() {
SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("test", "testAlias");
registry.registerAlias("testAlias", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3");
@@ -42,7 +47,6 @@ class SimpleAliasRegistryTests {
@Test // SPR-17191
void aliasChainingWithMultipleAliases() {
SimpleAliasRegistry registry = new SimpleAliasRegistry();
registry.registerAlias("name", "alias_a");
registry.registerAlias("name", "alias_b");
assertThat(registry.hasAlias("name", "alias_a")).isTrue();
@@ -60,4 +64,35 @@ class SimpleAliasRegistryTests {
assertThat(registry.hasAlias("real_name", "alias_c")).isTrue();
}
@Test
void removeAlias() {
registry.registerAlias("real_name", "nickname");
assertThat(registry.hasAlias("real_name", "nickname")).isTrue();
registry.removeAlias("nickname");
assertThat(registry.hasAlias("real_name", "nickname")).isFalse();
}
@Test
void isAlias() {
registry.registerAlias("real_name", "nickname");
assertThat(registry.isAlias("nickname")).isTrue();
assertThat(registry.isAlias("real_name")).isFalse();
assertThat(registry.isAlias("fake")).isFalse();
}
@Test
void getAliases() {
registry.registerAlias("test", "testAlias1");
assertThat(registry.getAliases("test")).containsExactly("testAlias1");
registry.registerAlias("testAlias1", "testAlias2");
registry.registerAlias("testAlias2", "testAlias3");
assertThat(registry.getAliases("test")).containsExactlyInAnyOrder("testAlias1", "testAlias2", "testAlias3");
assertThat(registry.getAliases("testAlias1")).containsExactlyInAnyOrder("testAlias2", "testAlias3");
assertThat(registry.getAliases("testAlias2")).containsExactly("testAlias3");
assertThat(registry.getAliases("testAlias3")).isEmpty();
}
}
@@ -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.
@@ -33,9 +33,51 @@ import static org.assertj.core.api.Assertions.entry;
* Base class for {@link AnnotationMetadata} tests.
*
* @author Phillip Webb
* @author Sam Brannen
*/
public abstract class AbstractAnnotationMetadataTests {
@Test
public void verifyEquals() throws Exception {
AnnotationMetadata testClass1 = get(TestClass.class);
AnnotationMetadata testClass2 = get(TestClass.class);
AnnotationMetadata testMemberClass1 = get(TestMemberClass.class);
AnnotationMetadata testMemberClass2 = get(TestMemberClass.class);
assertThat(testClass1.equals(null)).isFalse();
assertThat(testClass1.equals(testClass1)).isTrue();
assertThat(testClass2.equals(testClass2)).isTrue();
assertThat(testClass1.equals(testClass2)).isTrue();
assertThat(testClass2.equals(testClass1)).isTrue();
assertThat(testMemberClass1.equals(testMemberClass1)).isTrue();
assertThat(testMemberClass2.equals(testMemberClass2)).isTrue();
assertThat(testMemberClass1.equals(testMemberClass2)).isTrue();
assertThat(testMemberClass2.equals(testMemberClass1)).isTrue();
assertThat(testClass1.equals(testMemberClass1)).isFalse();
assertThat(testMemberClass1.equals(testClass1)).isFalse();
}
@Test
public void verifyHashCode() throws Exception {
AnnotationMetadata testClass1 = get(TestClass.class);
AnnotationMetadata testClass2 = get(TestClass.class);
AnnotationMetadata testMemberClass1 = get(TestMemberClass.class);
AnnotationMetadata testMemberClass2 = get(TestMemberClass.class);
assertThat(testClass1).hasSameHashCodeAs(testClass2);
assertThat(testMemberClass1).hasSameHashCodeAs(testMemberClass2);
assertThat(testClass1).doesNotHaveSameHashCodeAs(testMemberClass1);
}
@Test
public void verifyToString() throws Exception {
assertThat(get(TestClass.class).toString()).isEqualTo(TestClass.class.getName());
}
@Test
public void getClassNameReturnsClassName() {
assertThat(get(TestClass.class).getClassName()).isEqualTo(TestClass.class.getName());
@@ -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.
@@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Abstract base class for testing implementations of
* {@link ClassMetadata#getMemberClassNames()}.
@@ -30,48 +29,45 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public abstract class AbstractClassMetadataMemberClassTests {
public abstract ClassMetadata getClassMetadataFor(Class<?> clazz);
protected abstract ClassMetadata getClassMetadataFor(Class<?> clazz);
@Test
void withNoMemberClasses() {
ClassMetadata metadata = getClassMetadataFor(L0_a.class);
String[] nestedClasses = metadata.getMemberClassNames();
assertThat(nestedClasses).isEqualTo(new String[]{});
assertThat(nestedClasses).isEmpty();
}
public static class L0_a {
}
@Test
void withPublicMemberClasses() {
ClassMetadata metadata = getClassMetadataFor(L0_b.class);
String[] nestedClasses = metadata.getMemberClassNames();
assertThat(nestedClasses).isEqualTo(new String[]{L0_b.L1.class.getName()});
assertThat(nestedClasses).containsOnly(L0_b.L1.class.getName());
}
@Test
void withNonPublicMemberClasses() {
ClassMetadata metadata = getClassMetadataFor(L0_c.class);
String[] nestedClasses = metadata.getMemberClassNames();
assertThat(nestedClasses).containsOnly(L0_c.L1.class.getName());
}
@Test
void againstMemberClass() {
ClassMetadata metadata = getClassMetadataFor(L0_b.L1.class);
String[] nestedClasses = metadata.getMemberClassNames();
assertThat(nestedClasses).isEmpty();
}
public static class L0_a {
}
public static class L0_b {
public static class L1 { }
}
@Test
void withNonPublicMemberClasses() {
ClassMetadata metadata = getClassMetadataFor(L0_c.class);
String[] nestedClasses = metadata.getMemberClassNames();
assertThat(nestedClasses).isEqualTo(new String[]{L0_c.L1.class.getName()});
}
public static class L0_c {
private static class L1 { }
}
@Test
void againstMemberClass() {
ClassMetadata metadata = getClassMetadataFor(L0_b.L1.class);
String[] nestedClasses = metadata.getMemberClassNames();
assertThat(nestedClasses).isEqualTo(new String[]{});
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -37,6 +37,54 @@ import static org.assertj.core.api.Assertions.entry;
*/
public abstract class AbstractMethodMetadataTests {
@Test
public void verifyEquals() throws Exception {
MethodMetadata withMethod1 = getTagged(WithMethod.class);
MethodMetadata withMethod2 = getTagged(WithMethod.class);
MethodMetadata withMethodWithTwoArguments1 = getTagged(WithMethodWithTwoArguments.class);
MethodMetadata withMethodWithTwoArguments2 = getTagged(WithMethodWithTwoArguments.class);
assertThat(withMethod1.equals(null)).isFalse();
assertThat(withMethod1.equals(withMethod1)).isTrue();
assertThat(withMethod2.equals(withMethod2)).isTrue();
assertThat(withMethod1.equals(withMethod2)).isTrue();
assertThat(withMethod2.equals(withMethod1)).isTrue();
assertThat(withMethodWithTwoArguments1.equals(withMethodWithTwoArguments1)).isTrue();
assertThat(withMethodWithTwoArguments2.equals(withMethodWithTwoArguments2)).isTrue();
assertThat(withMethodWithTwoArguments1.equals(withMethodWithTwoArguments2)).isTrue();
assertThat(withMethodWithTwoArguments2.equals(withMethodWithTwoArguments1)).isTrue();
assertThat(withMethod1.equals(withMethodWithTwoArguments1)).isFalse();
assertThat(withMethodWithTwoArguments1.equals(withMethod1)).isFalse();
}
@Test
public void verifyHashCode() throws Exception {
MethodMetadata withMethod1 = getTagged(WithMethod.class);
MethodMetadata withMethod2 = getTagged(WithMethod.class);
MethodMetadata withMethodWithTwoArguments1 = getTagged(WithMethodWithTwoArguments.class);
MethodMetadata withMethodWithTwoArguments2 = getTagged(WithMethodWithTwoArguments.class);
assertThat(withMethod1).hasSameHashCodeAs(withMethod2);
assertThat(withMethodWithTwoArguments1).hasSameHashCodeAs(withMethodWithTwoArguments2);
assertThat(withMethod1).doesNotHaveSameHashCodeAs(withMethodWithTwoArguments1);
}
@Test
public void verifyToString() throws Exception {
assertThat(getTagged(WithMethod.class).toString())
.endsWith(WithMethod.class.getName() + ".test()");
assertThat(getTagged(WithMethodWithOneArgument.class).toString())
.endsWith(WithMethodWithOneArgument.class.getName() + ".test(java.lang.String)");
assertThat(getTagged(WithMethodWithTwoArguments.class).toString())
.endsWith(WithMethodWithTwoArguments.class.getName() + ".test(java.lang.String,java.lang.Integer)");
}
@Test
public void getMethodNameReturnsMethodName() {
assertThat(getTagged(WithMethod.class).getMethodName()).isEqualTo("test");
@@ -171,6 +219,24 @@ public abstract class AbstractMethodMetadataTests {
}
public static class WithMethodWithOneArgument {
@Tag
public String test(String text) {
return "";
}
}
public static class WithMethodWithTwoArguments {
@Tag
public String test(String text, Integer num) {
return "";
}
}
public abstract static class WithAbstractMethod {
@Tag
@@ -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.
@@ -19,6 +19,7 @@ package org.springframework.core.type.classreading;
import java.io.BufferedInputStream;
import java.io.InputStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.asm.ClassReader;
@@ -35,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* Tests for {@link AnnotationMetadataReadingVisitor}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
@SuppressWarnings("deprecation")
class AnnotationMetadataReadingVisitorTests extends AbstractAnnotationMetadataTests {
@@ -62,11 +64,29 @@ class AnnotationMetadataReadingVisitorTests extends AbstractAnnotationMetadataTe
}
}
@Test
@Disabled("equals() not implemented in deprecated AnnotationMetadataReadingVisitor")
@Override
public void verifyEquals() throws Exception {
}
@Test
@Disabled("hashCode() not implemented in deprecated AnnotationMetadataReadingVisitor")
@Override
public void verifyHashCode() throws Exception {
}
@Test
@Disabled("toString() not implemented in deprecated AnnotationMetadataReadingVisitor")
@Override
public void verifyToString() {
}
@Override
@Test
public void getAnnotationsReturnsDirectAnnotations() {
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
super::getAnnotationsReturnsDirectAnnotations);
assertThatExceptionOfType(UnsupportedOperationException.class)
.isThrownBy(super::getAnnotationsReturnsDirectAnnotations);
}
}
@@ -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.
@@ -19,6 +19,7 @@ package org.springframework.core.type.classreading;
import java.io.BufferedInputStream;
import java.io.InputStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.asm.ClassReader;
@@ -35,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* Tests for {@link MethodMetadataReadingVisitor}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
@SuppressWarnings("deprecation")
class MethodMetadataReadingVisitorTests extends AbstractMethodMetadataTests {
@@ -62,8 +64,26 @@ class MethodMetadataReadingVisitorTests extends AbstractMethodMetadataTests {
}
}
@Override
@Test
@Disabled("equals() not implemented in deprecated MethodMetadataReadingVisitor")
@Override
public void verifyEquals() throws Exception {
}
@Test
@Disabled("hashCode() not implemented in deprecated MethodMetadataReadingVisitor")
@Override
public void verifyHashCode() throws Exception {
}
@Test
@Disabled("toString() not implemented in deprecated MethodMetadataReadingVisitor")
@Override
public void verifyToString() {
}
@Test
@Override
public void getAnnotationsReturnsDirectAnnotations() {
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(
super::getAnnotationsReturnsDirectAnnotations);
@@ -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.
@@ -194,7 +194,7 @@ class FastByteArrayOutputStreamTests {
this.os.write(this.helloBytes);
InputStream inputStream = this.os.getInputStream();
DigestUtils.appendMd5DigestAsHex(inputStream, builder);
builder.append("\"");
builder.append('"');
String actual = builder.toString();
assertThat(actual).isEqualTo("\"0b10a8db164e0754105b7a99be72e3fe5\"");
}
@@ -208,7 +208,7 @@ class FastByteArrayOutputStreamTests {
}
InputStream inputStream = this.os.getInputStream();
DigestUtils.appendMd5DigestAsHex(inputStream, builder);
builder.append("\"");
builder.append('"');
String actual = builder.toString();
assertThat(actual).isEqualTo("\"06225ca1e4533354c516e74512065331d\"");
}
@@ -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.
@@ -41,7 +41,7 @@ class StopWatchTests {
private static final long duration1 = 200;
private static final long duration2 = 100;
private static final long fudgeFactor = 50;
private static final long fudgeFactor = 100;
private final StopWatch stopWatch = new StopWatch(ID);
@@ -107,7 +107,7 @@ class StopWatchTests {
.isLessThanOrEqualTo(duration1 + duration2 + fudgeFactor);
assertThat(stopWatch.getTotalTimeSeconds())
.as("total time in seconds for task #2")
.isGreaterThanOrEqualTo((duration1 + duration2 - fudgeFactor) / 1000.0)
.isGreaterThanOrEqualTo((duration1 + duration2 - fudgeFactor) / 1000.0)
.isLessThanOrEqualTo((duration1 + duration2 + fudgeFactor) / 1000.0);
assertThat(stopWatch.getTaskCount()).isEqualTo(2);
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 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.
@@ -612,7 +612,7 @@ class StringUtilsTests {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < components.length; i++) {
if (i != 0) {
sb.append(",");
sb.append(',');
}
sb.append(components[i]);
}
@@ -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.
@@ -137,7 +137,7 @@ public class ExpressionException extends RuntimeException {
StringBuilder output = new StringBuilder();
output.append("Expression [");
output.append(this.expressionString);
output.append("]");
output.append(']');
if (this.position >= 0) {
output.append(" @");
output.append(this.position);

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