Compare commits

...

2689 Commits

Author SHA1 Message Date
Sam Brannen 2b08e6e1d3 Merge branch '7.0.x' 2026-06-08 18:29:20 +02:00
Sam Brannen 2c18c33ce0 Track operations during SpEL expression evaluation
This commit introduces support for tracking operations during SpEL
expression evaluation. If the maximum number of operations is exceeded,
a SpelEvaluationException is thrown.

The limit can be configured either on a per-use-case basis via
SpelParserConfiguration supplied to the SpelExpressionParser or
globally as a JVM system property or Spring property named
`spring.expression.maxOperations`.

Closes gh-36801
2026-06-08 15:13:44 +02:00
Sam Brannen 83667f808c Ensure getters have non-void return types in SpEL
Closes gh-36800
2026-06-08 15:13:44 +02:00
Sam Brannen 7a8917b137 Improve additional error messages in SpEL
This commit picks up where 987d6cca6d left off.

See gh-36756
2026-06-08 15:13:44 +02:00
Sam Brannen 7baa86536f Further improve pattern caching in SpEL
See gh-36755
2026-06-08 15:13:44 +02:00
Sam Brannen 12b44f2545 Avoid too many character access attempts in AntPathMatcher
Closes gh-36799
2026-06-08 15:13:44 +02:00
Sébastien Deleuze e8f10244e3 Ensure consistent JSP tag attribute processing
Closes gh-36797
2026-06-08 15:13:44 +02:00
Sébastien Deleuze a1826b725c Refine JavaScriptUtils#javaScriptEscape
Closes gh-36795
2026-06-08 15:13:43 +02:00
Sébastien Deleuze 7add5243b9 Prevent special prefixes in default view name resolution
This commit updates the default view name generation logic in
both Spring WebMVC and Spring WebFlux to prevent "redirect:"
and "forward:" (for MVC) prefixes from the incoming request path.

Closes gh-36793
2026-06-08 15:13:43 +02:00
Sébastien Deleuze 9bec52b1ec Add trusted packages to MappingJackson2MessageConverter
This commit introduces trusted packages, specified via the related
setter for untrusted use cases. It allows explicit configuration
of which Java packages are allowed to be deserialized.

Closes gh-36791
2026-06-08 15:13:43 +02:00
Sébastien Deleuze fe68e337b2 Add trusted packages to JacksonJsonMessageConverter
This commit introduces trusted packages, specified via the related
setter for untrusted use cases. It allows explicit configuration
of which Java packages are allowed to be deserialized.

See gh-36791
2026-06-08 15:13:43 +02:00
rstoyanchev 322eef2942 RfcParser rejects invalid IPv6 host
Fix gh-36787
2026-06-08 15:13:43 +02:00
Brian Clozel 4e39c28b92 Merge branch '7.0.x' 2026-06-08 14:49:45 +02:00
Brian Clozel ba0a9b8923 Upgrade to Reactor 2025.0.6
Closes gh-36884
2026-06-08 14:49:19 +02:00
Brian Clozel 381fa10477 Merge branch '7.0.x' 2026-06-08 10:41:12 +02:00
Brian Clozel 8a192eab1f Upgrade to Micrometer 1.16.6
Closes gh-36883
2026-06-08 10:40:01 +02:00
rstoyanchev 14f4deef3a Merge branch '7.0.x' 2026-06-05 14:36:23 +01:00
rstoyanchev 45812cb9d0 Prefer Jackson XML codecs when present
Closes gh-36776
2026-06-05 14:36:05 +01:00
rstoyanchev 95bd3f7c67 Exclude Jackson XML from String encoding/decoding
Closes gh-36775
2026-06-05 14:36:05 +01:00
Sam Brannen e23971efb9 Merge branch '7.0.x' 2026-06-05 15:15:19 +02:00
Sam Brannen 6ca66afc7b Polish contribution
See gh-36871
2026-06-05 15:13:25 +02:00
zhaomeng 1b32d8d41d Include zone ID in CronTrigger's equals() and hashCode() implementations
CronTrigger carries an optional ZoneId since 5.3 that affects
nextExecution; however, prior to this commit, equals() and hashCode()
only considered the cron expression.

This commit ensures that CronTrigger instances with the same cron
expression but different time zones are no longer considered equal.

Closes gh-36871

Signed-off-by: zhaomeng <zhaomeng1.vendor@sensetime.com>
2026-06-05 15:09:14 +02:00
Sam Brannen 2469aae672 Merge branch '7.0.x' 2026-06-05 14:57:29 +02:00
Sam Brannen b4a378186f Fix additional links to Selenium documentation
See gh-36875
2026-06-05 14:56:51 +02:00
leestana01 220fcaa1e3 Fix broken links to Selenium documentation
The links to docs.seleniumhq.org no longer resolve, since the host was
retired.

This commit changes those links to use the current Selenium
documentation at selenium.dev.

Closes gh-36875

Signed-off-by: leestana01 <leestana01@naver.com>
2026-06-05 14:52:15 +02:00
cookie-meringue 83e29382b3 Optimize ClassNameReader.getClassName via direct ASM API
getClassName now calls ClassReader.getClassName() directly instead
of routing through the visitor-based getClassInfo. Previously, it
allocated a List and a ClassVisitor and decoded super_class and
every interface name only to discard all but the first element.

The method is on the hot path of every CGLIB proxy class definition,
so this change significantly lowers its per-call processing cost.

Closes gh-36814

Signed-off-by: cookie-meringue <daehyeon3351@gmail.com>
2026-06-04 14:20:49 +02:00
Brian Clozel ee5c82a2f8 Merge branch '7.0.x' 2026-06-04 12:27:18 +02:00
Brian Clozel 80534f9df6 Polishing contribution
This commit adds further fixes in the same area, since there were
similar bugs in the WriteCompletionHandler:
* databuffers were not always emitted when fully read in the onNext hook
* on completion, the iterator was closed too early, before it was fully
  read
* on completion, writing the next bytebuffers from the iterator would
  always reuse the first one and not update the attachment

Closes gh-36714
2026-06-04 12:18:01 +02:00
KimDaehyeon d8bc54d2e7 Fix data loss in DataBufferUtils synchronous write
Prior to this commit, WritableByteChannelSubscriber.hookOnNext() called
iterator.next() exactly once. If a DataBuffer consisted of multiple NIO
ByteBuffers (e.g., NettyDataBuffer wrapping a CompositeByteBuf), only
the first buffer was written to the channel, and the remaining buffers
were silently ignored and lost.

This commit adds the missing while (iterator.hasNext()) outer loop to
ensure all fragmented buffers exposed by the iterator are completely
and safely written to the synchronous channel.

See gh-36714

Signed-off-by: KimDaehyeon <daehyeon3351@gmail.com>
2026-06-04 12:17:57 +02:00
rstoyanchev ae7891e797 Revise disconnected client error handling in WebFlux
A disconnected client error does not necessarily prevent us from setting
the status of the WebFlux ServerHttpResponse, which is only gated by a
committed flag and does not necessarily reflect the connection state.

This is why we need to check if we have a disconnected client error
first and handle it accordingly. We still set the response to 500
in case the disconnect client error is to a remote host in which
case it will propagate to the client.

Closes gh-36811
2026-06-04 11:10:58 +01:00
rstoyanchev 98ed1dfcf8 Revise disconnected client error handling in Spring MVC
DisconnectedClientHelper identifies lost connection issues, but it's
not always easy to know if it is the connection to the client or to
another remote host. DisconnectedClientHelper does recognize and
filter out common client exceptions, but there is a possibility for
other similar custom exceptions.

DefaultHandlerExceptionResolver now attempts to set the status to
500, which won't impact a client that has gone away, but it will
set the status correct on the off chance that the exception is
actually a server side issue.

Closes gh-34481
2026-06-04 11:10:58 +01:00
Brian Clozel 9b8a851969 Merge branch '7.0.x' 2026-06-04 10:49:36 +02:00
Brian Clozel 6467fca05b Polishing contribution
This fixes a potential regression introduced by the previous commit.
Because the current value was not updated after the temporal was rolled
forward, there were new cases where entire days would be skipped.

Closes gh-36865
2026-06-04 10:22:23 +02:00
arno cddc671a8c Fix CronExpression day skip on midnight DST gap
After rollForward, BitsCronField always searched for the next
matching bit from zero. When daylight saving creates a gap at
the start of a period (e.g. Africa/Cairo), the temporal lands on
a non-zero field value and matching from zero could advance an
entire period too far, skipping the calendar day.

Search from the actual field value in the new period instead,
falling back to zero only when no bit matches in that period.

See gh-36865

Signed-off-by: arno <me@zmovo.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 10:22:17 +02:00
seungchan 4c6194a2ad Simplify BUFFER_COUNT in ConcurrentLruCache to a constant
The detectNumberOfBuffers() method attempted to scale the read
buffer count based on the number of available processors, but used
Math.min(4, nextPowerOfTwo) which effectively caps the result at 4
regardless of CPU count. For systems with fewer than 3 processors,
the buffer count would be reduced below 4, but this edge case adds
complexity without measurable benefit.

Simplify BUFFER_COUNT to a constant value of 4, removing the
unnecessary CPU-detection logic.

Closes gh-36872

Signed-off-by: seungchan <s24041@gsm.hs.kr>
2026-06-04 09:30:36 +02:00
Juergen Hoeller 2fc99eb12f Merge branch '7.0.x' 2026-06-03 23:04:51 +02:00
Juergen Hoeller 2e653246b5 Fix concurrency issue against shared cookie field in setLocaleContext
Closes gh-36869
2026-06-03 23:03:39 +02:00
Brian Clozel 783388e9f8 Merge branch '7.0.x' 2026-06-03 11:23:03 +02:00
Brian Clozel 86a68a77c4 Support multi-line comments in Server Sent Events
Prior to this commit, comments sent with Server Sent Events could break
the wire format when sent over the network when comments contained line
breaks.
While comments are mainly used for sending keepalive messages, they can
also be used for sending debug data. This commit ensures that line
breaks are properly handled in comments.

Fixes gh-36866
2026-06-03 11:13:32 +02:00
Juergen Hoeller de4de02a1d Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-context/src/main/java/org/springframework/validation/DataBinder.java
2026-06-02 17:33:07 +02:00
Juergen Hoeller fe27ad24d5 Upgrade to Netty 4.2.15 and Hibernate ORM 7.2.17 2026-06-02 17:30:17 +02:00
Juergen Hoeller ecc847c493 Fix applicability note on setAutoGrowCollectionLimit
Closes gh-36863
2026-06-02 17:28:33 +02:00
Juergen Hoeller e6ce2a3c36 Expose autoGrowCollectionLimit in ConfigurablePropertyAccessor interface
See gh-36862
2026-06-02 17:20:52 +02:00
Matthias Kurz 481a5743b3 Apply auto-grow limit to direct field binding
DataBinder applies its auto-grow collection limit to bean
property access, but direct field access left DirectFieldAccessor
at its default limit.

Pass DataBinder's configured limit into DirectFieldBindingResult
and apply it to the DirectFieldAccessor.

Closes gh-36861

Signed-off-by: Matthias Kurz <m.kurz@irregular.at>
2026-06-02 16:58:47 +02:00
wushiyuanmaimob 85a8868bae Preserve generic type info in awaitEntity()
awaitEntity() used T::class.java which erases generic type
information (e.g. List<Foo> becomes just List). Use the
reified toEntity<T>() extension instead, which preserves
full generic type via ParameterizedTypeReference.

Closes gh-36834
Signed-off-by: wushiyuanmaimob <wushiyuanwork@outlook.com>
2026-06-02 12:26:41 +02:00
rstoyanchev dd72b9eb4b Merge branch '7.0.x' 2026-06-01 10:53:55 +01:00
daguimu c2191e3ce2 Fix fragment parsing for relative URI in RfcUriParser
When parsing a relative URI such as `path2#foo`, RfcUriParser's
SCHEME_OR_PATH state advanced to FRAGMENT without moving the component
index past the `#` character, so the captured fragment included the
entire input (`path2#foo`) instead of just `foo`. As a result,
`toUriString()` produced `path2#path2#foo`.

Update the SCHEME_OR_PATH `#` transition to advance the component
index to `i + 1`, matching the sibling `?` -> QUERY transition in the
same state and every other `-> FRAGMENT` transition in the parser.
URIs with a `/` in the path are unaffected because they leave
SCHEME_OR_PATH for PATH on the first slash; the WhatWG parser already
handled this case correctly.

Closes gh-36762

Signed-off-by: daguimu <daguimu.geek@gmail.com>
2026-06-01 10:52:37 +01:00
Juergen Hoeller 2e65c1dfe6 Merge branch '7.0.x' 2026-05-29 13:31:01 +02:00
Juergen Hoeller 175c1f9437 Runtime compatibility with JPA 4.0 M4
Closes gh-36784
2026-05-29 13:28:46 +02:00
Juergen Hoeller 0b77c3df45 Detect back-off exhaustion at invoker level as well
See gh-36809
2026-05-29 13:23:30 +02:00
Sam Brannen ca72cd66e3 Merge branch '7.0.x' 2026-05-28 10:59:38 +02:00
Sam Brannen 6985d00fce Update antora-extensions to 1.14.12
Closes gh-36851
2026-05-28 10:57:11 +02:00
Juergen Hoeller a3f3ba5685 Merge branch '7.0.x' 2026-05-27 18:59:32 +02:00
Juergen Hoeller 1e45ad8fa6 Restore back-off on listener setup failure
Supports exponential back-off as well now.

Closes gh-36809
2026-05-27 18:58:37 +02:00
rstoyanchev 79f4f76bd2 Merge branch '7.0.x' 2026-05-27 17:19:22 +01:00
rstoyanchev 6fd45c118d Polishing contribution
Closes gh-36650
2026-05-27 17:19:00 +01:00
Max Guiking f9b75b02da Fix last flag check in JettyWebSocketSession
See gh-36650

Signed-off-by: Max Guiking <mguiking@een.com>
2026-05-27 17:19:00 +01:00
Patrick Strawderman 84efa46e09 DefaultPathContainer uses immutable map for SEPARATORS
Closes gh-36821

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2026-05-27 17:18:59 +01:00
shenjianeng b3dfba8719 Refactor map initialization using CollectionUtils
Closes gh-36763

Signed-off-by: shenjianeng <ishenjianeng@qq.com>
2026-05-27 17:17:02 +01:00
Juergen Hoeller 744d136cf7 Upgrade to Hibernate ORM 7.4
Closes gh-36519
2026-05-27 16:44:26 +02:00
Juergen Hoeller 00ca23859e Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2026-05-27 16:35:51 +02:00
Juergen Hoeller 2782a2701c Upgrade to Netty 4.2.14 and Hibernate ORM 7.2.16 2026-05-27 16:33:15 +02:00
Juergen Hoeller af2b96192d Force initialization of configuration class in mainline thread
Closes gh-36844
2026-05-27 16:32:37 +02:00
Juergen Hoeller 121c0ac285 Remove scanned class only when conflicting with imported class
Closes gh-36835
2026-05-27 16:31:13 +02:00
Juergen Hoeller 3e585830d7 Fix MethodParameter nestingLevel documentation
Closes gh-36826
2026-05-27 16:29:51 +02:00
Sam Brannen facc7c5371 Merge branch '7.0.x' 2026-05-27 12:16:46 +02:00
Sam Brannen b95caa8331 Upgrade Antora dependencies 2026-05-27 12:15:25 +02:00
Sam Brannen bd1e7e16a9 Merge branch '7.0.x' 2026-05-27 12:05:04 +02:00
Sam Brannen c17939ed5c Polish contribution
See gh-36831
2026-05-27 12:02:50 +02:00
Dennis-Mircea Ciupitu f3bfe27445 Document @⁠Conditional gating of nested @⁠Configuration classes
Closes gh-36831

Signed-off-by: Dennis-Mircea Ciupitu <dennis.mircea.ciupitu@gmail.com>
2026-05-27 12:02:50 +02:00
Sam Brannen 7651d5841f Pin Node.js version to 24.15.0
Prior to this commit, the `antora` Gradle task silently failed to build
the reference documentation, since Antora uses the latest LTS release
for Node.js by default, and the latest LTS apparently does not work for
us.
2026-05-27 12:01:09 +02:00
Brian Clozel 25e8395df8 Reject duplicate MIME type parameters
Prior to this commit, MIME type parsing in Spring would allow duplicate
parameters like "text/plain; dupe=1; dupe=2", effectively retaining the
latest value and ignoring the first.

RFC 6838 4.3 states that this should be treated as an error and this
commit ensures that this is the case.

Closes gh-36841
2026-05-26 17:53:28 +02:00
Sam Brannen 148b7fd8f3 Merge branch '7.0.x' 2026-05-26 16:40:06 +02:00
Sam Brannen 6e122d3aaa Polish contribution
See gh-36833
2026-05-26 16:39:30 +02:00
seonwoo_jung f7be796c1c Expose ClassLoader from DefaultDeserializer
Add a public accessor for the ClassLoader configured on a
DefaultDeserializer instance so that callers no longer need to read the
private field via reflection in order to forward it to a
ConfigurableObjectInputStream subclass.

See gh-36827
Closes gh-36833

Signed-off-by: seonwoo_jung <laborlawseon@kap.kr>
2026-05-26 16:35:37 +02:00
Brian Clozel 68338aa818 Use ASCII chars in Content-Disposition filename parameter
Prior to this commit, gh-36328 avoided using RFC 2047 encoding for the
"filename" parameter and use ISO-8859-1 only. This change unfortunately
caused issues because some implementations might try and detect the
encoding automatically.

This commit restricts the filename parameter to ASCII encoding only by:
* transliterating characters to the closes ASCII character
("é"->"e", "ä"->"ae"...)
* falling back to "_" for other chacacters with non latin alphabet or
  emojis

Fixes gh-36805
2026-05-22 21:33:40 +02:00
Sam Brannen fbbc0f487c Use Constants API introduced in JUnit 6.1
See gh-36815
2026-05-21 12:48:37 +02:00
Sam Brannen 611c390417 Use EngineTestKit in ParallelExecutionSpringExtensionTests 2026-05-21 12:27:33 +02:00
Sam Brannen cf3196e8de Merge branch '7.0.x' 2026-05-20 17:49:42 +02:00
Sam Brannen 1e843fd3ec Polish contribution
See gh-36777
2026-05-20 17:45:24 +02:00
Kai Zander 4bb20ea8db Allow specifying charset to use in ExchangeFilterFunctions#basicAuthentication
Prior to this commit, it was not possible to specify the character set
to use with ExchangeFilterFunctions#basicAuthentication.

To address that, this commit introduces a new

Closes gh-36777

Signed-off-by: Kai Zander <61500114+kzander91@users.noreply.github.com>
2026-05-20 17:45:24 +02:00
Sam Brannen 80e9e4f6f2 Make ParallelExecutionSpringExtensionTests more robust
... due to changes in JUnit 6.1.0.

See gh-36815
2026-05-20 17:32:01 +02:00
Sam Brannen 91655be0db Merge branch '7.0.x' 2026-05-20 16:53:56 +02:00
dependabot[bot] ac24766510 Upgrade fast-xml-parser to 5.7.0
Closes gh-36691
2026-05-20 16:51:05 +02:00
Sam Brannen 3b030e0431 Upgrade to JUnit 6.1
Closes gh-36815
2026-05-20 16:34:26 +02:00
Sam Brannen 9870ce1844 Only update ObservationThreadLocalAccessor when test has an active ApplicationContext
Prior to this commit,
MicrometerObservationRegistryTestExecutionListener always attempted to
load the test's ApplicationContext in order to update the
ObservationThreadLocalAccessor in its beforeTestMethod() callback, even
if there was no active ApplicationContext.

To avoid unnecessarily loading an ApplicationContext or attempting to
load an ApplicationContext that cannot be loaded (for example, due to a
context-load failure), this commit applies a hasApplicationContext()
check in beforeTestMethod().

Since the MicrometerObservationRegistryTestExecutionListener is
registered after the DependencyInjectionTestExecutionListener (at least
by default), an active ApplicationContext should be present unless
dependency injection from the context failed or the context failed to
load.

Closes gh-36817
2026-05-20 14:52:20 +02:00
Sam Brannen d87c03a6be Reset mocks only when a test has an ApplicationContext
Prior to this commit and the previous commit,
MockitoResetTestExecutionListener always attempted to load the
ApplicationContext to reset mocks in its beforeTestMethod() and
afterTestMethod() callbacks, even if there was no active
ApplicationContext.

The reason this was noticed is that the @BeforeMethod(alwaysRun = true)
and @AfterMethod(alwaysRun = true) lifecycle methods in
AbstractTestNGSpringContextTests are always invoked, even if a previous
lifecycle configuration method failed (for example, due to a
context-load failure).

However, with JUnit Jupiter and the SpringExtension the
beforeTestMethod() and afterTestMethod() callbacks in the
TestExecutionListener API are not invoked if there was a previous
lifecycle failure.

Consequently, the reported drawbacks only exist when using Spring's
TestNG base support classes

This commit picks up where the previous commit left off by applying the
same hasApplicationContext() check in beforeTestMethod().

This commit also introduces unit and integration tests for both Jupiter
and TestNG support.

Closes gh-36782
2026-05-20 14:04:09 +02:00
seregamorph 1d91982f83 Reset mocks after test only when the test has an ApplicationContext
See gh-36782

Signed-off-by: seregamorph <serega.morph@gmail.com>
2026-05-20 14:03:55 +02:00
Sam Brannen 0c25d817bd Merge branch '7.0.x' 2026-05-17 15:33:24 +02:00
Sam Brannen d5e85bd95e Remove obsolete code 2026-05-17 15:30:04 +02:00
Sam Brannen 17ed3e8370 Merge branch '7.0.x' 2026-05-17 13:56:47 +02:00
Sam Brannen c3c96b9f32 Upgrade to Gradle 9.5.1
Closes gh-36744
2026-05-17 13:47:00 +02:00
rstoyanchev 2f458f9093 Merge branch '7.0.x' 2026-05-15 13:51:31 +01:00
rstoyanchev 4d98ff5dcf Polishing in data binding docs 2026-05-15 13:50:57 +01:00
rstoyanchev 16e0ed0463 Merge branch '7.0.x' 2026-05-14 16:56:21 +01:00
rstoyanchev 48262b8efe Further polishing in docs on web binding
See gh-36803
2026-05-14 16:55:53 +01:00
rstoyanchev e24448118c Merge branch '7.0.x' 2026-05-14 16:42:29 +01:00
rstoyanchev ca32ac5e7f Polishing in docs
See gh-36803
2026-05-14 16:41:59 +01:00
rstoyanchev 63ccc9d9cc Restructure web binding documentation and refine guidance
Closes gh-36803
2026-05-14 16:36:27 +01:00
Juergen Hoeller a0ec6656b4 Merge branch '7.0.x' 2026-05-13 19:46:39 +02:00
Juergen Hoeller 8fe1de4595 Polishing 2026-05-13 19:46:07 +02:00
Juergen Hoeller 5ab4c5c5d9 Add support for JPA 4.0 @PersistenceAgent injection
Closes gh-36264
2026-05-13 19:41:21 +02:00
Juergen Hoeller c3baa01535 Merge branch '7.0.x' 2026-05-12 16:21:43 +02:00
Juergen Hoeller c048074436 Restrict SpringVersion.getVersion() to "major.minor.patch" format
Closes gh-36785
2026-05-12 16:20:47 +02:00
Juergen Hoeller c0b749479a Merge branch '7.0.x' 2026-05-12 13:10:34 +02:00
Juergen Hoeller b7882d703c Expose package-info classes through PersistenceUnitInfo#getAllClassNames()
Closes gh-36784
2026-05-12 13:09:51 +02:00
Juergen Hoeller 5bf58cfe05 Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2026-05-11 13:09:38 +02:00
Juergen Hoeller ca8a1ea375 Upgrade to Log4J 2.26, Groovy 5.0.6, Tomcat 11.0.22, Jetty 12.1.9, Hibernate ORM 7.2.14, Checkstyle 13.4.2 2026-05-11 13:08:34 +02:00
Vinod Kumar 238a24cb6d Polish collection usage in HttpHeadersTests
Signed-off-by: Vinod Kumar <codingkiddo@gmail.com>
2026-05-11 09:34:28 +02:00
Sam Brannen 9a54f75d6d Merge branch '7.0.x' 2026-05-09 16:40:53 +02:00
Yanming Zhou cfb8dc6cc8 Fix typos for validateExistingTransaction
Closes gh-36767

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-05-09 16:39:50 +02:00
Juergen Hoeller 9db16e4c15 Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2026-05-08 16:02:00 +02:00
Juergen Hoeller 665c9ad7df Upgrade to Netty 4.2.13 and Hibernate ORM 7.2.13 2026-05-08 16:00:14 +02:00
Juergen Hoeller d3152c11c7 Consistently expose map key quotes
Closes gh-36765
2026-05-08 15:59:57 +02:00
Juergen Hoeller 856e1d5dc8 Avoid ResolvableType#forType contention for implicit cache cleanup
Closes gh-36745
2026-05-08 15:59:46 +02:00
Sam Brannen ec8f0ca6b2 Merge branch '7.0.x' 2026-05-06 13:54:03 +02:00
Sam Brannen 987d6cca6d Fix error message for invalid regex in SpEL
Closes gh-36756
2026-05-06 13:53:37 +02:00
Sam Brannen 1a0bd12c34 Merge branch '7.0.x' 2026-05-06 13:26:10 +02:00
shenjianeng ec21dc0f91 Refactor regex pattern caching using computeIfAbsent
Closes gh-36755

Signed-off-by: shenjianeng <ishenjianeng@qq.com>
2026-05-06 13:25:07 +02:00
Brian Clozel e6590aa1a8 Merge branch '7.0.x'
Closes gh-36753
2026-05-05 11:59:37 +02:00
Brian Clozel 628261d5bb Do not warn against Root Servlet context location
Closes gh-36692
2026-05-05 11:50:28 +02:00
Sam Brannen 051b09694e Merge branch '7.0.x' 2026-05-04 17:21:22 +02:00
Kai Zander 715d33f001 Remove control character from log message in TransportHandlingSockJsService
Closes gh-36731

Signed-off-by: Kai Zander <61500114+kzander91@users.noreply.github.com>
2026-05-04 17:20:20 +02:00
Sam Brannen 39ff8e46ab Use String#replace instead of String#replaceAll in tests
See gh-36678
2026-05-03 14:36:23 +02:00
shenjianeng 27bdf24482 Use String#replace instead of String#replaceAll where appropriate
Avoid using String#replaceAll when the pattern is not a regular
expression.

Using java.lang.String#replace(CharSequence, CharSequence) will
improve performance.

Closes gh-36678

Signed-off-by: shenjianeng <ishenjianeng@qq.com>
2026-05-03 14:34:01 +02:00
Sam Brannen d9ecf945cc Merge branch '7.0.x' 2026-05-02 18:39:59 +02:00
Sam Brannen bb5142164e Upgrade to Gradle 9.5
Closes gh-36744
2026-05-02 18:38:09 +02:00
Sam Brannen b35da5b140 Merge branch '7.0.x' 2026-05-02 18:35:24 +02:00
박건영(Parkgunyoung) 25b8d64cd0 Fix typo in HttpServiceProxyFactory example
Closes gh-36736

Signed-off-by: 박건영(Parkgunyoung) <parkky3563@gmail.com>
2026-05-02 18:34:00 +02:00
rstoyanchev 367a62018d Merge branch '7.0.x' 2026-05-01 21:48:29 +01:00
rstoyanchev d72da90d3a Avoid race in InMemoryWebSession
Closes gh-36742
2026-05-01 21:47:37 +01:00
rstoyanchev bff9899905 Switch to JdkIdGenerator in AbstractWebSocketSession
Closes gh-36740
2026-05-01 21:47:26 +01:00
Brian Clozel 41cd6879bd Fix parsing failure for MIME types with quoted pairs
Prior to this commit, MIME types with parameter values that contain a
quoted pair would sometimes fail and parse an incomplete parameter
value.

This commit ensures that the quoted section of the parameter value is
correctly handled.

Fixes gh-36730
2026-05-01 21:47:16 +01:00
Brian Clozel 3a91d90c28 Resolve URL path for versioned webjar directories
Prior to this commit, the `resolveUrlPath` implementation for the
`LiteWebJarsResourceResolver` would always delegate to the resource
chain once the versioned webjar folder has been resolved.

While this aligns with the `ResourceResolver` contract and the fact that
the resource chain does not resolve directories, here the WebJar locator
does support such use cases and we shouldn't get in the way here.

This commit falls back to the resolved versioned WebJar path if no
resource could be resolved and the path ends with "/".

Fixes gh-36726
2026-05-01 21:47:06 +01:00
Juergen Hoeller 1b26f5d1e6 Adapt bean overriding test for deferred BeanRegistrar processing in 7.1
See gh-36648
See gh-21497
2026-04-30 14:33:55 +02:00
Juergen Hoeller 6ff2d187cf Merge branch '7.0.x'
# Conflicts:
#	spring-context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java
2026-04-30 14:21:49 +02:00
Juergen Hoeller 08c5280843 Consistent wrapping of BeanCreationExceptions from instance suppliers
Includes tests for circular references and bean definition overrides.

Closes gh-36725
See gh-36648
2026-04-30 14:19:25 +02:00
Juergen Hoeller 72cf389754 Merge branch '7.0.x' 2026-04-29 21:53:07 +02:00
Juergen Hoeller cd5fee5347 Polishing 2026-04-29 21:52:10 +02:00
Juergen Hoeller 916cb64581 Detect custom deserialized NullValue instances
Closes gh-36727
2026-04-29 21:52:04 +02:00
rstoyanchev 3184eb3acc Merge branch '7.0.x' 2026-04-29 12:12:31 +01:00
rstoyanchev b3ef834ae6 Reliably detect broadcast messages
Closes gh-36662
2026-04-29 12:11:16 +01:00
rstoyanchev a9d344b3ed TransportHandlingSockJsService checks remoteAddress
Closes gh-36681
2026-04-29 12:11:16 +01:00
cuitianhao 39a746d30f Set host header consistently in STOMP relay CONNECT frames
StompBrokerRelayMessageHandler only set the host header in CONNECT
frames when virtualHost was explicitly configured. Per STOMP 1.2, the
host header is required on CONNECT frames.

Fall back to relayHost (the TCP connection target) when virtualHost is
not configured, ensuring the host header is always present in both
system session and client session CONNECT frames.

Closes gh-36673

Signed-off-by: cuitianhao <54015884+tianhaocui@users.noreply.github.com>
2026-04-29 12:11:16 +01:00
Brian Clozel 9e4c127eda Merge branch '7.0.x' 2026-04-28 23:36:56 +02:00
Brian Clozel 952198b2ee Fix PartGenerator token request while creating tmp file
Prior to this commit, the `PartGenerator` would allow requesting
additional part tokens while in the `CreateFileState`. This is invalid
as any new token emitted would be rejected and would fail the entire
process.
This would only happen if the tmp file creation is slow enough for a new
token to be parsed and emitted.

This commit ensures that no new part token is requested while creating
the temporary file.
This change also fixes lifecycle issues and ensures that buffer
resources are cleaned in case of errors.

Fixes gh-36694
2026-04-28 23:21:05 +02:00
Sébastien Deleuze 1f642b973b Merge branch '7.0.x' 2026-04-28 11:16:42 +02:00
Dmitry Sulman 8d93670430 Support Micrometer context propagation in Kotlin Flow
See gh-36427
Closes gh-36667
Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
2026-04-28 11:10:55 +02:00
Sébastien Deleuze 29a7402adf Fix WebClient context propagation in Kotlin Coroutines
Prior to this commit, thread-local variables like Trace ID were not
automatically propagated into the Reactor Context when making requests
using Kotlin coroutine WebClient extensions like `awaitExchange`.

This commit updates `CoroutineContext.toReactorContext()` to capture
thread-local values via Micrometer Context Propagation when available,
ensuring observations and traces are properly reused.

Closes gh-36182
2026-04-28 11:10:55 +02:00
Sigurd Gerke 3dfd6838c0 Fix a regression on value class parameter handling
This commit fixes a regression introduced by gh-36449 for
nullable value class with an non-null value.

Closes gh-36665
Signed-off-by: Sigurd Gerke <sigurd.gerke@onedata.de>
2026-04-28 11:10:55 +02:00
Brian Clozel 80c9efd638 Merge branch '7.0.x' 2026-04-28 09:29:26 +02:00
Brian Clozel 32170e5847 Avoid cache collisions in CachingResourceResolver
Prior to this commit, there could be cache collisions in the
`CachingResourceResolver` because the cache key generation was
incomplete. This commit expands the cache key generation to avoid such
cases.

Fixes gh-36713
2026-04-28 09:28:00 +02:00
Sam Brannen 0e1a2b4f87 Merge branch '7.0.x' 2026-04-27 14:01:51 +03:00
Yanming Zhou bfb88cfc1c Remove unnecessary invocations of toString()
Closes gh-36709

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-04-27 11:27:29 +03:00
Yanming Zhou c4dfb24116 Update copyright headers in remaining source files
Closes gh-36703

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-04-27 11:26:35 +03:00
Brian Clozel 5e6e223686 Merge branch '7.0.x' 2026-04-23 16:24:27 +02:00
Brian Clozel 4fb0244b5a Enfoce single version removal in content versioning
Prior to this commit, content based version strategies would remove all
instances of the version string in the request path when trying to
resolve the original resource with the chain.
This can cause issues in rare cases where there is a collision between
the content version and some other version string in the request path.

Because this strategy is based on the contents of the file itself, we
should only remove the last instance of the version string and then
attempt to resolve the original file.

Fixes gh-36698
2026-04-23 15:04:02 +02:00
Brian Clozel 7a5844f1ce Reject unsafe resource handling locations
As of gh-36692, Spring logs a WARN message when an unsafe resource
handling location is configured. This change now rejects entirely such
setups by failing before the application starts up.

Closes gh-36695
2026-04-23 11:29:47 +02:00
Brian Clozel 0d14aa5856 Merge branch '7.0.x' 2026-04-23 10:55:18 +02:00
Brian Clozel 0725bf4941 Warn against unsafe static resource locations
Prior to this commit, `ResourceHandlerUtils` would perform resource
location checks to ensure that the configured location is valid. This
commit also ensures that we log a WARN message if the application
chooses a well-known unsafe location like "classpath:" or the root
Servlet context for serving static resources.

Closes gh-36692
2026-04-23 10:45:15 +02:00
Juergen Hoeller c6096ff6e5 Upgrade to Hibernate ORM 7.3.2 and Woodstox 7.1.1 2026-04-21 20:37:08 +02:00
Juergen Hoeller 6ff758391c Merge branch '7.0.x' 2026-04-21 20:36:27 +02:00
Juergen Hoeller 8965d9bccf Polishing 2026-04-21 20:35:25 +02:00
Juergen Hoeller af7a5716e8 Consistently ignore exceptions for Xerces-specific properties
Closes gh-36682
2026-04-21 20:34:29 +02:00
Brian Clozel ca9b26eb8f Merge branch '7.0.x' 2026-04-21 18:52:41 +02:00
Brian Clozel 83e7aa1131 Update HttpComponents Javadoc URI
Fixes gh-36685
2026-04-21 18:51:58 +02:00
Brian Clozel 279409acce Merge branch '7.0.x' 2026-04-21 17:47:25 +02:00
박동윤 (Park Dong-Yun) 865cf3c117 Avoid redundant URI object creation in WebClientUtils
Prior to this commit, WebClientUtils.getRequestDescription()
created a new URI object on every invocation. Since the URI
constructor includes validation and parsing, which is already
performed by the parameter URI object, this was unnecessarily
expensive for a logging utility.

This commit reuses the original URI's string representation
to avoid redundant parsing.
This commit also strips userInfo, query, and fragment from the
log description even if URIs contain only userInfo or
fragment (without a query).

Closes gh-36641

Signed-off-by: 박동윤 (Park Dong-Yun) <ehddbs7458@gmail.com>
2026-04-21 16:52:33 +02:00
Sam Brannen 4f1b4b36bf Merge branch '7.0.x' 2026-04-17 17:25:53 +02:00
Stéphane Nicoll be70e1c5a7 Next development version (v7.0.8-SNAPSHOT) 2026-04-17 08:33:14 +02:00
Juergen Hoeller 680f4ee482 Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2026-04-16 23:30:21 +02:00
Juergen Hoeller 91852546d9 Upgrade to Reactor 2025.0.5 and Micrometer 1.16.5
Includes Hibernate ORM 7.2.11

Closes gh-36658
Closes gh-36659
2026-04-16 23:28:46 +02:00
Juergen Hoeller 802fa4d65e Refine RetryListener example
See gh-36452
2026-04-16 23:27:59 +02:00
rstoyanchev 59cd577fd1 Merge branch '7.0.x' 2026-04-16 21:15:42 +01:00
rstoyanchev 7052da4532 Add doOnDiscard in MultipartHttpMessageReader
Closes gh-36563
2026-04-16 21:15:09 +01:00
Sébastien Deleuze 9f92183710 Upgrade to Kotlin Serialization 1.11.0
Closes gh-36657
2026-04-16 16:36:56 +02:00
Sam Brannen 680854d1f3 Merge branch '7.0.x' 2026-04-16 16:35:25 +02:00
Sam Brannen 63817ce202 Add missing tests for WebRequestDataBinder
See gh-36625
2026-04-16 16:33:43 +02:00
Sam Brannen 61bd79017f Polish WebRequestDataBinderTests 2026-04-16 16:31:57 +02:00
Sam Brannen 1a7161c85e Merge branch '7.0.x' 2026-04-16 15:12:44 +02:00
Sam Brannen ab6637c670 Completely extract ServletRequestParameterPropertyValuesTests
This aligns with changes to ServletRequestParameterPropertyValuesTests
on 6.2.x.
2026-04-16 15:11:39 +02:00
Sam Brannen 8bce51267a Merge branch '7.0.x' 2026-04-16 14:42:00 +02:00
Sam Brannen c9b88b4ebd Extract ServletRequestParameterPropertyValuesTests 2026-04-16 14:38:17 +02:00
Sam Brannen 68c575ab14 Revise "Skip binding entirely when field is not allowed"
This commit reverts the changes made to WebDataBinder's doBind()
implementation in e4d03f6625 and instead implements the skipping logic
directly in checkFieldDefaults(), checkFieldMarkers(), and
adaptEmptyArrayIndices() by preemptively checking if the corresponding
field is allowed.

This commit also improves the Javadoc and adds missing tests.

Fixes gh-36625
2026-04-16 14:33:50 +02:00
Sam Brannen d169eb547e Polishing 2026-04-15 14:30:03 +02:00
Sam Brannen 9c8535f5e4 Compile SpEL expressions that use Optional with null-safe & Elvis operators
In Spring Framework 7.0, we introduced support for using `Optional`
with the null-safe and Elvis operators in SpEL expressions; however,
such expressions were previously not compilable.

To address that, this commit introduces a new
insertOptionalUnwrapIfNecessary() method in CodeFlow which effectively
inserts byte code instructions for `myOptional.orElse(null)`, and the
Elvis, Indexer, MethodReference, and PropertyOrFieldReference
implementations have been modified to track the need to unwrap an
`Optional` in compiled mode and delegate to
insertOptionalUnwrapIfNecessary() accordingly.

See gh-20433
See gh-36331
Closes gh-36330
2026-04-15 14:09:57 +02:00
Sam Brannen 829add3aa9 Update Javadoc for HttpMethod.valueOf() on main
See gh-36642
See gh-36652
2026-04-14 16:30:56 +02:00
Sam Brannen 20e57608ba Merge branch '7.0.x' 2026-04-14 16:18:23 +02:00
Sam Brannen cb320468db Further clarify semantics of HttpMethod.valueOf()
See gh-36652
2026-04-14 16:17:20 +02:00
angry2.k df828458fa Clarify semantics of HttpMethod.valueOf()
HttpMethod.valueOf() performs a case-sensitive lookup of predefined
HttpMethod constants. For example, valueOf("GET") resolves to
HttpMethod.GET, whereas valueOf("get") results in a newly created
HttpMethod instance.
Update the Javadoc to explicitly document this behavior.

See gh-36642
Closes gh-36652

Signed-off-by: angry-2k <edkev@kakao.com>
2026-04-14 16:15:43 +02:00
Sam Brannen 6275f46a66 Merge branch '7.0.x' 2026-04-13 17:42:59 +02:00
Sam Brannen ff3f2937ab Restructure SpelCompilationCoverageTests using @⁠Nested test classes 2026-04-13 17:42:18 +02:00
Sam Brannen 9a17b5c453 Merge branch '7.0.x' 2026-04-13 12:59:04 +02:00
Sam Brannen d7450ce8e4 Polish SpelCompilationCoverageTests 2026-04-13 12:58:36 +02:00
Sam Brannen 1787d3e885 Merge branch '7.0.x' 2026-04-12 17:17:27 +02:00
Sam Brannen 28f78f435e Introduce missing tests for immediate SpEL compilation for Elvis operator 2026-04-12 17:11:07 +02:00
Sam Brannen a3705632c1 Polish SpEL Ternary and Elvis operators 2026-04-12 17:09:28 +02:00
Sam Brannen 1f5af8f364 Merge branch '7.0.x' 2026-04-12 16:46:39 +02:00
Sam Brannen 84221064c8 Polish SpEl Ternary operator and compilation tests 2026-04-12 16:41:49 +02:00
Sam Brannen a4b33b98df Merge branch '7.0.x' 2026-04-12 14:29:42 +02:00
Sam Brannen 21f3b964fe Improve SpEL tests for Elvis and Ternary operators 2026-04-12 14:28:33 +02:00
Sam Brannen 59f9cf8645 Polish SpEL internals 2026-04-12 14:20:50 +02:00
Sébastien Deleuze fb34264169 Merge branch '7.0.x' 2026-04-10 16:10:45 +02:00
Sébastien Deleuze efb85d68ef Apply nullable value class fix to InvocableHandlerMethod
See gh-36449
2026-04-10 16:03:06 +02:00
T45K b3f01a7f92 Fix nullable value class handling in CoroutinesUtils
Closes gh-36449
Signed-off-by: T45K <tasktas9@gmail.com>
2026-04-10 16:03:06 +02:00
Sébastien Deleuze 22bcac1eb5 Refine Kotlin serialization contribution
This commit moves the JSON specific code to
KotlinSerializationJsonDecoder, uses switchOnFirst operator to keep the
existing behavior and derives the list serializer from the element one.

Closes gh-36597
2026-04-10 16:02:51 +02:00
Dmitry Sulman 546ae15a44 Support JSON list deserialization in KotlinSerializationStringDecoder
See gh-36597
Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
2026-04-10 16:02:51 +02:00
Sam Brannen c2cf5e065d Perform case-insensitive lookup in HttpMethod.valueOf()
Prior to this commit, the implementation of HttpMethod.valueOf()
aligned with the semantics of Enum#valueOf() which requires an exact
match for the enum constant name.

However, since HttpMethod is no longer an enum, that restriction is no
longer necessary. Consequently, this commit revises the implementation
of valueOf() to perform a case-insensitive lookup for predefined
constants.

In other words, HttpMethod.valueOf("GET") and HttpMethod.valueOf("get")
now both resolve to HttpMethod.GET.

Closes gh-36518
2026-04-10 15:04:42 +02:00
Sam Brannen e0e78257d6 Merge branch '7.0.x' 2026-04-09 13:07:19 +02:00
xxxxxxjun 78c32aa7d2 Fix typo in FormTag Javadoc and TLD
Closes gh-36610

Signed-off-by: xxxxxxjun <ryuu.public@gmail.com>
2026-04-09 13:06:31 +02:00
Sam Brannen 227ddf817d Merge branch '7.0.x' 2026-04-09 12:57:01 +02:00
Sam Brannen 99b78adce3 Revise documentation for @⁠ActiveProfiles and ActiveProfilesResolver
See gh-36269
See gh-36600
2026-04-09 12:52:18 +02:00
Sam Brannen 07aa952bed Merge branch '7.0.x' 2026-04-09 12:16:02 +02:00
Mohak-Nagaraju 644731c9f6 Document that spring.profiles.active is ignored by @⁠ActiveProfiles
The Spring TestContext Framework does not honor the
`spring.profiles.active` system property when determining
active profiles for a test class if @⁠ActiveProfiles is
used.

This commit documents that behavior in the @⁠ActiveProfiles
and DefaultActiveProfilesResolver Javadoc, as well as in
the reference manual. A SystemPropertyActiveProfilesResolver
example is also added showing how to allow
`spring.profiles.active` to override @⁠ActiveProfiles.

See gh-36269
Closes gh-36600

Signed-off-by: Mohak Nagaraju <98132980+Mohak-Nagaraju@users.noreply.github.com>
2026-04-09 12:15:33 +02:00
Brian Clozel 598f0b64f0 Merge branch '7.0.x' 2026-04-09 11:02:07 +02:00
Brian Clozel e4d03f6625 Skip binding entirely when field is not allowed
Prior to this commit, fields that are not allowed for binding were
always skipped and would not be bound. But the field and default marker
support (with the "_" and "!" prefixes) would be still considered and
could trigger collection instantiation/autogrow.

While this does not cause unwanted binding, this allocates memory for no
reason. This commit revisits the binding algorithm to only consider
default and field marker support if the regular field is allowed.

Fixes gh-36625
2026-04-09 10:58:57 +02:00
Sam Brannen d4e3d6be58 Merge branch '7.0.x' 2026-04-09 10:36:15 +02:00
Sam Brannen 6251b2c0c9 Support @⁠Sql with DataSource wrapped in a TransactionAwareDataSourceProxy
Prior to this commit, SqlScriptsTestExecutionListener unwrapped data
sources wrapped in an InfrastructureProxy or a scoped proxy, but it did
not unwrap a data source wrapped in a TransactionAwareDataSourceProxy.
Consequently, the sameDataSource() check failed in the latter case,
preventing execution of @⁠Sql scripts.

To address that, this commit revises sameDataSource() to unwrap a
TransactionAwareDataSourceProxy as well, analogous to the
implementations of setDataSource() in DataSourceTransactionManager,
JpaTransactionManager, and HibernateTransactionManager.

Closes gh-36611
2026-04-09 10:35:22 +02:00
Juergen Hoeller 8fe0eec5bf Merge branch '7.0.x' 2026-04-08 16:11:34 +02:00
Sam Brannen f78264d158 Polish contribution
See gh-36626
2026-04-08 16:08:09 +02:00
Junseo Bae 4b0101a9dc Defensively copy sentDate in SimpleMailMessage
Use defensive Date copies for sentDate to avoid shared mutable state.

Apply consistent handling in setSentDate, getSentDate, the copy constructor, and copyTo.

Add regression tests for mutation safety and copy isolation.

Closes gh-36626

Signed-off-by: Junseo Bae <ferrater1013@gmail.com>
2026-04-08 16:07:33 +02:00
Juergen Hoeller 3d211b71b1 Revise target bean exception with consistent message formatting 2026-04-08 15:28:29 +02:00
Sam Brannen e940a38014 Merge branch '7.0.x' 2026-04-08 14:19:16 +02:00
Sam Brannen 18b8f871aa Prevent mockk from transitively pulling in JUnit 4 2026-04-08 14:13:59 +02:00
Juergen Hoeller 623bdfb677 Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2026-04-08 13:43:25 +02:00
Juergen Hoeller d7ddfe8d2e Upgrade to Log4J 2.25.4, Groovy 5.0.5, Hibernate ORM 7.2.10, Mockito 5.23, Checkstyle 13.4 2026-04-08 13:41:57 +02:00
Juergen Hoeller 1687d90a8c Polishing 2026-04-08 13:41:32 +02:00
Juergen Hoeller b8f1005897 Improve SpringValidatorAdapter and MethodValidationAdapter performance
Closes gh-36621
2026-04-08 13:39:20 +02:00
Juergen Hoeller 0150c4ba06 Avoid MessageFormat rendering for exception messages in binding errors
Closes gh-36609
2026-04-08 13:39:10 +02:00
Sam Brannen 8566e7bf55 Favor Class#getTypeName over ClassUtils#getQualifiedName where feasible 2026-04-08 13:27:52 +02:00
Sam Brannen c17f25f939 Fall back to type name in ClassUtils.getCanonicalName()
See gh-36607
2026-04-08 12:39:40 +02:00
Sam Brannen 9da22ecb46 Merge branch '7.0.x' 2026-04-08 12:35:54 +02:00
Sam Brannen b560c7b85d Improve Javadoc for MergedAnnotations 2026-04-08 12:35:24 +02:00
Sam Brannen f602967dbc Consistently supply List to MergedAnnotations.of() 2026-04-08 11:59:24 +02:00
Yanming Zhou f7d3556b8c Polish DisconnectedClientHelper
Use `CollectionUtils::newLinkedHashSet` instead of `LinkedHashSet::new` to avoid resizing.

Closes gh-36618

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-04-08 11:58:36 +02:00
Sam Brannen 813e113ea9 Merge branch '7.0.x' 2026-04-08 11:40:52 +02:00
Sam Brannen 0f05a2e153 Polish ClassFileMethodMetadata 2026-04-08 11:38:07 +02:00
Sam Brannen 306a1f6c99 Merge branch '7.0.x' 2026-04-08 11:14:48 +02:00
Sam Brannen d4cc273c31 Avoid recursion in ClassFileAnnotationMetadata.resolveTypeName()
See gh-36577
2026-04-08 11:13:51 +02:00
Sam Brannen 62c6d67615 Align StandardMethodMetadata with ASM/ClassFile support for getReturnTypeName()
We currently have three implementations of MethodMetadata:

- StandardMethodMetadata (Java reflection)
- SimpleMethodMetadata (ASM)
- ClassFileMethodMetadata (ClassFile API)

The ASM and ClassFile variants return a string equivalent to
Class#getTypeName(); whereas, StandardMethodMetadata currently returns a
binary name using Class#getName() (for example, `[I` instead of `int[]`).

In order to align with the ASM and ClassFile variants and provide
consistent results for all MethodMetadata implementations, this commit
revises StandardMethodMetadata.getReturnTypeName() to use
Class#getTypeName().

Closes gh-36619
2026-04-08 10:27:39 +02:00
Sam Brannen c4c0aca69b Polishing 2026-04-08 10:11:23 +02:00
Sam Brannen 6f08c0b473 Merge branch '7.0.x' 2026-04-07 18:17:00 +02:00
Sam Brannen f3b6c222f9 Use ClassLoader for method or field in MergedAnnotation
Prior to this commit, the `return` keyword was missing in
TypeMappedAnnotation's getClassLoader() implementation, which prevented
the ClassLoader of the Member (Method or Field) from being used.

This commit fixes that by adding the missing `return` keyword and adds
a test using a custom ClassLoader to verify the correct behavior.

Closes gh-36606
2026-04-07 18:16:09 +02:00
Sam Brannen 8d390f4e5a Polish SpEL documentation 2026-04-07 17:54:43 +02:00
daguimu d37d7abb17 Reject unbalanced parentheses in profile expressions
ProfilesParser.parseTokens() silently accepts unbalanced parentheses
in profile expressions such as "dev)" or "(dev", treating them as
valid. This can lead to unexpected behavior where malformed @Profile
annotations are silently interpreted instead of being rejected.

This commit tightens the validation in parseTokens() to reject:
- Unmatched closing parenthesis at the top level
- Unmatched opening parenthesis when tokens are exhausted

Also fixes an existing test that inadvertently relied on this lenient
behavior by using "spring&framework)" instead of "(spring&framework)".

Closes gh-36550

Signed-off-by: daguimu <daguimu.geek@gmail.com>
2026-04-07 15:38:50 +02:00
Sébastien Deleuze 2a1678f246 Merge branch '7.0.x' 2026-04-07 15:11:54 +02:00
Manu Sridharan f5a8c321c0 Address nullness warning from future version of NullAway
Closes gh-36548
Signed-off-by: Manu Sridharan <msridhar@gmail.com>
2026-04-07 15:10:35 +02:00
Brian Clozel 3806315e31 Merge branch '7.0.x' 2026-04-07 11:53:44 +02:00
Brian Clozel 14466eef4c Document valid SpEL separators for tokenizer 2026-04-07 11:52:47 +02:00
Sam Brannen 6062363738 Use canonical names in error messages in annotation processing
Prior to this commit, we invoked `Class.getName()` when building error
messages during annotation processing, resulting in exceptions like the
following which use binary names for nested types and arrays.

  Attribute 'chars' in annotation
  org.springframework.core.annotation.AnnotationUtilsTests$CharsContainer
  should be compatible with [C but a [I value was returned

This commit switches to canonical names in error messages in annotation
processing, resulting in improved such errors messages such as the
following.

  Attribute 'chars' in annotation
  org.springframework.core.annotation.AnnotationUtilsTests.CharsContainer
  should be compatible with char[] but a int[] value was returned

In addition, this commit introduces a new getCanonicalName(Class) method
in ClassUtils, which has effectively been extracted from the following
classes where this functionality was previously duplicated.

- AttributeMethods
- SynthesizedMergedAnnotationInvocationHandler
- TypeDescriptor
- DefaultRetryPolicy
- ReflectiveIndexAccessor

Closes gh-36607
2026-04-06 17:34:54 +02:00
Sam Brannen 31d9fe5f41 Merge branch '7.0.x' 2026-04-06 16:56:26 +02:00
Sam Brannen 9d365906b5 Fix typo 2026-04-06 16:55:32 +02:00
Sam Brannen 97e10a5948 Fix flaky SpEL tests
This commit fixes SpEL related tests that failed if the test methods
were executed in a different order than in the Gradle build.
2026-04-06 16:55:32 +02:00
Sam Brannen bfbfe4a572 Fix BridgeMethodResolverTests.findBridgedMethodInHierarchy() in Eclipse 2026-04-06 16:54:34 +02:00
Sébastien Deleuze 2ee4c3a363 Provide bean conditional registration capabilities in BeanRegistrarDsl
Closes gh-36601
2026-04-05 18:49:07 +02:00
Sam Brannen 82b179f238 Merge branch '7.0.x' 2026-04-04 17:21:16 +02:00
Sam Brannen 38464a15dc Retain source declaration order in AnnotatedTypeMetadata on Java 24+
Prior to this commit, ClassFileAnnotationDelegate created
MergedAnnotations from a HashSet, which resulted in a non-deterministic
iteration order and lost the original source declaration order of the
annotations.

To address that, this commit revises ClassFileAnnotationDelegate to
create MergedAnnotations from a List.

In addition, this commit updates all related tests to use the
containsExactly() assertion instead of containsExactlyInAnyOrder() to
ensure we consistently adhere to the "source declaration order"
requirement.

Closes gh-36598
2026-04-04 17:19:25 +02:00
Sam Brannen c04b502866 Polishing 2026-04-04 17:17:38 +02:00
Sam Brannen f993e9710d Align with JDK by throwing TypeNotPresentException in MergedAnnotations
Prior to this commit, we used ClassUtils.resolveClassName() in
TypeMappedAnnotation.adapt(...) which throws an IllegalStateException
or IllegalArgumentException if a type referenced by an annotation
attribute cannot be loaded. However, if such an error occurs while
using the JDK's reflection APIs, a TypeNotPresentException is thrown
instead.

In order to align with the standard behavior of the JDK, this commit
modifies TypeMappedAnnotation.adapt(...) to use ClassUtils.forName()
and throw a TypeNotPresentException in such scenarios.

This commit also makes similar changes in
MergedAnnotationReadingVisitor and ClassFileAnnotationDelegate.

Closes gh-36593
2026-04-03 16:44:28 +02:00
Sam Brannen 822001c6a4 Merge branch '7.0.x' 2026-04-03 15:42:28 +02:00
xxxxxxjun f2c0ad484e Fix typo in HttpRange error message
Closes gh-36590

Signed-off-by: xxxxxxjun <ryuu.public@gmail.com>
2026-04-03 15:41:14 +02:00
Sam Brannen f2d4d59f5a Merge branch '7.0.x' 2026-04-03 15:39:58 +02:00
Sam Brannen d10460d775 Track class loading exceptions in MergedAnnotation.asMap()
Spring Framework 5.2 introduced a regression in our annotation
processing support when the MergedAnnotations API was introduced.
Consequently, prior to this commit, our "annotation attributes as a Map
or AnnotationAttributes instance" support no longer stored exceptions
thrown while attempting to load a type referenced by an annotation
attribute. Instead, the exception was thrown immediately.

To address that, this commit revises our MergedAnnotation.asMap()
support so that it now tracks such exceptions in the map instead of
immediately throwing them. This allows map functionality such as
contains(attributeName), keySet(), etc. to continue to function
properly. In addition, the internal getRequiredAttribute() method in
AnnotationAttributes once again properly throws the original exception
wrapped in an IllegalArgumentException whenever a caller invokes one of
the convenience methods such as getClass() and getClassArray().

Note that this affects both asMap() variants as well as
asAnnotationAttributes().

In addition, this commit reverts the fix applied in 00fbd91cca since
it is no longer necessary.

See gh-36524
Closes gh-36586
2026-04-03 15:38:36 +02:00
Sam Brannen 4709f68446 Merge branch '7.0.x' 2026-04-02 18:40:08 +02:00
Sam Brannen 1ead8bf1ab Polishing 2026-04-02 18:39:37 +02:00
Sam Brannen afba74c516 Merge branch '7.0.x' 2026-04-02 17:21:10 +02:00
Sam Brannen 7b087d1a6c Disable flaky reactorNettyAttributes() test in WebClientIntegrationTests
See gh-36589
2026-04-02 17:20:38 +02:00
Sam Brannen fd50c0841c Merge branch '7.0.x' 2026-04-02 16:55:02 +02:00
Sam Brannen 00fbd91cca Skip annotations that cannot be processed in AnnotationBeanNameGenerator
Prior to this commit, AnnotationBeanNameGenerator failed when searching
for a convention-based bean name, if an annotation referenced a
non-existent class.

To address that, this commit introduces a try-catch block around each
invocation of MergedAnnotation.asAnnotationAttributes() and skips
processing of the current MergedAnnotation if an exception occurs,
which is likely due to a type referenced from an annotation attribute
not being present in the classpath.

See gh-31203
Closes gh-36524
2026-04-02 16:51:17 +02:00
Brian Clozel cbe8b148b1 Merge branch '7.0.x' 2026-04-02 14:48:56 +02:00
Brian Clozel d87ebbff78 Polishing
See gh-36584
2026-04-02 14:48:09 +02:00
Stéphane Nicoll 2086508924 Polish
See gh-36581
2026-04-02 14:41:26 +02:00
Juergen Hoeller 759b173b1a Merge branch '7.0.x' 2026-04-02 14:31:56 +02:00
Juergen Hoeller e977bd7bf0 Enforce strict implementation of Resource#isReadable() contract
Closes gh-36584
2026-04-02 14:30:51 +02:00
Sam Brannen 7590c4c92e Fix Javadoc link
See gh-36581
2026-04-02 13:32:32 +02:00
Sam Brannen 596c0df826 Merge branch '7.0.x' 2026-04-02 12:45:50 +02:00
Sam Brannen 24c7d31ba7 Polishing 2026-04-02 12:43:28 +02:00
Sam Brannen b6fc3a1b6f Enforce use of AssertJ assumptions via Checkstyle
Closes gh-36582
2026-04-02 12:43:12 +02:00
Sam Brannen d767806977 Ignore .cursor directory 2026-04-02 12:11:58 +02:00
Stéphane Nicoll d5b6f4a7ee Polish BeanRegistrar Javadoc and add tests for non-invocation semantics
Revise the BeanRegistrar Javadoc to document the two distinct usage
modes: @Configuration/@Import and programmatic GenericApplicationContext
setup.

Clarify that implementations are not Spring components (requiring a
no-arg constructor and no dependency injection), and detail the ordering
guarantees for each mode.

Add missing tests

Signed-off-by: Stéphane Nicoll <stephane.nicoll@broadcom.com>
2026-04-02 11:18:58 +02:00
Sam Brannen 5dc4a3a7a0 Merge branch '7.0.x' 2026-04-02 11:06:39 +02:00
Sam Brannen c5b9c3d604 Add 2D array tests, use AssertJ assumptions, and polish
See gh-36577
2026-04-02 11:05:59 +02:00
Brian Clozel 21f8b6d2f3 Merge branch '7.0.x' 2026-04-02 10:19:55 +02:00
Brian Clozel 40ef6f6872 Fix method and annotation metadata for ClassFile variant
Prior to this commit, the ClassFile variant for  annotation and method
metadata would report incorrect metadata for:
* the method return type names in case of primitives and array types
* `toString` values for methods
* `equals` and `hashcode` information for methods

This commit expands the test suite and ensures that the ASM and
ClassFile variants are aligned.

Fixes gh-36577

Signed-off-by: Brian Clozel <brian.clozel@broadcom.com>
2026-04-02 10:18:13 +02:00
Junseo Bae b01fdb0140 Fix ClassFileMethodMetadata return type names for primitives and arrays
Return correct names for primitive and array types
Introduce resolveTypeName helper for ClassDesc handling
Add ClassFileMethodMetadataTests (java24Test)
Extend AbstractMethodMetadataTests with void return case

See gh-36577

Signed-off-by: Junseo Bae <ferrater1013@gmail.com>
2026-04-02 10:17:21 +02:00
Juergen Hoeller 6ebaeba1c2 Merge branch '7.0.x' 2026-04-01 21:17:00 +02:00
Juergen Hoeller 3f01e3fe11 Polishing 2026-04-01 21:15:58 +02:00
Juergen Hoeller e78af58af3 Fix Writer lifecycle for writeInternal(Object, Type, Writer)
Closes gh-36565
2026-04-01 21:15:50 +02:00
Juergen Hoeller 3bf31e45dd Replace DeferredBeanRegistrar with implicit ordering semantics
GenericApplicationContext-registered BeanRegistrars are invoked after other programmatic bean definitions. Configuration-imported BeanRegistrars participate in configuration class order and in particular in Boot's auto-configuration ordering.

Closes gh-21497
2026-04-01 20:59:45 +02:00
Brian Clozel 5e16e25109 Merge branch '7.0.x' 2026-04-01 11:06:24 +02:00
Brian Clozel aebf7c97f7 Register overrides in HttpMessageConverters when defaults are off
Prior to this commit, all `with**Converter` methods in
`HttpMessageConverters` builders would only apply if the
`registerDefaults()` option is on. While the original intent is to allow
overrides for auto-detected defaults, this creates an unnecessary
discrepancy with `addCustomConverter` which is always effective.

Allowing sich registrations when defaults are off should not introduce
invalid states and only reflects the intent of the developer. This
commit now allows such cases.

Fixes gh-36579
2026-04-01 10:49:55 +02:00
Sam Brannen 6b5f0e92b1 Merge branch '7.0.x' 2026-04-01 10:15:08 +02:00
Sam Brannen 7b8d8693dd Fix AnnotationMetadata tests in Eclipse IDE
Since commit 89391fd94c, the getClassAttributeWhenUnknownClass() methods
in SimpleAnnotationMetadataTests and DefaultAnnotationMetadataTests
have failed in Eclipse, since the JSR-305 JAR is always on the test
runtime classpath in Eclipse.

To address that, this commit introduces a FilteringClassLoader in both
test classes which mimics the test runtime behavior in the Gradle build.

See gh-36432
2026-04-01 10:13:06 +02:00
Brian Clozel 2c973d3034 Mention when RestTemplate will be removed
`RestTemplate` is deprecated, this commit amends the JavaDoc to mention
its scheduled removal for the next major version, Spring Framework 8.0.

See gh-36574
2026-03-31 22:03:36 +02:00
Brian Clozel 94e2f49e9f Read multipart requests from RestTestClient
Prior to this commit, the `RestTestClient` MockMvc integration would
support transforming client requests into MockMvc requests.
`RestTestClient` can serialize `MultiValueMap` request bodies as
multipart requests. In this case, the `MockMvcClientHttpRequestFactory`
would only read the body as byte stream and would not turn this into a
proper `MockMultipartHttpServletRequestBuilder`.

This commit uses the new `MultipartHttpMessageConverter` to parse the
request payload as `MockPart` instances to be added to the MockMvc
requests.

Closes gh-35569
2026-03-31 19:13:06 +02:00
Yanming Zhou 8b62ea13a1 Remove deprecated methodIdentification() method in CacheAspectSupport
The Javadoc said it's used for logging, but it's not used anywhere.

Closes gh-36560

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
Signed-off-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
2026-03-31 17:56:47 +02:00
Sam Brannen 76ad7c9cc0 Merge branch '7.0.x' 2026-03-31 17:50:15 +02:00
Sam Brannen 22adccd190 Deprecate methodIdentification() in CacheAspectSupport for removal
CacheAspectSupport currently contains a protected methodIdentification()
method which is not used internally within the framework, and it appears
that it was accidentally copied from TransactionAspectSupport when the
caching support was first introduced.

In light of that, this commit deprecates it for removal in 7.1.

Closes gh-36576
2026-03-31 17:49:21 +02:00
rstoyanchev 8586095370 Merge branch '7.0.x' 2026-03-31 16:22:16 +01:00
rstoyanchev d4d49fd546 Make base classes for client requests public
AbstractBufferingClientHttpRequest and AbstractStreamingClientHttpRequest

Closes gh-36501
2026-03-31 14:11:17 +01:00
Sébastien Deleuze 32970fe10d Fix WebClient context propagation in Kotlin Coroutines
Prior to this commit, thread-local variables like Trace ID were not
automatically propagated into the Reactor Context when making requests
using Kotlin coroutine WebClient extensions like `awaitExchange`.

This commit updates `CoroutineContext.toReactorContext()` to capture
thread-local values via Micrometer Context Propagation when available,
ensuring observations and traces are properly reused.

Closes gh-36182
2026-03-31 14:45:55 +02:00
Brian Clozel 83c2afb643 Deprecate RestTemplate and related types
As announced in "the state of HTTP clients in Spring" blog post
(https://spring.io/blog/2025/09/30/the-state-of-http-clients-in-spring),
the deprecation timeline for `RestTemplate` was announced last November
and docs were updated accordingly.

This commit `@Deprecate` `RestTemplate` and related types for removal to
send a stronger signal to our community.
The actual removal is scheduled for Spring Framework 8.0 (not yet
scheduled).

Closes gh-36574
2026-03-31 12:28:44 +02:00
KimDaehyeon 730f824cad Fix Javadoc in HandlerMethodReturnValueHandlerComposite
Closes gh-36555

Signed-off-by: KimDaehyeon <daehyeon3351@gmail.com>
2026-03-31 11:19:52 +01:00
rstoyanchev 7473cd5fbc Merge branch '7.0.x' 2026-03-31 11:00:51 +01:00
rstoyanchev 2dcd56bbaf Polishing contribution
Closes gh-36514
2026-03-31 11:00:22 +01:00
Vishnutheep B 00be6d3afd Add null check when setting API version to preserve default value
See gh-36514

Signed-off-by: Vishnutheep B <vishnutheep@gmail.com>
2026-03-31 11:00:22 +01:00
rstoyanchev ebe3b45743 Consistently log request details in ExchangeFunctions
Closes gh-36502
2026-03-31 11:00:22 +01:00
Brian Clozel 8de3683ccb Merge branch '7.0.x' 2026-03-31 11:47:41 +02:00
Brian Clozel 9c4b246c8c Use RestClient in integration tests
Now that `RestClient` offers a better alternative, this commit revisits
our integration tests to use `RestClient` instead of `RestTemplate`.

Closes gh-36573
2026-03-31 11:37:43 +02:00
Brian Clozel f850b051b5 Add MockRestServiceServer#createServer variant for RestClient
Prior to this commit, `MockRestServiceServer` would provide
`createServer` shortcuts for `RestTemplate` and `RestGatewaySupport`.

Now that `RestClient` offers a modern client variant, we should provide
the same for `RestClient`.

Closes gh-36572
2026-03-31 11:20:44 +02:00
Brian Clozel 208f62ba07 Merge branch '7.0.x' 2026-03-31 11:02:57 +02:00
Brian Clozel c9c137ec51 Create and use RestClientXhrTransport
Prior to this commit, the `SockJsClient` would use the
`RestTemplateXhrTransport`. `RestClient` is a modern replacement for
RestTemplate and should be used instead.

This commit introduces the `RestClientXhrTransport` variant as an
immediate replacement.

Closes gh-36566
2026-03-31 11:02:33 +02:00
Sébastien Deleuze a0d51c8f7d Upgrade to Dokka 2.2.0
Closes gh-36570
2026-03-31 09:40:46 +02:00
Sébastien Deleuze f4cefb6ec5 Upgrade to Jackson 3.1 and 2.21
This commit raises the Jackson baseline and upgrades related
dependencies to Jackson 3.1 and 2.21 which are the new LTS.

Closes gh-36130
2026-03-31 09:21:48 +02:00
Sam Brannen e7fdbb8339 Merge branch '7.0.x' 2026-03-30 17:01:56 +02:00
Sam Brannen b7a1157e66 Correct Javadoc for MergedAnnotation.asAnnotationAttributes()
Closes gh-36567
2026-03-30 16:59:57 +02:00
Sam Brannen 27bc60e077 Polishing 2026-03-30 16:59:24 +02:00
Sam Brannen a64b001f6a Use AtomicBoolean as a "plain" holder in BeanOverrideUtils
Since the AtomicBoolean cannot be accessed by another thread, there is
no need to use compareAndSet().
2026-03-30 13:44:12 +02:00
Sam Brannen c68470d0fd Simplify Bean Override support in the SpringExtension
See gh-36096
2026-03-30 13:22:12 +02:00
Sam Brannen 182e6b744a Polishing 2026-03-30 13:22:12 +02:00
rstoyanchev d46e96f1ca Correct ApiVersionConfigurer method signature
Closes gh-36551
2026-03-30 12:07:06 +01:00
Sam Brannen 51a5489438 Polishing 2026-03-29 17:34:32 +02:00
Sam Brannen f9523a785b Support @⁠MockitoBean and @⁠MockitoSpyBean on test constructor parameters
Prior to this commit, @⁠MockitoBean and @⁠MockitoSpyBean could be
declared on fields or at the type level (on test classes and test
interfaces), but not on constructor parameters. Consequently, a test
class could not use constructor injection for bean overrides.

To address that, this commit introduces support for @⁠MockitoBean and
@⁠MockitoSpyBean on constructor parameters in JUnit Jupiter test
classes. Specifically, the Bean Override infrastructure has been
overhauled to support constructor parameters as declaration sites and
injection points alongside fields, and the SpringExtension now
recognizes composed @⁠BeanOverride annotations on constructor
parameters in supportsParameter() and resolves them properly in
resolveParameter(). Note, however, that this support has not been
introduced for @⁠TestBean.

For example, the following which uses field injection:

   @⁠SpringJUnitConfig(TestConfig.class)
   class BeanOverrideTests {

      @⁠MockitoBean
      CustomService customService;

      // tests...
   }

Can now be rewritten to use constructor injection:

   @⁠SpringJUnitConfig(TestConfig.class)
   class BeanOverrideTests {

      private final CustomService customService;

      BeanOverrideTests(@⁠MockitoBean CustomService customService) {
         this.customService = customService;
      }

      // tests...
   }

With Kotlin this can be achieved even more succinctly via a compact
constructor declaration:

   @⁠SpringJUnitConfig(TestConfig::class)
   class BeanOverrideTests(@⁠MockitoBean val customService: CustomService) {

      // tests...
   }

Of course, if one is a fan of so-called "test records", that can also
be achieved succinctly with a Java record:

   @⁠SpringJUnitConfig(TestConfig.class)
   record BeanOverrideTests(@⁠MockitoBean CustomService customService) {

      // tests...
   }

Closes gh-36096
2026-03-29 17:17:16 +02:00
Juergen Hoeller 955f9d3ea9 Merge branch '7.0.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/BeanRegistryAdapter.java
#	spring-context/src/main/java/org/springframework/context/annotation/Import.java
2026-03-28 20:41:57 +01:00
Juergen Hoeller 0abf97ff90 Polishing 2026-03-28 20:38:03 +01:00
Juergen Hoeller 7502b92392 Introduce DeferredBeanRegistrar and BeanRegistry#containsBean methods
Closes gh-21497
2026-03-28 20:27:23 +01:00
Juergen Hoeller 99e7543a7f Merge branch '7.0.x' 2026-03-28 11:13:56 +01:00
Juergen Hoeller f0f447a73d Upgrade to Netty 4.2.12 2026-03-28 11:13:04 +01:00
Juergen Hoeller b81a63fb5c Polishing 2026-03-28 11:12:28 +01:00
Juergen Hoeller 529a6fc932 Add documentation notes on error handling with sync=true
See gh-36531
2026-03-28 11:11:52 +01:00
Juergen Hoeller e964ced1ad Make ApplicationListenerMethodAdapter#getTargetMethod() public
Closes gh-36558
2026-03-28 11:11:46 +01:00
Sam Brannen 82a9d66079 Merge branch '7.0.x' 2026-03-27 11:26:11 +01:00
Junseo Bae ff30329861 Fix incorrect method name in TypeDescriptor.array() Javadoc
Closes gh-36549

Signed-off-by: Junseo Bae <ferrater1013@gmail.com>
2026-03-27 11:25:40 +01:00
Sam Brannen 5708b73ea9 Introduce ResolvableType.forParameter() factory method
Prior to this commit, one could invoke
ResolvableType.forMethodParameter(MethodParameter.forParameter(parameter))
to create a ResolvableType for a Parameter; however, that's slightly
cumbersome.

To address that, this commit introduces ResolvableType.forParameter(),
analogous to existing convenience factory methods in ResolvableType.

Closes gh-36545
2026-03-26 16:43:50 +01:00
Sam Brannen 5e975f51dd Remove redundant Assert.notNull() checks in ResolvableType
Since equivalent Assert.notNull() checks are already performed by
subsequent code (constructors and factory methods), there is no need
to perform the exact same assertion twice in such use cases.

Closes gh-36544
2026-03-26 16:40:17 +01:00
Sam Brannen ccf0cae18c Polishing 2026-03-26 15:22:04 +01:00
Brian Clozel de0dfe5d93 Fix Javadoc format error
See gh-33263
2026-03-26 15:19:20 +01:00
Brian Clozel aac521c116 Add integration tests and docs for multipart support
This commit adds integration tests and reference documentation
 for multipart support in `RestClient` and `RestTestClient`.

Closes gh-35569
Closes gh-33263
2026-03-26 15:10:01 +01:00
Brian Clozel ab8de8ec4b Support Map payloads in FormHttpMessageConverter
Prior to this commit, the `FormHttpMessageConverter` would only support
`MultiValueMap` payloads for reading and writing. While this can be
useful when web forms contain multiple values under the same key, this
prevent developers from using a common `Map` type and factory methods
like `Map.of(...)`.

This commit relaxes constraints in `FormHttpMessageConverter` and
ensures that `Map` types are supported for reading and writing URL
encoded forms.
Note that when reading forms to a `Map`, only the first value for each
key will be considered and other values will be dropped if they exist.

Closes gh-36408
2026-03-26 15:09:44 +01:00
Brian Clozel abc3cfc7be Move multipart support to dedicated converter
Prior to this commit, gh-36255 introduced the new
`MultipartHttpMessageConverter`, focusing on multipart message
conversion in a separate converter. The `FormHttpMessageConverter` did
conflate URL encoded forms and multipart messages in the same converter.

With the introduction of the new converter and related types in the same
package (with `Part`, `FormFieldPart` and `FilePart`), we can now
revisit this arrangement.

This commit restricts the `FormHttpMessageConverter` to URL encoded
forms only and as a result, changes its implementation to only consider
`MultiValueMap<String, String>` types for reading and writing HTTP
messages. Because type erasure, this converter is now a
`SmartHttpMessageConverter` to get better type information with
`ResolvableType`.

As a result, the `AllEncompassingFormHttpMessageConverter` is formally
deprecated and replaced by the `MultipartHttpMessageConverter`, by
setting part converters explicitly in its constructor.

Closes gh-36256
2026-03-26 15:08:58 +01:00
Brian Clozel 44302aca93 Add MultipartHttpMessageConverter
Prior to this commit, the `FormHttpMessageConverter` would write, but
not read, multipart HTTP messages. Reading multipart messages is
typicaly performed by Servlet containers with Spring's
`MultipartResolver` infrastructure.

This commit introduces a new `MultipartHttpMessageConverter` that copies
the existing feature for writing multipart messages, borrowed from
`FormHttpMessageConverter`. This also introduces a new `MultipartParser`
class that is an imperative port of the reactive variant, but keeping it
based on the `DataBuffer` abstraction. This will allow us to maintain
both side by side more easily.

This change also adds new `Part`, `FilePart` and `FormFieldPart` types
that will be used when converting multipart messages to
`MultiValueMap<String, Part>` maps.

Closes gh-36255
2026-03-26 15:08:22 +01:00
Brian Clozel ac86dc1264 Move multipart test files to a common location
This commit moves "*.multipart" test files to a common location
in order to share these resources with another test suite.

Closes gh-36253
2026-03-26 15:08:01 +01:00
Brian Clozel 051219c3c9 Introduce HttpMessageConverter#canWriteRepeatedly
The `AbstractHttpMessageConverter#supportsRepeatableWrites`
contract is a protected method that message converters can override.
This method tells whether the current converter can write several
times the payload given as a parameter. This is mainly useful on the
client side, where we need to know if we can send the same HTTP
message again, after receiving an HTTP redirect status.

Because this method is protected, this limits our ability to call
it from a different package; this is needed for gh-33263.

This commit promotes this method to the main `HttpMessageConverter`
interface and deprecates the former.

Closes gh-36252
2026-03-26 15:07:48 +01:00
Sam Brannen d8916a326a Merge branch '7.0.x' 2026-03-26 14:29:16 +01:00
Sam Brannen 6d3d3d11c4 Introduce Kotlin examples for Bean Overrides (@⁠MockitoBean, etc.)
This commit introduces Kotlin examples in the reference manual for
@⁠MockitoBean, @⁠MockitoSpyBean, and @⁠TestBean.

Closes gh-36541
2026-03-26 14:28:36 +01:00
Brian Clozel 3be51b1c77 Merge branch '7.0.x' 2026-03-25 21:53:09 +01:00
Brian Clozel 9140ed6fa9 Fix SSE flushing in SseServerResponse
Prior to this commit, `SseServerResponse.send()` would flush the
output stream returned by `getBody()`. Since gh-36385,
`ServletServerHttpResponse` wraps this stream with a non-flushing
decorator to avoid performance issues with `HttpMessageConverter`
implementations that flush excessively. As a result, SSE events were
no longer flushed to the client.

This commit changes `send()` to call `outputMessage.flush()` instead
of `body.flush()`, which properly delegates to the servlet response
`flushBuffer()` and is not affected by the non-flushing wrapper.

Fixes gh-36537
2026-03-25 21:45:24 +01:00
Sam Brannen a3118f276f Remove @⁠ContextConfiguration from MockitoBeanNestedTests
See gh-31456
2026-03-25 17:46:48 +01:00
Sam Brannen 3d70074089 Introduce support for custom parameter names in ParameterResolutionDelegate
The resolveDependency() utility method in ParameterResolutionDelegate
resolves a dependency using the name of the parameter as a fallback
qualifier. That suffices for most use cases; however, there are times
when a custom parameter name should be used instead.

For example, for our Bean Override support in the Spring TestContext
Framework, an annotation such as @⁠MockitoBean("myBean") specifies an
explicit name that should be used instead of name of the annotated
parameter.

Furthermore, introducing support for custom parameter names will
greatly simplify the logic in SpringExtension that will be required to
implement #36096.

To address those issues, this commit introduces an overloaded variant
of resolveDependency() which accepts a custom parameter name.
Internally, a custom DependencyDescriptor has been implemented to
transparently support this use case.

See gh-36096
Closes gh-36534
2026-03-25 13:15:15 +01:00
Sam Brannen bcc9e27dd0 Polishing 2026-03-25 12:41:05 +01:00
Sam Brannen 0f4ee906de Extract BeanOverrideUtils from BeanOverrideHandler
Prior to this commit, BeanOverrideHandler contained a large amount of
logic solely related to search algorithms for finding handlers.
Consequently, BeanOverrideHandler took on more responsibility than it
ideally should. In addition, we will soon increase the complexity of
those search algorithms, and we will need to make another utility
method public for use outside the bean.override package.

To address those issues, this commit extracts the search utilities from
BeanOverrideHandler into a new BeanOverrideUtils class.

Closes gh-36533
2026-03-25 11:58:49 +01:00
Juergen Hoeller 5f9dd9e135 Merge branch '7.0.x' 2026-03-24 23:50:32 +01:00
Juergen Hoeller 6cea397bd8 Consistent handling of early setCatalog/setSchema/setHoldability calls
Closes gh-36527
Closes gh-36528
2026-03-24 23:40:43 +01:00
Juergen Hoeller 5335dbf802 Merge branch '7.0.x' 2026-03-24 18:08:10 +01:00
Juergen Hoeller 484599ecbb Upgrade to EclipseLink 5.0.0 GA 2026-03-24 18:06:33 +01:00
Juergen Hoeller 1ff369d1ce Document RetryTemplate#invoke variants in reference manual
Closes gh-36452
2026-03-24 18:06:24 +01:00
Brian Clozel 4c1b4f33a8 Skip Jaxb auto-detection in HttpMessageConverters for servers
Prior to this commit, `HttpMessageConverters` would consider the JAXB
message converters when building `HttpMessageConverters` instances.
We noticed that, on the server side, the Jakarta JAXB dependency is very
common on the classpath and often brought transitively. At runtime, this
converter can use significant CPU resources when checking the
`canRead`/`canWrite` methods. This can happen when content types aren't
strictly called out on controller endpoints.

This commit changes the auto-detection mechanism in
`HttpMessageConverters` to not consider the JAXB message converter for
server use cases.
For client use cases, we keep considering this converter as the runtime
cost there is lower.

Closes gh-36302
2026-03-24 17:23:49 +01:00
Brian Clozel f1a60f1664 Merge branch '7.0.x' 2026-03-24 13:19:49 +01:00
Brian Clozel ede46647e8 Link observability section to Micrometer Observation Handler docs
This commit links the Spring Framework Observability section in the
reference documentation to the Micrometer docs describing how
Observations are handled as metrics.

Closes gh-34994
2026-03-24 13:18:52 +01:00
Sam Brannen d66e6571c1 Merge branch '7.0.x' 2026-03-24 11:07:55 +01:00
Sam Brannen 7f7f7c5f5b Invoke assertIsMock() before configuring mocks 2026-03-24 11:07:38 +01:00
Brian Clozel dc8b9fff57 Merge branch '7.0.x' 2026-03-24 10:26:04 +01:00
Brian Clozel d1950f598a Fix response stream handling in RestClient
Prior to this commit, the `DefaultRestClient` implementation would
look at the type of the returned value to decide whether the HTTP
response stream needs to be closed before returning.
As of gh-36380, this checks for `InputStream` and `InputStreamResource`
return types, effectively not considering `ResponseEntity<InputStream>`
and variants.

This commit ensures that `ResponseEntity` types are unwrapped before
checking for streaming types.

Fixes gh-36492
2026-03-24 10:18:32 +01:00
Yanming Zhou 0eba6f0da3 Add typesafe method to get generic bean by name with type reference
Fix GH-34687

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-03-24 08:02:58 +01:00
Juergen Hoeller a5579614d9 Merge branch '7.0.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2026-03-23 20:14:26 +01:00
Juergen Hoeller a01dd1cd79 Upgrade to Tomcat 11.0.20, Hibernate ORM 7.2.7, Protobuf 4.34.1 2026-03-23 20:13:03 +01:00
Juergen Hoeller 86924d067b Add registerManagedResource variant with bean key argument
Closes gh-36520
2026-03-23 20:12:40 +01:00
Juergen Hoeller f0472ea1c0 Polishing (includes nullable declaration for internal type array) 2026-03-23 20:11:54 +01:00
Juergen Hoeller eca6d91532 Refine nullable declaration of internal type array constant 2026-03-23 17:11:32 +01:00
Juergen Hoeller 354c315f55 Upgrade to Hibernate ORM 7.3
Closes gh-36519
2026-03-23 17:11:21 +01:00
Brian Clozel a302ad88f3 Merge branch '7.0.x' 2026-03-23 14:35:05 +01:00
elgun.shukurov 4b211643bb Handle blank Accept-Language header in AcceptHeaderLocaleResolver
When the Accept-Language header is present but blank, defaultLocale
was ignored and fell back to Locale.getDefault() (JVM system locale).
A blank header represents the same intent as an absent header.

Closes gh-36513

Signed-off-by: elgun.shukurov <elgun.sukurov@kapitalbank.az>
2026-03-23 14:28:27 +01:00
Sam Brannen 447e1ee0cd Merge branch '7.0.x' 2026-03-23 11:50:36 +01:00
Junseo Bae f92e810831 Fix incorrect cross reference in AbstractEnvironment Javadoc
Closes gh-36516

Signed-off-by: Junseo Bae <ferrater1013@gmail.com>
2026-03-23 11:49:39 +01:00
Sam Brannen bef2f4488f Merge branch '7.0.x' 2026-03-23 11:36:48 +01:00
Sam Brannen 9fba394b8a Sync changes to antora-playbook.yml from docs-build branch 2026-03-23 11:36:26 +01:00
Sam Brannen d5adfd7980 Merge branch '7.0.x' 2026-03-22 18:04:53 +01:00
Sam Brannen 0005ec09c2 Fix link to SpringProperties
See gh-36460
2026-03-22 18:04:33 +01:00
Sam Brannen 3777a9fcbd Merge branch '7.0.x' 2026-03-22 17:33:01 +01:00
Sam Brannen 0e800538c0 Fix warning in ConcurrentOperationExecutor.kt
Prior to this commit, the following warning was emitted in the build.

w: file:///<path>/spring-framework/framework-docs/src/main/kotlin/org/springframework/docs/core/aop/ataspectj/aopataspectjexample/ConcurrentOperationExecutor.kt:57:29 Unnecessary non-null assertion (!!) on a non-null receiver of type 'PessimisticLockingFailureException'.
2026-03-22 17:31:14 +01:00
Sam Brannen 7c834224a2 Merge branch '7.0.x' 2026-03-22 16:56:20 +01:00
Sam Brannen 43b01382ed Support global ExtensionContext scope configuration for SpringExtension
Prior to this commit, the extension context scope used by the
SpringExtension defaulted to test-method scoped and could only be
changed on a per-class basis via the @⁠SpringExtensionConfig
annotation. However, having to annotate each affected test class is
cumbersome for developers who wish to use test-class scoped extension
context semantics across their code base.

To address that, this commit introduces support for configuring the
global default extension context scope for the SpringExtension via
Spring properties or JUnit properties.

Specifically, this commit introduces a
`spring.test.extension.context.scope` property that can be set via the
SpringProperties mechanism or via a JUnit Platform configuration
parameter.

See gh-35697
Closes gh-36460
2026-03-22 16:48:41 +01:00
Paul Ngo (Do Not Bug) c1e90d51ca GenericTypeResolver.resolveType should resolve TypeVariable with nested ParameterizedType (#36480)
Signed-off-by: anaconda875 <hflbtmax@gmail.com>
2026-03-21 13:28:12 +01:00
Juergen Hoeller a0dba60fa6 Merge branch '7.0.x' 2026-03-21 12:45:25 +01:00
Juergen Hoeller 3a35c4dbd0 Consistent IOException spelling in class/method names 2026-03-21 12:13:39 +01:00
Juergen Hoeller 4c854d564c Avoid endless re-interruption loop on shutdown
Closes gh-36506
2026-03-21 12:04:29 +01:00
Juergen Hoeller de562deab0 Recognize error code 149 as deadlock loser (MySQL Galera)
Closes gh-36499
2026-03-21 12:04:00 +01:00
Brian Clozel 63e01cf6b3 Merge branch '7.0.x' 2026-03-20 15:56:10 +01:00
Brian Clozel 0b2e3900b9 Share codings resolution in resource resolvers
Prior to this commit, different resource resolvers would resolve
accepted codings from the HTTP request sent by the client. This would be
done with different implementations, which could lead to resolution
errors and desynchronizations.

This commit now introduced a new shared method in
`EncodedResourceResolver` (Servlet and Reactive) to perform a consisten
resolution.

Fixes gh-36507
2026-03-20 15:47:09 +01:00
Sam Brannen 5d45036c09 Merge branch '7.0.x' 2026-03-20 11:13:01 +01:00
Sam Brannen e1e4d52b61 Clean up AssertJ usage after migration
- Avoid the use of assertThat(Arrays.equals(...))
- Convert assertThat(Boolean.FALSE).isEqualTo(x) to assertThat(x).isEqualTo(Boolean.FALSE)
- Convert assertThat(Boolean.TRUE).isEqualTo(x) to assertThat(x).isEqualTo(Boolean.TRUE)
- Convert assertThat(x.equals(y)).isTrue() to assertThat(x).isEqualTo(y)
- Convert assertThat(x.equals(y)).isFalse() to assertThat(x).isNotEqualTo(y)
- Remove unnecessary parentheses in assertThat() arguments
- Convert assertThat(x instanceof X).isFalse() to assertThat(x).isNotInstanceOf()
- Convert assertThat(x instanceof X).isTrue() to assertThat(x).isInstanceOf()
- Convert assertThat(!x).isTrue() to assertThat(x).isFalse()
- Inline conditions in assertThat() statements

Closes gh-36504
2026-03-20 11:07:42 +01:00
Sam Brannen 8ca0262e2f Avoid the use of assertThat(Arrays.equals(...))
See gh-36504
2026-03-20 10:54:57 +01:00
Sam Brannen 29ea530525 Convert assertThat(Boolean.FALSE).isEqualTo(x) to assertThat(x).isEqualTo(Boolean.FALSE)
See gh-36504
2026-03-20 10:54:54 +01:00
Sam Brannen ac10d079df Convert assertThat(Boolean.TRUE).isEqualTo(x) to assertThat(x).isEqualTo(Boolean.TRUE)
See gh-36504
2026-03-20 10:54:46 +01:00
Sam Brannen 87c4acd7ac Convert assertThat(x.equals(y)).isTrue() to assertThat(x).isEqualTo(y)
Search:

  assertThat\((?!\s*Arrays\.)((?:[^()]+|\([^()]*\))+)\.equals\(\s*((?:[^()]+|\([^()]*\))+)\s*\)\)(.*)\.isTrue\(\)

Replace:

  assertThat($1)$3.isEqualTo($2)

See gh-36504
2026-03-20 10:54:42 +01:00
Sam Brannen 2ce21f7654 Convert assertThat(x.equals(y)).isFalse() to assertThat(x).isNotEqualTo(y)
Search:

  assertThat\((?!\s*Arrays\.)(.+?)\.equals\((.+?)\)\)(.*?)\.isFalse\(\)

Replace:

  assertThat($1)$3.isNotEqualTo($2)

See gh-36504
2026-03-20 10:54:37 +01:00
Sam Brannen 9e6504b05a Remove unnecessary parentheses in assertThat() arguments
Search:  assertThat\(\(\s*((?:[^()]+|\([^()]*\))+)\s*\)\)(\s*\..+)

Replace: assertThat($1)$2

See gh-36504
2026-03-20 10:54:31 +01:00
Sam Brannen 399f779c43 Convert assertThat(x instanceof X).isFalse() to assertThat(x).isNotInstanceOf()
Search:  assertThat\((.+?) instanceof (.+?)\)(.*?)\.isFalse\(\)

Replace: assertThat($1)$3.isNotInstanceOf($2.class)

See gh-36504
2026-03-20 10:54:27 +01:00
Sam Brannen a40ec44cb7 Convert assertThat(x instanceof X).isTrue() to assertThat(x).isInstanceOf()
Search:  assertThat\((.+?) instanceof (.+?)\)(.*?)\.isTrue\(\)

Replace: assertThat($1)$3.isInstanceOf($2.class)

See gh-36504
2026-03-20 10:54:23 +01:00
Sam Brannen 4357bbd31b Convert assertThat(!x).isTrue() to assertThat(x).isFalse()
Search:  assertThat\(\!(.+?)\)(.*?)\.isTrue\(\)

Replace: assertThat($1)$2.isFalse()

See gh-36504
2026-03-20 10:54:13 +01:00
Sam Brannen 4548f1ec66 Inline conditions in assertThat() statements
Search: assertThat\(conditions?[0-9]?\)

See gh-36504
2026-03-20 10:53:54 +01:00
Sam Brannen b31f78de50 Merge branch '7.0.x' 2026-03-19 14:16:58 +01:00
Sam Brannen 9e71dc6029 Upgrade to Gradle 9.4.1
Closes gh-36500
2026-03-19 14:05:14 +01:00
Sam Brannen 967fd099f9 Merge branch '7.0.x' 2026-03-19 14:02:36 +01:00
Sam Brannen 0daa5ce631 Polishing
(cherry-picked from b846a29b17)
2026-03-19 14:02:11 +01:00
rstoyanchev e655edafec Merge branch '7.0.x' 2026-03-19 09:12:49 +00:00
rstoyanchev 8817536e5a Lower log level of cache miss in HandlerMappingIntrospector
See gh-36309
2026-03-19 09:10:43 +00:00
rstoyanchev cdbaee11c1 Add PreFlightRequestFilter
Closes gh-36482
2026-03-19 09:10:04 +00:00
Sam Brannen 6ec2455e24 Merge branch '7.0.x' 2026-03-18 18:39:17 +01:00
Sam Brannen 1256307c83 Enable SpringJUnit5 Checkstyle rule
See gh-36496
Closes gh-36496
2026-03-18 18:38:43 +01:00
Sam Brannen 003d8b2f80 Merge branch '7.0.x' 2026-03-18 18:19:31 +01:00
Sam Brannen 4c14abf0cd Remove obsolete "test" prefix from test method names
Although this commit also changes the visibility of some test methods
to package-private, the remainder of that task will be addressed in
conjunction with gh-36496.

Closes gh-36495
2026-03-18 18:16:15 +01:00
Sam Brannen b846a29b17 Polishing 2026-03-18 17:42:18 +01:00
박준형 8b994be381 Remove unnecessary space in contributing guide title
Closes gh-36491

Signed-off-by: junhyung8795 <junhyung8795@naver.com>
2026-03-18 15:43:45 +01:00
Brian Clozel b246fc881b Merge branch '7.0.x' 2026-03-18 12:19:22 +01:00
Tobias Fasching a81367f686 Use ISO-8859-1 for fallback filename
Updates the Content-Disposition header creation logic to use only
ISO-8859-1 characters for the fallback 'filename' parameter instead of
RFC 2047 encoded strings. Non-compatible characters are replaced with '_'.

This does not remove the ability to parse RFC 2047 encoded filenames.

Closes gh-36328

Signed-off-by: Tobias Fasching <tobias.fasching@outlook.com>
2026-03-18 12:09:36 +01:00
rstoyanchev 5785923c0e Lower log level of cache miss in HandlerMappingIntrospector
See gh-36309
2026-03-17 19:00:34 +00:00
rstoyanchev 66607cb145 Add PreFlightRequestFilter
Closes gh-36482
2026-03-17 18:54:29 +00:00
Brian Clozel 4637da1f36 Merge branch '7.0.x' 2026-03-17 18:12:40 +01:00
Brian Clozel a21706c58a Copy WS handshake headers to store in session
Prior to this commit, the `StandardWebSocketUpgradeStrategy` would get
the HTTP headers from the handshake request and store them in the
WebSocket session for the entire duration of the session.
As of gh-36334, Spring MVC manages HTTP directly with a native API
instead of copying them. This improves performance but also uncovered
this bug: we cannot keep a reference to HTTP headers once the HTTP
exchange is finished, because such resources can be recycled and reused.

This commit ensures that the handshake headers are copied into the
session info to keep them around for the entire duration of the session.
Without that, Tomcat will raise an `IllegalStateException` at runtime.

This was already done for WebFlux in SPR-17250, but the latest header
management changes in Framework uncovered this issue for the Standard
WebSocket container case.

Fixes gh-36486
2026-03-17 18:09:57 +01:00
Brian Clozel 22e4d84993 Add support for "application/jsonl" JSON lines
Prior to this commit, Spring web frameworks were using the
"application/x-ndjson" media type for streaming JSON payloads delimited
with newlines.

The "application/jsonl" media type seems to gain popularity in the
broader ecosystem and could supersede NDJSON in the future. This commit
adds support for JSON Lines as an alternative.

Closes gh-36485
2026-03-17 12:18:23 +01:00
Sébastien Deleuze e2b9b19970 Upgrade to Kotlin 2.3.20
Closes gh-36484
2026-03-17 11:59:45 +01:00
Brian Clozel 75f964657f Merge branch '7.0.x' 2026-03-17 09:20:16 +01:00
github-actions[bot] de913642fb Update Antora Spring UI to v0.4.26 2026-03-17 09:19:50 +01:00
Sam Brannen 23b73168a0 Merge branch '7.0.x' 2026-03-16 13:39:30 +01:00
jun c2c6130da5 Fix typo in StompSession Javadoc
Closes gh-36469

Signed-off-by: jun <ryuu.public@gmail.com>
2026-03-16 13:38:19 +01:00
Juergen Hoeller 391dd90e84 Support "classpath*:" prefix for resource bundle basename
Closes gh-36292
See gh-36415
2026-03-16 12:23:35 +01:00
Juergen Hoeller 1345760087 Support "classpath*:" prefix for ResourceLoader#getResource
Introduces a general-purpose consumeContent method on Resource and EncodedResource with special behavior for multi-content resources. Regular getInputStream/getReader calls will expose the merged content of all same-named resources in the classpath.

Closes gh-36415
2026-03-16 12:23:16 +01:00
Brian Clozel 51fccf226f Merge branch '7.0.x' 2026-03-16 11:16:48 +01:00
Brian Clozel df817364b2 Fix WebTestClient list assertions
Prior to this commit, the `WebTestClient` could only accept non-nullable
types in its `expectBodyList<T>` Kotlin extension function.
This commit relaxes this requirements to allow for more assertions.

Fixes gh-36476
2026-03-16 11:14:55 +01:00
Brian Clozel bc07a451dc Fix ParameterizedTypeReference nullness
This commit ensures that `ParameterizedTypeReference<T>` can accept
nullable types. This is especially useful for Kotlin extension functions
and assertion contracts.

Fixes gh-36477
2026-03-16 11:12:06 +01:00
Sam Brannen a14a20b61b Merge branch '7.0.x' 2026-03-15 17:06:18 +01:00
Sam Brannen 5eb0e99d58 Fix common typos and grammatical mistakes
Closes gh-36471
2026-03-15 17:05:29 +01:00
Sam Brannen 17699103dc Consistently use American English spelling
Since the Spring Framework uses American English spelling, this commit
updates Javadoc and the reference manual to ensure consistency in that
regard. However, there are two exceptions to this rule that arise due
to their use within a technical context.

- We use "cancelled/cancelling" instead of "canceled/canceling" in
  numerous places (including error messages).
- We use "implementor" instead of "implementer".

Closes gh-36470
2026-03-15 17:04:23 +01:00
Sam Brannen fadbd0fa31 Partially revert forward merge of "Branch for 7.0.x maintenance" 2026-03-15 14:45:09 +01:00
Sam Brannen 40ef084e7f Merge branch '7.0.x' 2026-03-15 14:40:47 +01:00
Sam Brannen 9b366b28b7 Remove obsolete, custom Eclipse configuration for spring-oxm
See gh-36195
2026-03-15 14:32:56 +01:00
Sam Brannen 0f990e44a8 Polish contribution
See gh-36195
2026-03-15 14:32:56 +01:00
Clayton Walker e102bc4933 Improve XJC configuration for spring-oxm in the Gradle build
Closes gh-36195

Signed-off-by: Clayton Walker <clayton.m.walker@gmail.com>
2026-03-15 14:32:44 +01:00
Sam Brannen a07033f3fb Resolve all default context configuration within test class hierarchies
Prior to this commit, if a superclass or enclosing test class (such as
one annotated with @⁠SpringBootTest or simply
@⁠ExtendWith(SpringExtension.class)) was not annotated with
@⁠ContextConfiguration (or @⁠Import with @⁠SpringBootTest), the
ApplicationContext loaded for a subclass or @⁠Nested test class would
not use any default context configuration for the superclass or
enclosing test class.

Effectively, a default XML configuration file or static nested
@⁠Configuration class for the superclass or enclosing test class was
not discovered by the AbstractTestContextBootstrapper when attempting
to build the MergedContextConfiguration (application context cache key).

To address that, this commit introduces a new
resolveDefaultContextConfigurationAttributes() method in
ContextLoaderUtils which is responsible for creating instances of
ContextConfigurationAttributes for all superclasses and enclosing
classes. This effectively enables AbstractTestContextBootstrapper to
delegate to the resolved SmartContextLoader to properly detect a
default XML configuration file or static nested @⁠Configuration class
even if such classes are not annotated with @⁠ContextConfiguration.

Closes gh-31456
2026-03-13 15:39:05 +01:00
Sam Brannen 293a9c0ee3 Allow local @⁠BootstrapWith annotation to override a meta-annotation
This commit revises the resolveExplicitTestContextBootstrapper()
algorithm in BootstrapUtils to allow a local @⁠BootstrapWith annotation
to override a meta-annotation within the same composed annotation.

Closes gh-35938
2026-03-13 15:24:38 +01:00
Sam Brannen 32d1b83f62 Override Servlet 6.1's doPatch() method in FrameworkServlet
See gh-12640
See gh-14975
See gh-36258
Closes gh-36247
2026-03-13 15:17:04 +01:00
Brian Clozel 227bc196b1 Consider 7.0.x branch for Antora UI upgrades 2026-03-13 15:02:25 +01:00
Brian Clozel 2fcef050e0 Build 7.1.0-SNAPSHOT 2026-03-13 14:50:12 +01:00
Brian Clozel be1bf91ce8 Branch for 7.0.x maintenance 2026-03-13 10:22:01 +01:00
Brian Clozel 877825b4ab Next development version (v7.0.7-SNAPSHOT) 2026-03-13 09:33:52 +01:00
Sébastien Deleuze 739d5ba77b Leverage ResourceHandlerUtils in ScriptTemplateView
This commit apply extra checks to ScriptTemplateView resource handling
with ResourceHandlerUtils, consistently with what is done with static
resource handling.

Closes gh-36458
2026-03-12 19:43:17 +01:00
Sébastien Deleuze 19ab92ef59 Restore ScriptTemplateViewTests
Restore both WebMVC and WebFlux variants that were deleted
by mistake in commit 4db2f8ea1b.

This commit also removes the empty resource loader path, as it is not
needed for the main WEB-INF/ use case that is typically configured
explicitly by the user, and not needed to pass the restored tests.

Closes gh-36456
2026-03-12 19:42:28 +01:00
Sam Brannen 04313f062e Improve documentation for FullyQualifiedConfigurationBeanNameGenerator
This commit documents FullyQualifiedConfigurationBeanNameGenerator in
related Javadoc and in the reference manual.

See gh-33448
Closes gh-36455
2026-03-12 17:03:45 +01:00
Sam Brannen e634ced56b Fix log message in ConfigurationClassBeanDefinitionReader
The log message now properly generates the fully-qualified method name
and includes the resolved bean name as well.

Closes gh-36453
2026-03-12 16:23:45 +01:00
Sam Brannen 1502c2296e Remove redundant method invocation 2026-03-12 16:17:23 +01:00
Brian Clozel cc5c7ba186 Fix enclosing class resolution with ClassFile API
Prior to this commit, the `ClassFile` based implementation of
`AnnotationMetadata` would rely on the `NestHost` class element to get
the enclosing class name for a nested class.
This approach works for bytecode emitted by Java11+, which aligns with
our Java17+ runtime policy. But there are cases where bytecode was not
emitted by a Java11+ compiler, such as Kotlin. In this case, the
`NestHost` class element is absent and we should instead use the
`InnerClasses` information to get it.

This commit makes use of `InnerClasses` to get the enclosing class name,
but still uses `NestHost` as a fallback for anonymous classes.

Fixes gh-36451
2026-03-12 10:47:39 +01:00
Sam Brannen 0269eb80da Fix typo and improve Javadoc for ConfigurationBeanNameGenerator 2026-03-11 17:18:11 +01:00
Sam Brannen 9cedcd65ef Polishing 2026-03-11 16:45:30 +01:00
Sam Brannen 4e8acb9ef2 Polish contribution
See gh-36448
2026-03-11 16:45:30 +01:00
gbouwen dbbbf37ac9 Update exception message in JacksonJsonMessageConverter
Closes gh-36448

Signed-off-by: gbouwen <57719521+gbouwen@users.noreply.github.com>
2026-03-11 16:41:19 +01:00
Juergen Hoeller d8216d719b Upgrade to SnakeYAML 2.6, Protobuf 4.34, H2 2.4.240 2026-03-11 15:53:42 +01:00
Juergen Hoeller 63ced3f3b4 Polishing 2026-03-11 13:52:34 +01:00
Juergen Hoeller 89391fd94c Consistently ignore non-loadable annotation types with ClassFile/ASM
Uses ClassFileAnnotationMetadata name for actual AnnotationMetadata.
Moves JSR-305 dependency to compile-only for all spring-core tests.

Closes gh-36432
2026-03-11 13:52:19 +01:00
rstoyanchev 5168e3a38b Polishing contribution
Closes gh-36400
2026-03-10 19:14:41 +00:00
husseinvr97 d4893fb32f Support defaultHtmlEscape in WebFlux
See gh-36400

Signed-off-by: husseinvr97 <husseinmustafabas05@gmail.com>
2026-03-10 19:14:41 +00:00
Juergen Hoeller 104a2033c5 Upgrade to Reactor 2025.0.4 and Micrometer 1.16.4
Includes Jetty 12.1.7, Hibernate ORM 7.2.6, EclipseLink 5.0.0-RC1, Selenium 4.41, Mockito 5.22, Checkstyle 13.3

Closes gh-36443
Closes gh-36444
2026-03-10 20:09:20 +01:00
Brian Clozel cc1514be85 Fix DefaultResponseErrorHandler method visibility
Prior to this commit, the `setMessageConverters` method would have
private visibility. But `initBodyConvertFunction`, which is `protected`,
relies on the message converters being set in the first place.
While this works with `RestTemplate` because this is done automatically,
the `RestClient` does offer a builder method to configure a
`ResponseErrorHandler` and this makes it impossible to configure
converters in this case.

This commit aligns the method visibility by making it protected.

Closes gh-36434
2026-03-10 18:08:09 +01:00
Brian Clozel 6e9758700a Guard against invalid id/event values in Server Sent Events
Prior to this commit, our implementation of Server Sent Events (SSE),
`SseEmitter` (MVC) and `ServerSentEvent` (WebFlux), would not guard
against invalid characters if the application mistakenly inserts such
characters in the `id` or `event` types.
Both implementations would also behave differently when it comes
to escaping comment multi-line events.

This commit ensures that both implementations handle multi-line comment
events and reject invalid characters in id/event types.
This commit also optimizes `String` concatenation and memory usage
when writing data.

Fixes gh-36440
2026-03-10 17:56:58 +01:00
Sam Brannen 37e8aa76e9 Use link for first reference to @⁠Fallback in @⁠Bean Javadoc
See gh-36439
2026-03-10 17:53:33 +01:00
Sam Brannen 27686dc2e2 Document @Fallback alongside Primary in the reference docs and @Bean Javadoc
Closes gh-36439
2026-03-10 17:13:23 +01:00
Sam Brannen 3b8efbe5a6 Document registration recommendations for BeanPostProcessor and BeanFactoryPostProcessor
Closes gh-34964
2026-03-10 13:07:13 +01:00
Sam Brannen 6f2e59a995 Polishing 2026-03-10 13:07:12 +01:00
Sam Brannen 644a20ae2a Polish @⁠Bean Javadoc and reference docs 2026-03-10 12:24:53 +01:00
rstoyanchev 77bc13dc8c Polishing contribution
See gh-36325
2026-03-09 17:52:12 +00:00
rstoyanchev ab9895b5a9 Polishing contribution
Closes gh-36325
2026-03-09 17:49:25 +00:00
Agil ce5c4f3b4b Refactor calculateHashCode method for clarity
This will:
1. Mathematical Distribution (Collision Reduction)
2. Pipelining and CPU Caching
3. Avoiding "Method Heavy" Expressions

See gh-36325

Signed-off-by: Agil <41694337+AgilAghamirzayev@users.noreply.github.com>
2026-03-09 17:38:15 +00:00
rstoyanchev cd0c26b6db Update Javadoc on binding flag in ModelAttribute
Add clarification and mention primary use case.
2026-03-09 14:25:47 +00:00
조형준 1203ace285 Fix typo in HttpExchangeAdapterDecorator Javadoc
Closes gh-36433

Signed-off-by: jun <ryuu.public@gmail.com>
2026-03-09 14:46:20 +01:00
Sam Brannen 1219943e73 Polishing
See gh-36323
2026-03-09 11:15:19 +01:00
Sébastien Deleuze eeddf9a73a Fix transaction managemement snippet and documentation
Closes gh-36323
2026-03-09 10:29:45 +01:00
jisub-dev b2a4bc8900 Add programmatic configuration code snippet
- Extract code examples to separate Java, Kotlin, and XML files
- Add Kotlin configuration sample alongside Java
- Change "Java Config" terminology to "Programmatic Configuration"
- Use include-code directive for better maintainability

See gh-36323
Signed-off-by: jisub-dev <kimjiseob1209@gmail.com>
2026-03-09 10:12:20 +01:00
Sam Brannen 3a266e65d6 Revise nullability in AnnotationConfigContextLoaderUtils 2026-03-08 14:42:17 +01:00
Sam Brannen 463138acbc Resolve context initializers only once in AbstractTestContextBootstrapper
The internal buildMergedContextConfiguration() method in
AbstractTestContextBootstrapper originally resolved the
ApplicationContextInitializer set only once. However, the changes made
in commit 2244461778 introduced a regression resulting in the
initializers being resolved twice: once for validation and once for
actually building the merged context configuration. In addition, the
resolution for validation does not honor the inheritInitializers flag
in ContextConfigurationAttributes.

To address these issues, buildMergedContextConfiguration() once again
resolves the context initializers once via
ApplicationContextInitializerUtils.resolveInitializerClasses().

See gh-18528
Closes gh-36430
2026-03-08 14:32:06 +01:00
Tran Ngoc Nhan b8a4961b81 Remove unused imports in framework-docs examples
Closes gh-36429

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-03-07 15:11:05 +01:00
rstoyanchev 06d4a8fc4b Fix case sensitivity issue in ServletRequestHeadersAdapter
The RequestHeaderOverrideWrapper did not deduplicate in keySet()
across underlying headers and overrides.

A similar change in size() even if it was working correctly,
to align with keySet and make it more efficient.

Closes gh-36418
2026-03-06 16:51:27 +00:00
Sam Brannen 13b0643828 Invoke resolveContextLoader() only once in AbstractTestContextBootstrapper
See commit c2d0d292bd
See gh-35994
Closes gh-36425
2026-03-06 16:05:30 +01:00
Sam Brannen 548b2167b0 Simplify changes made in commit c2d0d292bd
See gh-36390
2026-03-06 13:13:18 +01:00
froggy0m0 de417beff7 Fix typo in ExceptionMapingComparator name
Closes gh-36422

Signed-off-by: 신성현 <froggy0m0a@gmail.com>
2026-03-06 11:57:14 +01:00
rstoyanchev ccc6789cb5 Update docs for path API version resolver
See gh-36398
2026-03-05 17:21:43 +00:00
rstoyanchev f73302a66e Polishing contribution
Closes gh-36398
2026-03-05 17:12:13 +00:00
Martin Mois 348482b5a0 Add usePathSegment with Predicate<RequestPath>
See gh-36398

Signed-off-by: Martin Mois <martin.mois@gmail.com>
2026-03-05 17:12:13 +00:00
rstoyanchev 25bb264bd9 Polishing in ReactorNettyWebSocketClient
Also, remove local variables that should have been removed when
the corresponding, deprecated setters were removed in
2ed281f6a8.

Closes gh-36370
2026-03-05 17:12:13 +00:00
Artem Voronin 9819e1cad5 Propagate max frame length to WebSocket session
This change ensures that maxFramePayloadLength from
WebsocketClientSpec is passed to ReactorNettyWebSocketSession.

Previously, the session used the default 64KB limit regardless
of client configuration, causing TooLongFrameException when
receiving larger frames from servers like Tomcat or Jetty.

See gh-36370

Signed-off-by: Artem Voronin <artem.voronin.dev@gmail.com>
2026-03-05 17:12:13 +00:00
rstoyanchev ce2402a581 Link to Tomcat issue in ServletResponseHeadersAdapter 2026-03-05 17:12:13 +00:00
Sam Brannen c2d0d292bd Re-resolve ContextLoader in logWarningForIgnoredDefaultConfig()
Ideally, we should be able to reuse the ContextLoader that was resolved
in buildDefaultMergedContextConfiguration(); however, since we have
been informed that some implementations of resolveContextLoader()
mutate the state of the supplied ContextConfigurationAttributes to
detect default configuration classes, we need to invoke
resolveContextLoader() on the completeDefaultConfigAttributesList as
well in order not to break custom TestContextBootstrappers that exhibit
such side effects.

Closes gh-36390
2026-03-05 15:28:54 +01:00
Sam Brannen bbe733def7 Address Checkstyle violation 2026-03-05 11:43:06 +01:00
Stéphane Nicoll 03391dfa94 Switch serializable flag to primitive boolean
This commit improves the change made to TypeHint to use a primitive
boolean for the serializable flag.

See gh-36379
2026-03-05 11:23:51 +01:00
Sam Brannen 50c29e64f8 Polish documentation for FrameworkServlet and HttpServletBean 2026-03-05 11:21:44 +01:00
Sam Brannen 22301fd069 Further align synthesized annotation toString() with modern JDKs
Closes gh-36417
2026-03-04 17:39:02 +01:00
Sam Brannen 11ab0b4351 Upgrade to Gradle 9.4
Closes gh-36416
2026-03-04 13:43:07 +01:00
Juergen Hoeller 4734c15d81 Polishing 2026-03-03 23:28:37 +01:00
Sam Brannen 02af3e7a17 Introduce setDefaultCharset() in AbstractResourceBasedMessageSource
Traditionally, AbstractResourceBasedMessageSource has only had a
setDefaultEncoding() method which accepts the name of the default
encoding character set. However, although we have recently made a
concerted effort within the framework to introduce support for
supplying a Charset instead of a character set's name, we had
overlooked this particular scenario.

In light of that, this commit introduces setDefaultCharset(Charset) and
getDefaultCharset() methods in AbstractResourceBasedMessageSource and
makes direct use of the available Charset in
ReloadableResourceBundleMessageSource and ResourceBundleMessageSource.

Furthermore, although technically a regression in behavior, invoking
setDefaultEncoding() on such MessageSource implementations with an
invalid character set name now results in an immediate
UnsupportedCharsetException at configuration time instead of a
NoSuchMessageException at runtime, which will help users to more easily
detect misconfiguration.

Closes gh-36413
2026-03-03 18:08:21 +01:00
cetf 3c6f1b35ba Fix format string argument count
Fixes: gh-36410
Signed-off-by: cetf <cetf9h@163.com>
2026-03-03 12:14:33 +01:00
Sam Brannen 7a420b28df Revise custom @⁠BootstrapWith use case in test
See https://github.com/spring-projects/spring-boot/issues/15077
See gh-35938
2026-03-02 17:07:30 +01:00
Sam Brannen 63723fadb6 Introduce tests for additional @⁠BootstrapWith use cases
See gh-35938
2026-03-02 16:34:39 +01:00
Sam Brannen ab7a2c4e70 Rename configuration.interfaces package to config.interfaces
This commit renames the
org.springframework.test.context.configuration.interfaces package to
org.springframework.test.context.config.interfaces in order to colocate
"config" related tests under the same package.
2026-03-02 16:07:43 +01:00
dependabot[bot] a87b2e0146 Upgrade fast-xml-parser to 5.3.8
Closes gh-36402

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 13:13:43 +01:00
Sam Brannen bd40f0e6bb Fix typo 2026-03-01 13:03:40 +01:00
Sam Brannen 04186fdf0e Consistently refer to URLs and URIs in documentation 2026-03-01 13:03:14 +01:00
Tran Ngoc Nhan b2b731b0ba Fix links to UriComponentsBuilder and polish examples
Closes gh-36403

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-03-01 12:51:43 +01:00
Juergen Hoeller a3b9098850 Remove prefixed FactoryBean name in ApplicationListenerDetector
Closes gh-36404
2026-03-01 12:08:19 +01:00
Juergen Hoeller 36815f4021 Add support for JPA 4.0 FlushModeType.EXPLICIT
Includes defensive nullable field access in EclipseLinkConnectionHandle.

Closes gh-36401
2026-02-28 19:37:27 +01:00
Sam Brannen 3b1b7ff594 Add Checkstyle suppression 2026-02-28 16:22:57 +01:00
Sam Brannen 95080cabfd Polishing 2026-02-28 16:01:01 +01:00
조형준 017892265e Fix typo in WebMvcConfigurationSupport Javadoc
Closes gh-#36399

Signed-off-by: jun <ryuu.public@gmail.com>
2026-02-28 14:16:14 +01:00
Juergen Hoeller d096a33f13 Add note on test difference against Jackson 3.1.0 2026-02-28 13:36:39 +01:00
Juergen Hoeller b6833ff31f Cancel late-executing tasks within revised closed handling
Closes gh-36362
2026-02-28 13:34:01 +01:00
Stéphane Nicoll 3bc55c77ec Add support for declaring reflection metadata for lambdas
Closes gh-36339
2026-02-27 14:42:46 +01:00
Sam Brannen 824aa137f8 Align implementation of injectDependencies() with injectDependenciesInAotMode() 2026-02-26 18:01:01 +01:00
Sam Brannen 0dc44f79d5 Avoid superfluous MergedContextConfiguration equals() check
See gh-36390
2026-02-26 12:56:38 +01:00
Sam Brannen f481f99516 Avoid unnecessary List and Stream creation
See gh-36390
2026-02-26 12:02:38 +01:00
Sam Brannen 72ed2eaa31 Fix lambda variable names
See gh-36390
2026-02-26 11:57:32 +01:00
Sam Brannen 0676c958f7 Log warning for ignored default context configuration in tests
In Spring Framework 7.1, the TestContext Framework will reliably detect
all default context configuration within the type hierarchy or
enclosing class hierarchy (for @⁠Nested test classes) above a given
test class; however, test suites may encounter failures once we make
that switch in behavior.

In order to help development teams prepare for the switch in 7.1, this
commit logs a warning similar to the following whenever default context
configuration is detected but currently ignored.

  WARN - For test class [org.example.MyTests$NestedTests], the
  following 'default' context configuration classes were detected but
  are currently ignored: org.example.MyTests$Config. In Spring
  Framework 7.1, these classes will no longer be ignored. Please update
  your test configuration accordingly. For details, see:
  https://docs.spring.io/spring-framework/reference/testing/testcontext-framework/ctx-management/default-config.html

See gh-31456
See gh-36392
Closes gh-36390
2026-02-26 11:24:02 +01:00
Sam Brannen 482519d03b Document how to avoid issues w/ ignored default context config in tests
See gh-31456
See gh-36390
Closes gh-36392
2026-02-25 17:36:14 +01:00
Sam Brannen d6b7cea327 Polishing 2026-02-25 17:34:14 +01:00
Sam Brannen 9eea227ab9 Further emphasize @⁠Configuration classes over XML and Groovy in testing chapter
See gh-36393
2026-02-25 15:44:00 +01:00
Sam Brannen 706c98228d Emphasize @⁠Configuration classes over XML and Groovy in testing chapter
Closes gh-36393
2026-02-25 15:26:32 +01:00
rstoyanchev b83cb4a947 Make newRequest methods public
The methods to build a request in RestClientAdapter and WebClientAdapter
are now public to make it easier to create a custom adapter that wraps
the built-in ones and delegates for methods that can be the same.

Closes gh-36374
2026-02-25 12:43:19 +00:00
rstoyanchev 7e79d0e206 Polishing in DefaultRestClientTests 2026-02-25 12:43:19 +00:00
rstoyanchev e58ba2c665 Simplify use of InputStream with RestClient
Closes gh-36380
2026-02-25 12:43:19 +00:00
Sam Brannen 0c9127d111 Use consistent indentation in Gradle build scripts 2026-02-25 11:15:16 +01:00
Sam Brannen c2088517b9 Upgrade to JUnit 6.0.3
Closes gh-36389
2026-02-25 11:05:05 +01:00
Sam Brannen 59b9057e59 Polishing 2026-02-25 10:52:28 +01:00
Sam Brannen 2ec630ef45 Remove obsolete EMPTY_GROUPS constant in InvocableHandlerMethod
See gh-36274
2026-02-25 10:50:45 +01:00
Sam Brannen cf2b59b68b Delete obsolete addCharsetParameter() method
See gh-36318
2026-02-25 10:50:45 +01:00
Sam Brannen f1ca29b05d Move NOTE in "Programmatic Retry Support" to correct location 2026-02-25 10:28:23 +01:00
dependabot[bot] ee6a115a18 Upgrade fast-xml-parser to 5.3.6
Closes gh-36348

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-25 10:08:56 +01:00
Juergen Hoeller 95a31c4e8c Align constant name in ServletServerHttpResponse
See gh-36385
2026-02-25 09:29:22 +01:00
Brian Clozel e0b54e244e Ignore flushes on ServletServerHttpResponse output stream
Prior to this commit, flush calls on the output stream returned by
`ServletServerHttpResponse#getBody` would be delegated to the Servlet
response output stream.
This can cause performance issues when `HttpMessageConverter` and other
web components write and flush multiple times to the response body.
Here, the Servlet container is in a better position to flush to the
network at the optimal time and buffer the response body until then.

This is particularly true for `HttpMessageConverters` when they flush
many times the output stream, sometimes due to the underlying codec
library. Instead of revisiting the entire message converter contract, we
are here ignoring flush calls to that output stream.

This change does not affect the client side, nor the
`ServletServerHttpResponse#flush` calls.

This commit also introduces a new Spring property
`"spring.http.response.flush.enabled"` that reverts this behavior change
if necessary.

Closes gh-36385
2026-02-24 21:44:48 +01:00
Juergen Hoeller f2b64ad09c Polishing 2026-02-24 17:17:31 +01:00
Juergen Hoeller cff48fff2d Reject late-executing tasks after termination waiting
Closes gh-36362
2026-02-24 17:17:21 +01:00
Juergen Hoeller ab8cb8de6e Add support for non-flushing OutputStream
Avoids decoration for streams that are non-closing/flushing already.

Closes gh-36382
2026-02-24 17:17:04 +01:00
Stéphane Nicoll 434da06d1f Migrate to GraalVM metadata format 1.2.0
This commit adapts RuntimeHints to be compatible with v1.2.0 of the
GraalVM metadata format. The changes are as follows:

* Resources and resource bundles are now defined at the same level. This
is transparent to users.
* Serialization is no longer a top-level concept, but rather an
attribute of a type or proxy. The top-level concept has been deprecated
and the relevant methods have been added.

Closes gh-36379
2026-02-24 17:05:50 +01:00
Brian Clozel a37447e07f Remove duplicate flushes in HttpMessageConverter implementations
Prior to this commit, a few implementations of the `HttpMessageConverter`
contract were inheriting from abstract classes. Those classes were
performing extra `OutputStream#flush` on the response body even though
this is the responsibility of the super class. Such abstract classes
do flush already, after delegating to the `writeInternal` method.

This commit ensures that we remove such extra calls as they tend to
waste resources for no added benefit.

Closes gh-36383
2026-02-24 16:49:37 +01:00
Sam Brannen b1cb9c5052 Polish contribution
See gh-36367
2026-02-23 17:24:13 +01:00
Tran Ngoc Nhan 057633edb5 Polish SpEL operator examples in reference docs
Closes gh-36367

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-02-23 17:08:22 +01:00
Brian Clozel 7299ff9326 Improve ResourceHttpMessageConverter target type support
This commit updates the target type detection in
`ResourceHttpMessageConverter` to only support target types that are
relevant: `InputStreamResource` for streaming, and types assignable from
`ByteArrayResource` for non-streaming cases.

Closes gh-36368
2026-02-23 11:02:22 +01:00
조형준 53f1656f56 Fix typo in CorsConfiguration Javadoc
Closes gh-36366

Signed-off-by: jun <ryuu.public@gmail.com>
2026-02-22 16:14:45 +01:00
Brian Clozel 2691489381 Fix InvalidMimeTypeException for compatible media types
The `AbstractMessageConverterMethodProcessor` is in charge of handling
controller method return values and to write those as HTTP response
messages. The content negotiation process is an important part.

The `MimeTypeUtils#sortBySpecificity` is in charge of sorting inbound
"Accept" media types by their specificity and reject them if the list
is too large, in order to protect the application from ddos attacks.

Prior to this commit, the content negotiation process would first get
the sorted "Accept" media types, the producible media types as
advertized by message converters - and collect the intersection of both
in a new list (also sorted by specificity). If the "Accept" list is
large enough (but under the limit), the list of compatible media types
could exceed that limit because duplicates could be introduced in that
list: several converters can produce the same content type.

This commit ensures that compatible media types are collected in a set
to avoid duplicates. Without that, exceeding the limit at this point
will throw an `InvalidMimeTypeException` that's not handled by the
processor and result in a server error.

Fixes gh-36300
2026-02-20 18:21:45 +01:00
Tran Ngoc Nhan f103af4982 Remove obsolete space in HandlerMethod.html#assertTargetBean javadoc
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-02-20 13:43:11 +00:00
rstoyanchev b9a59853fa Use case-insensitive comparator in HttpHeadersAssert
Closes gh-36349
2026-02-20 13:38:51 +00:00
rstoyanchev d4b2a493f9 Fix duplicate header writing in ResponseBodyEmitterReturnValueHandler
Closes gh-36357
2026-02-20 10:45:22 +00:00
rstoyanchev 188cb9b24d Update Javadoc of RestClient.Builder defaultStatusHandler
See gh-36248
2026-02-19 11:42:59 +00:00
rstoyanchev e3568a3f0a Fix generic return type support in HttpServiceMethod
Closes gh-36326
2026-02-18 17:27:02 +00:00
rstoyanchev e106fc0434 Polishing in RestClientAdapterTests and WebClientAdapterTests 2026-02-18 17:27:02 +00:00
Stéphane Nicoll ca3adf43eb Next development version (v7.0.6-SNAPSHOT) 2026-02-18 14:07:54 +01:00
rstoyanchev 85c18caf25 Update docs on supported versions with baseline notation
Closes gh-36316
2026-02-18 11:33:08 +00:00
Juergen Hoeller 22bd8bd704 Skip serialization of potentially non-serializable cached state
Closes gh-36346
2026-02-17 22:13:57 +01:00
Juergen Hoeller 9b10bb5e08 Polishing 2026-02-17 18:57:09 +01:00
Juergen Hoeller 727ccd04ef Avoid setCharacterEncoding(Charset) call with null value
Includes consistent content length check for functional response.

See gh-36343
2026-02-17 18:56:59 +01:00
Juergen Hoeller a9f447e8d7 Consistent adaptation of HTTP headers on Servlet responses
Includes use of Servlet 6.1 setCharacterEncoding(Charset)

Closes gh-36343
2026-02-17 17:38:50 +01:00
海子 Yang 0841e79e32 Copy methodAnnotations in MethodParameter copy constructor
Signed-off-by: 海子 Yang <i.take.today@gmail.com>
2026-02-17 17:17:22 +01:00
Niravil a1868d3e9e fix TransactionAspectSupport#currentTransactionStatus javadoc
Signed-off-by: Niravil <messerignacius@gmail.com>
2026-02-17 16:26:02 +01:00
rstoyanchev e5aac66157 ServletResponseHeadersAdapter checks contentType property
Issue gh-36334
2026-02-17 11:55:34 +00:00
Juergen Hoeller 8bf85d2596 Polishing 2026-02-17 12:27:00 +01:00
Juergen Hoeller 508b31da4f Optimize Entry hashCode in HttpHeaders (plus related polishing) 2026-02-17 11:55:10 +01:00
Juergen Hoeller d291272736 Use HandlerMethod-determined validation groups
Closes gh-36336
2026-02-17 11:50:07 +01:00
海子 Yang db01f07037 Remove unused EMPTY_GROUPS in InvocableHandlerMethod
Signed-off-by: 海子 Yang <i.take.today@gmail.com>
2026-02-17 11:30:54 +01:00
Brian Clozel b9e190e313 Fix HttpMessageConverters configurers support
This commit fixes the `configureMessageConverters` and
`configureMessageConvertersList` behavior.

`configureMessageConverters` was not executing consumers in their order
of registration (but in the reverse order).
`configureMessageConvertersList` was not executing multiple consumers
and was instead executing the first consumer multiple times.

This commit fixes both issues.

Fixes gh-36332
2026-02-16 18:48:26 +01:00
rstoyanchev d712ec3d49 Minor optimization in Tomcat header adapters
get method skips containsKey and instead checks if the enumeration
has elements, which should give the same behavior other than for
headers without values.

See gh-36334
2026-02-16 17:38:01 +00:00
rstoyanchev 5baa4fdd69 Further optimize Servlet header adapters
- Optimize get method for request headers
- Update keySet methods to use custom extension of AbstractSet
- Drop use of native Tomcat headers, which could be an issue for
request and response wrappers that override header methods.
The performance of Servlet adapters should be similar for the
commonly used methods, and it should be possible to optimize
further for the future in HttpHeaders (e.g. by adding a
set alternative to put), and requesting Servlet API refinements.

Closes gh-36334
2026-02-16 17:37:51 +00:00
rstoyanchev 9273a11a2c Stub Servlet headers adapter methods not needed in HttpHeaders
See gh-36334
2026-02-16 17:37:27 +00:00
rstoyanchev 7ea11baff9 Pass-through handling of Servlet headers
See gh-36334
2026-02-16 17:37:09 +00:00
Sam Brannen 655fd2e2bf Document that SpEL expressions using Optional w/ null-safe & Elvis operators are not compilable
Closes gh-36331
2026-02-15 12:26:54 +01:00
Brian Clozel a31574a0a2 Fix MultipartParser & PartGenerator memory leak
Prior to this commit, the reactive `MultipartParser` and `PartGenerator`
types were leaking memory at runtime in specific cases:

* many HTTP clients must send multipart requests to be parsed and close
  the connection while uploading
* the `PartGenerator` must be configured to write file parts to
  temporary files on disk
* concurrency, upload speed must be important to trigger cases where the
  file system is not fast enough to consume incoming buffers

The `MultipartParser` parses and emits `BodyToken` to its sink
(here, the `PartGenerator`). By definition, Reactor's `FluxSink` when
created with `Flux.create(FluxSink)` will use a "buffer" strategy and
will queue emitted elements if they cannot be consumed.

Here, the cancellation signal does dispose internal states in the
`MultiPartParser` and `PartGenerator` but does not clear the internal
queue in `FluxSink`.

This commit ensures that an operation is registered to release buffers
on the discard event.

Fixes gh-36262
2026-02-13 18:33:47 +01:00
Juergen Hoeller 44f3e7b427 Fix Checkstyle violation
See gh-36317
2026-02-13 16:34:58 +01:00
Juergen Hoeller e8e24e65d2 Detect all common size exceptions from Tomcat and Commons FileUpload 2.x
Closes gh-36317
2026-02-13 16:19:46 +01:00
Sam Brannen 9a002a77b2 Stop referring to "Java-8" features in documentation
See gh-36310
2026-02-13 15:21:31 +01:00
Brian Clozel 97e96895db Optimize MediaType(MediaType, Charset) constructor
Prior to this commit, the `MediaType` and `MimeType` "copy" constructors
would not leverage the fact that the existing instance has been
validated already (types, subtype and parameters have been checked
already for errors) and the entire validation would be performed again.
This would also allocate map instances in the process.

This commit ensures that the already validated information is reused
directly and that we avoid unnessecary operations and allocations for
such constructors.

Closes gh-36318
2026-02-13 14:49:34 +01:00
Juergen Hoeller e98c2fe488 Reuse AnnotatedMethod annotation cache in derived instances
Closes gh-36322
2026-02-13 13:55:24 +01:00
Juergen Hoeller 75705bcbb1 Restore early MessageConsumer creation for temporary queue
Closes gh-36321
2026-02-13 13:55:08 +01:00
rstoyanchev 47a2e7059e Optimal charset handling in AbstractHttpMessageConverter
Closes gh-36320
2026-02-13 12:39:03 +00:00
Sam Brannen 14b6339351 Consistently support @⁠Autowired as a meta-annotation
Prior to this commit, the findAutowiredAnnotation() method in
AutowiredAnnotationBeanPostProcessor fully supported finding
@⁠Autowired as a meta-annotation; however, the isRequired() method in
QualifierAnnotationAutowireCandidateResolver only found @⁠Autowired as
a "directly present" annotation without any support for
meta-annotations.

For consistency and to avoid bugs, this commit revises
QualifierAnnotationAutowireCandidateResolver so that we always support
@⁠Autowired as a meta-annotation.

Closes gh-36315
2026-02-12 16:38:24 +01:00
Juergen Hoeller bc2e89a786 Cache ResponseBody annotation presence per controller class
See gh-36311
2026-02-12 13:44:54 +01:00
Sam Brannen 4abbddf601 Avoid duplicate required attribute lookup for @⁠Autowired annotations
This commit revises AutowiredAnnotationBeanPostProcessor so that
determineRequiredStatus(MergedAnnotation<?>) only looks up the required
attribute once.

Closes gh-36314
2026-02-12 13:19:06 +01:00
Sam Brannen 926bcbd9a6 Stop referring to obsolete ListenableFuture in documentation
ListenableFuture as deprecated for removal in 6.0 and removed in 7.0.

See gh-33808
See gh-33809
See commit cb8ed43be1
Closes gh-36313
2026-02-12 13:19:06 +01:00
Sam Brannen cb8ed43be1 Stop referring to "JDK 8" features in documentation
See gh-36310
2026-02-12 12:27:51 +01:00
Juergen Hoeller 1703388074 Cache ResponseBody annotation presence per controller class
Closes gh-36311
2026-02-12 12:20:14 +01:00
Sam Brannen d84c4a39e2 Stop referring to "Java 8" features in documentation
Closes gh-36310
2026-02-12 12:11:02 +01:00
Sam Brannen 6f03c186b9 Polishing 2026-02-12 11:51:39 +01:00
Brian Clozel e10d37ad54 Next development version (v7.0.5-SNAPSHOT) 2026-02-12 10:39:15 +01:00
Juergen Hoeller 4734837fe4 Upgrade to Netty 4.2.10, Hibernate ORM 7.2.4, Checkstyle 13.2 2026-02-11 22:41:52 +01:00
Juergen Hoeller 4a13655aa5 Polishing 2026-02-11 19:22:27 +01:00
Brian Clozel 5ef9972528 Allow to disable defaults in HttpMessageConverters
The builder for `HttpMessageConverters` allows for auto-detection of
message converters on the classpath and their default registration when
`registerDefaults()` is called. Once called, there is no way to undo
this.

This commit adds a new `disableDefaults()` method to disable the default
registration and take full control over the list of message converters.

Closes gh-36303
2026-02-11 18:37:12 +01:00
Christian Schuster a9b1d6335e avoid unnecessary locking in ConcurrentReferenceHashMap's implementation of computeIfAbsent and computeIfPresent
Signed-off-by: Christian Schuster <christian@dnup.de>
2026-02-11 17:53:26 +01:00
Sam Brannen 98d4046e4b Document that @⁠Validated & @⁠Lazy may be used as meta-annotations
See gh-36305
See gh-36306
2026-02-11 17:37:06 +01:00
Sam Brannen 282fee5c95 Consistently find @⁠Lazy as a meta-annotation at arbitrary depths
Prior to this commit, AnnotationConfigUtils looked up @⁠Lazy as a
meta-annotation at arbitrary depths (e.g., when used as a
meta-meta-annotation); however,
ContextAnnotationAutowireCandidateResolver only found @Lazy as a
"directly present" meta-annotation.

For consistency, this commit revises
ContextAnnotationAutowireCandidateResolver so that it also finds @⁠Lazy
as a meta-annotation at arbitrary depths.

Closes gh-36306
2026-02-11 17:33:15 +01:00
Sam Brannen 0d4737aeec Polishing 2026-02-11 17:26:15 +01:00
Juergen Hoeller 1ef8734881 Cache method annotations in AnnotatedMethod as well
See gh-36307
2026-02-11 17:23:05 +01:00
Juergen Hoeller 6dfa54b8ea Cache method annotations in MethodParameter
Closes gh-36307
2026-02-11 16:41:55 +01:00
Sam Brannen 2d3a2c5cbd Consistently find @⁠Validated as a meta-annotation at arbitrary depths
Prior to this commit, ValidationAnnotationUtils looked up @⁠Validated
as a meta-annotation at arbitrary depths (e.g., when used as a
meta-meta-annotation) in determineValidationGroups() but only as a
"directly present" meta-annotation in determineValidationHints().

For consistency, this commit revises determineValidationHints() so that
it finds @⁠Validated as a meta-annotation at arbitrary depths as well.

Closes gh-36274
2026-02-11 16:02:13 +01:00
Brian Clozel 62e590a437 Use updated message in HttpEntityMethodProcessor
Prior to this commit, the `HttpEntityMethodProcessor` would create a new
`ServletServerHttpRequest` input message to parse the native Servlet
request, but would not reuse it for reading the request body using the
message converters.

In gh-32471, we applied a change that updates HTTP headers accordingly
when request parameters are read. But not reusing the input message
means that we are losing this update when instantiating the resulting
`HttpEntity`.

This commit ensures that `HttpEntityMethodProcessor` uses the input
message it just created when decoding the request body.

Fixes gh-36298
2026-02-11 12:32:15 +01:00
Sam Brannen 7f29df4d79 Make StompBrokerRelayMessageHandler's isPauseable() logic dynamic
Prior to this commit, an attempt to restart the
StompBrokerRelayMessageHandler (SBRMH) resulted in an
IllegalStateException stating that the ReactorNettyTcpClient was still
in the process of "Shutting down." The reason is that a
ReactorNettyTcpClient cannot be restarted after it has been closed, and
that is by design.

To address that issue, this commit introduces an
`internallyManagedTcpClient` flag in SBRMH that is used to track
whether SBRMH is in charge of managing the TcpClient internally or if
the TcpClient was supplied by the user and is therefore managed
externally.

If SBRMH manages the TcpClient internally, isPauseable() returns
`true`, and the `tcpClient` field is set to null (in stopInternal())
when the handler is stopped. Consequently, a new internally managed
TcpClient will be created when the handler is restarted.

If the TcpClient is managed externally, the handler is not considered
to be "pauseable", and a reference to the externally managed TcpClient
is retained after the handler has been stopped. If the
ApplicationContext is subsequently restarted, the externally managed
TcpClient will be reused -- which may or may not work, depending on the
implementation of the TcpClient. Note, however, that this has always
been the behavior of SBRMH with regard to stop/start scenarios for
externally managed TcpClients.

Closes gh-36266
2026-02-11 11:19:36 +01:00
rstoyanchev 8fb119df1e Determine validation groups in HandlerMethod
Closes gh-36274
2026-02-11 09:00:52 +00:00
rstoyanchev 1bb0fdda6b Move validation group determination to ValidationAnnotationUtils
See gh-36274
2026-02-10 16:56:33 +00:00
rstoyanchev 6507367d10 Polishing contribution
Closes gh-36179
2026-02-10 15:28:54 +00:00
Junhwan Kim fee7e6b7e2 Refine SendTo/Subscription header propagation
See gh-36179

Signed-off-by: Junhwan Kim <musoyou1085@gmail.com>
2026-02-10 15:28:54 +00:00
Brian Clozel 35c4973504 Upgrade to Reactor 2025.0.3
Closes gh-36288
2026-02-10 14:06:02 +01:00
Sam Brannen 77b54c7409 Stop setting the relayPort, since we explicitly set the TCP client 2026-02-10 13:21:33 +01:00
Sam Brannen ff9ba15762 Extract test logging into extension 2026-02-10 13:20:43 +01:00
Łukasz Jernaś c33b82f2a1 Log which HandlerInterceptor threw the exception
Closes gh-36281

Signed-off-by: Łukasz Jernaś <lukasz.jernas@allegro.com>
2026-02-10 11:44:26 +01:00
Brian Clozel ec459aefbf Upgrade to Micrometer 1.6.3
Closes gh-36287
2026-02-10 11:42:30 +01:00
rstoyanchev b227701473 Optimize RequestMappingInfo hashcode calculation
Precalculated hashcode makes sense for infos in the registry, but
matched infos created on the fly don't need it.

Closes gh-36279
2026-02-10 10:14:54 +00:00
Tran Ngoc Nhan 7a85ce959b Remove obsolete code in Redirecting to a resource section
See gh-34103
Closes gh-36384

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-02-10 11:13:39 +01:00
Brian Clozel e93e55b456 Fix wildcard MIME type support in messaging converters
Prior to this commit, the "application/*+json" wildcard MIME type was
added to the list of supported MIME types in the JSON messaging
converter. This change wasn't fully reflected in the
`AbstractMessageConverter`, because only strict matching of type and
subtybe were considered.

This commit updates the `AbstractMessageConverter` to not only check the
type and subtype, but also check whether the supported MIME type
includes the one given as a parameter.

Fixes gh-36285
2026-02-10 10:41:17 +01:00
rstoyanchev e22b1648bf Cache HandlerMethod with resolved bean if singleton
See gh-36278
2026-02-09 17:16:05 +00:00
rstoyanchev 78967d4bd6 Optimize version match
Closes gh-36276
2026-02-09 16:36:26 +00:00
rstoyanchev 1d2351c87b Optimize single PathPattern match
Closes gh-36275
2026-02-09 16:33:22 +00:00
rstoyanchev 02dc4b6342 Avoid determineValidationGroups not necessary
There is no need to call determineValidationGroups if the method
itself doesn't require method validation.

See gh-36274
2026-02-09 15:52:58 +00:00
Sam Brannen 143828e27c Introduce "Attention Required" section in changelog
Closes gh-36277
2026-02-09 12:39:39 +01:00
Sam Brannen 7998bc9de2 Fix grammar in Javadoc 2026-02-09 12:06:06 +01:00
Manu Sridharan 8a1a9d2ab2 Fix nullability annotation in JdbcTemplate
Signed-off-by: Manu Sridharan <msridhar@gmail.com>
2026-02-08 18:13:57 +01:00
Juergen Hoeller 394a97d7e0 Add setPackagesToScan to LocalEntityManagerFactoryBean (and make setDataSource work)
Includes fix for consistent PersistenceException in case of no unit found for name.
Includes proper tests for Local(Container)EntityManagerFactoryBean with scan setup.

Closes gh-36270
Closes gh-36271
2026-02-08 17:54:02 +01:00
Juergen Hoeller 05ffe8249f Adapt to getAllClassNames SPI (post JPA 4.0 M1)
See gh-35705
2026-02-07 21:01:25 +01:00
Juergen Hoeller 20970a4a37 Repeatedly check status while trying to lock for shutdown
Closes gh-36260
2026-02-06 19:03:54 +01:00
rstoyanchev cb4b87cce2 Use headerFilter on SimpAnnotationMethodMessageHandler
See gh-36179
2026-02-06 17:13:11 +00:00
rstoyanchev 1d470fc375 Exposes headerFilter on SimpAnnotationMethodMessageHandler
Closes gh-36179
2026-02-06 17:08:50 +00:00
rstoyanchev 7fc619acdc Polishing contribution
See gh-36179
2026-02-06 17:08:50 +00:00
김준환 e5f8c5b7ae Add header propagation predicate support to message return value handlers
See gh-36179

Signed-off-by: Junhwan Kim <musoyou1085@gmail.com>
2026-02-06 17:08:50 +00:00
Juergen Hoeller 3666ad9d7f Derive StatelessSession from primary Session in HibernateJpaDialect
This is analogous to LocalSessionFactoryBean's SpringSessionContext.

See gh-36025
2026-02-06 00:18:00 +01:00
Juergen Hoeller 652d509cfc Avoid direct javadoc reference to JPA 4.0 EntityAgent class
See gh-36025
2026-02-05 20:13:20 +01:00
Juergen Hoeller 153c378bb2 Polishing 2026-02-05 20:01:47 +01:00
Juergen Hoeller cdbaa7f3a7 Early support for JPA 4.0 EntityAgent (autowiring a shared proxy)
Includes skipping of isOpen check on close where easily possible.

Closes gh-36025
2026-02-05 20:01:26 +01:00
Brian Clozel d1b0bdb3d5 Revert Servlet TRACE error dispatch workaround
Closes gh-36258
2026-02-04 14:53:07 +01:00
Brian Clozel 59a9d0fcb9 Remove outdated GraalVM substitutions
Closes gh-36257
2026-02-04 14:52:40 +01:00
rstoyanchev db9045ae28 Polishing in CharBufferDecoder 2026-02-04 11:37:52 +00:00
rstoyanchev 7c2159fbe9 Polishing contribution
Closes gh-36225
2026-02-04 11:36:45 +00:00
Đặng Minh Dũng f2d3da3f32 Add ProxyFactoryCustomizer
Allows manipulating the `ProxyFactory` before the proxy is created

See gh-36225

Signed-off-by: Đặng Minh Dũng <dungdm93@live.com>
2026-02-04 11:35:48 +00:00
Yurii Platunov f1c86b1bbc Fix formatting in Web MVC HTTP Message Conversion documentation
Closes gh-36250

Signed-off-by: Yurii Platunov <furachannel16@gmail.com>
2026-02-04 11:30:32 +01:00
Johnny Lim 7fde8a6fa3 Remove obsolete doc for spring.context.annotated-bean-reader.create
See gh-35570
Closes gh-36241

Signed-off-by: Johnny Lim <izeye@naver.com>
2026-02-04 11:06:16 +01:00
Ivars Silamiķelis 033c309d39 Fix JSON syntax in STOMP overview documentation
Closes gh-36229

Signed-off-by: Ivars Silamiķelis <ivars.silamikelis@gmail.com>
2026-02-04 11:04:13 +01:00
Juergen Hoeller ac243fae65 Runtime compatibility with JPA 4.0.0-M1 and Hibernate ORM 8.0.0.Alpha1
Closes gh-35705
2026-02-03 19:13:48 +01:00
Juergen Hoeller ad19c1ac82 Introduce beforeRetry callback with RetryState argument
Closes gh-36245
2026-02-02 18:34:00 +01:00
Sébastien Deleuze 29d125e659 Add resource hint for BeanRegistrar implementing ImportAware
Closes gh-36242
2026-02-02 15:44:22 +01:00
Juergen Hoeller d31bd8139d Remove duplicated Jakarta Validation API declaration 2026-02-02 14:45:22 +01:00
Juergen Hoeller fb10455d3c Upgrade to Groovy 5.0.4, Tomcat 11.0.18, Jetty 12.1.6, Jackson 3.0.4/2.20.2, Hibernate ORM 7.2.3, Checkstyle 13.1 2026-02-02 12:14:40 +01:00
Juergen Hoeller 40350653e1 Upgrade to ASM 9.9.1 and Objenesis 3.5
Includes JavaPoet 0.10.0

Closes gh-36243
2026-02-02 12:13:41 +01:00
Sam Brannen a08a4d6068 Document @⁠SpringExtensionConfig in the reference manual
This commit also updates the Javadoc for the SpringExtension and
@⁠SpringExtensionConfig to point out that the SpringExtension always
uses a test-class scoped ExtensionContext if
@⁠TestInstance(Lifecycle.PER_CLASS) semantics are in effect.

Closes gh-36240
2026-01-31 16:24:38 +01:00
dependabot[bot] 6fd84e4c2f Upgrade fast-xml-parser from 4.5.2 to 5.3.4 in /framework-docs
Closes gh-36234
2026-01-31 15:31:24 +01:00
Juergen Hoeller 516bf1c606 Consistently detect resilience annotations on interfaces
Closes gh-36233
2026-01-30 17:12:22 +01:00
Sam Brannen 32b55e68fc Upgrade to Gradle 9.3.1 2026-01-30 15:48:15 +01:00
Sam Brannen b1f427f137 Fix typo 2026-01-30 13:41:20 +01:00
Sébastien Deleuze f52481493c Use @Nullable Void in TaskCallback#from
See gh-36208
2026-01-30 13:36:29 +01:00
qwding 149397ed10 Optimize NamedParameterUtils#buildValueArray by lazily fetching SqlParameter
This PR optimizes the performance of NamedParameterUtils#buildValueArray by deferring the call to findParameter(declaredParams, paramName, i).

Changes: In the original implementation, findParameter was called for every parameter in the loop, regardless of whether the paramValue retrieved from paramSource was already an instance of SqlParameterValue.

Since findParameter involves iterating through the declaredParams list (or performing lookups), skipping this call when paramValue instanceof SqlParameterValue is true reduces unnecessary CPU cycles and memory access, especially for queries with a large number of parameters or long declaredParams lists.

Signed-off-by: qwding <761945125@qq.com>
2026-01-30 11:59:43 +01:00
Brian Clozel e1d3076570 Fix "remove" implementation in netty headers adapter
Prior to this commit, the `Netty4HeadersAdapter` `MultiValueMapi#remove`
implementation would return an empty list if no value was present. This
is not consistent with other implementations.

This change ensures that `null` is returned for those cases.

Fixes gh-36226
2026-01-29 11:06:46 +01:00
Juergen Hoeller 16f4b23c32 Consistently close streams through try-with-resources
Closes gh-36223
2026-01-28 18:08:06 +01:00
Sam Brannen 54c3d01270 Revise documentation on JSR-330 support in the reference manual
Closes gh-36222
2026-01-28 18:06:39 +01:00
Sam Brannen 799a520c35 Consistently refer to "an SQL" statement, type, etc.
Aside from the three classes I modified, we already do this
consistently across the code base and in the reference manual.
2026-01-28 18:02:34 +01:00
Patrick Strawderman bf5386712c Use Java Files utilities in FileCopyUtils
Use helpers from java.nio.file.Files for some methods in FileCopyUtils.

Additionally, add unit tests for the various file-related methods.

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2026-01-28 17:46:09 +01:00
Juergen Hoeller 5d33de943b Polishing 2026-01-28 17:09:02 +01:00
Juergen Hoeller 7da65fe4fc Support -1 for undetermined length in SqlBinaryValue/SqlCharacterValue
Closes gh-36219
2026-01-28 17:08:40 +01:00
Sam Brannen 0d612b3b1d Make TaskCallback a @⁠FunctionalInterface 2026-01-28 14:54:52 +01:00
Sam Brannen 4dacc64a30 Fix formatting and spelling 2026-01-28 14:27:27 +01:00
Sam Brannen ba47dd0714 Fix links to JUnit User Guide
Closes gh-36217
2026-01-28 14:16:32 +01:00
rstoyanchev 79386b0e83 Fix unfinished edit from previous commit
See gh-36198
2026-01-28 12:27:09 +00:00
rstoyanchev d1bfe03358 Update docs on trailing slash handling
Closes gh-36198
2026-01-28 12:21:33 +00:00
rstoyanchev 4bc9f68451 Update docs content types for ProblemDetail
Closes gh-36192
2026-01-28 12:21:33 +00:00
Sam Brannen ce0e37536b Fix Javadoc formatting
See gh-36207
2026-01-28 11:00:42 +01:00
Juergen Hoeller b0ac8df13e Consistent delegation to target ValidatorFactory 2026-01-27 20:55:01 +01:00
Juergen Hoeller 80a57c2468 Consistent references to Hibernate ORM 7.x 2026-01-27 20:46:30 +01:00
Juergen Hoeller 02e05b40b0 Polishing 2026-01-27 20:30:46 +01:00
Juergen Hoeller c8c99d0464 Support JtaTransactionManager/SpringBeanContainer on HibernateJpaVendorAdapter
Makes ConfigurableJtaPlatform public and removes outdated WebSphere UOW check.

Closes gh-36216
2026-01-27 20:30:21 +01:00
Juergen Hoeller 867dd0e972 Upgrade to Hibernate ORM 7.2.2 2026-01-27 20:28:18 +01:00
Sébastien Deleuze 2c96f18439 Upgrade nullability plugin to 0.0.11
Closes gh-36188
2026-01-27 14:10:18 +01:00
Patrick Strawderman 96fb5d72eb Use Reader.transferTo in FileCopyUtils
Use the transferTo method in FileCopyUtils#copy(Reader, Writer).

Closes gh-36196

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2026-01-27 09:38:58 +01:00
Sébastien Deleuze bc01eeb433 Leverage JUnit 6 suspending function support
Closes gh-36215
2026-01-27 08:45:04 +01:00
rstoyanchev 77c24b28b6 Polishing in ReactorClientHttpConnector 2026-01-26 10:51:00 +00:00
Kuyho Chung e809395635 Clarify Kotlin Coroutine definition
Closes gh-36209
Signed-off-by: Kuyho Chung <kchung1995@gmail.com>
2026-01-26 09:54:15 +01:00
Sam Brannen 801035bea7 Upgrade to AssertJ 3.27.7 2026-01-25 17:51:00 +01:00
Sam Brannen 9e4a54bb99 Ensure RetryTaskTests compiles in Eclipse IDE
Prior to this commit, "new RetryTask<>" declarations whose
TaskCallbacks (implemented as lambda expressions) did not actually
throw an exception resulted in a compilation error in Eclipse:

  "Unhandled exception type Exception".

This is due to the fact that RetryTask is declared with "E extends
Exception", and the Eclipse compiler therefore infers that the lambda
expression potentially throws a checked Exception.

To address that, this commit explicitly declares that the affected
lambda expressions throw unchecked RuntimeExceptions:

  "new RetryTask<String, RuntimeException>"
2026-01-25 17:46:14 +01:00
Sam Brannen e56f7c1e53 Polishing 2026-01-25 17:35:17 +01:00
Padraic Slattery 65bdc78a1e Update GitHub upload-artifact action to version 6
Closes gh-36199

Signed-off-by: Padraic Slattery <pgoslatara@gmail.com>
2026-01-25 17:07:09 +01:00
Juergen Hoeller fd3bbb057e Polishing 2026-01-25 10:42:13 +01:00
Juergen Hoeller c47da1247a Add TaskCallback/Callable/Runnable wrapper for retryable tasks
Closes gh-36208
2026-01-25 10:41:25 +01:00
Juergen Hoeller 22cf7958a5 Revise setPersistenceUnitName javadoc
Closes gh-36205
2026-01-25 10:38:24 +01:00
Phillip Webb ab314aadd9 Refine YamlProcessor to allow different empty values
Update `YamlProcessor` to allow any value to be inserted for
empty entries. This update will allow blank strings to be used
instead of `null` which better aligns with the way that
`.properties` files are loaded.

This update also allows allows the specified `emptyValue` to be
inserted instead of a blank String when the YAML contains `null`
or `~` values.

See gh-36197
See gh-19986

Signed-off-by: Phillip Webb <phil.webb@broadcom.com>
2026-01-24 20:23:48 +01:00
Sébastien Deleuze 611811d8fc Anticipate fixing Kotlin 2.3 compilation warning
Closes gh-36203
2026-01-23 18:34:45 +01:00
Phillip Webb 0c9f40b171 Allow YAML processors to create a flattened map with nulls included
Add an additional `getFlattenedMap` method to `YamlProcessor` to allow
the resulting flattened map to include nulls.

This update will allow processor subclasses to tell the difference
between YAML that is defined with an empty object vs missing the key
entirely:

e.g.:

  application:
    name: test
    optional: {}

vs

  application:
    name: test
    optional: {}

Closes gh-36197

Signed-off-by: Phillip Webb <phil.webb@broadcom.com>
2026-01-23 18:07:06 +01:00
Sam Brannen 5b4eda3d20 Clean up warnings in Gradle build 2026-01-22 17:27:24 +01:00
Sam Brannen af8fd8f07d Upgrade to TestNG 7.12 2026-01-22 17:27:00 +01:00
rstoyanchev 345fa51e77 Handle early exception from AsynchronousFileChannel#write
Closes gh-36184
2026-01-21 15:43:03 +01:00
Juergen Hoeller c05ea841bc Declare Callable parameter with nullable type variable
Closes gh-36191
2026-01-21 19:45:18 +01:00
Juergen Hoeller dab28b5dce Upgrade to Selenium 4.40 2026-01-21 15:09:24 +01:00
Juergen Hoeller 1c4b20287f Use correlation id for explicit sendAndReceive response queue
See gh-36162
See gh-36177
2026-01-21 14:46:36 +01:00
Sébastien Deleuze 8fbd147f0b Upgrade nullability plugin to 0.10.0
Closes gh-36188
2026-01-21 10:39:41 +01:00
Juergen Hoeller 1c56ec3f7e Polishing 2026-01-20 19:24:03 +01:00
Juergen Hoeller 65565de1a8 Prevent accidental printStackTrace() usage in main codebase
Closes gh-36185
2026-01-20 19:23:37 +01:00
Juergen Hoeller b3c26255b1 Upgrade to Hibernate ORM 7.2.1 and Protobuf 4.33.4 2026-01-20 19:23:29 +01:00
Sam Brannen 66962875f9 Reinstate test for Jetty in CookieIntegrationTests 2026-01-20 17:11:03 +01:00
Sam Brannen 5490ba94ae Simplify tests 2026-01-20 17:10:07 +01:00
Sam Brannen 17e02804ba Revert changes to FailingBeforeAndAfterMethodsTestNGTests 2026-01-20 15:47:45 +01:00
Sam Brannen 357205723f Simplify tests 2026-01-20 13:54:19 +01:00
Sam Brannen c4c167c0e1 Convert various test classes to @⁠ParameterizedClass
See gh-35833
2026-01-20 13:53:56 +01:00
rstoyanchev 4119ecc25b Refine solution to clear Netty channel attribute
Closes gh-36158
2026-01-20 11:34:18 +00:00
Sam Brannen 9ebfdb8b6a Fix test parameterization in CaffeineReactiveCachingTests
Prior to this commit, test methods in CaffeineReactiveCachingTests
were parameterized twice with the same configuration class.

See gh-31637
See gh-35833
2026-01-20 11:43:22 +01:00
Sébastien Deleuze c4cb55fbde Modernize DispatcherServlet context hierarchy diagram
See gh-36175
2026-01-20 09:41:28 +01:00
Sam Brannen 7917ae53e8 Polishing 2026-01-19 19:16:28 +01:00
Sébastien Deleuze 693ec8219f Introduce RestClient.ResponseSpec#requiredBody
Closes gh-36173
2026-01-19 18:15:34 +01:00
rstoyanchev 9b95482557 ContentRequestMatchers supports HttpEntity multipart
Closes gh-36154
2026-01-19 17:05:16 +00:00
Sam Brannen a029dfc6a8 Improve display names for parameterized invocations
See gh-35833
2026-01-19 17:59:49 +01:00
Sébastien Deleuze a921c487b4 Fix snippet imports
See gh-36175
2026-01-19 17:38:30 +01:00
Sébastien Deleuze 3f01830d11 Refine CORS documentation to match latest changes
Closes gh-36156
2026-01-19 17:27:19 +01:00
Sébastien Deleuze 64d95d7f3e Extract code snippets from mvc-servlet.adoc
Closes gh-36175
2026-01-19 17:24:38 +01:00
Sébastien Deleuze 5a4b1bd1d1 Extract code snippets from logging.adoc
See gh-36175
2026-01-19 17:24:38 +01:00
Sébastien Deleuze a91402dcc6 Extract code snippets from multipart.adoc
See gh-36175
2026-01-19 17:24:38 +01:00
Sébastien Deleuze 0014e0b3c9 Extract code snippets from context-hierarchy.adoc
See gh-36175
2026-01-19 17:24:38 +01:00
Sébastien Deleuze 49da766551 Extract code snippets from exceceptionhandlers.adoc
See gh-36175
2026-01-19 17:24:38 +01:00
Sébastien Deleuze 50bbe6191a Extract code snippets from container-config.adoc
See gh-36175
2026-01-19 17:24:37 +01:00
Shubham Kalloli a8c33c13e2 Upgraded Apache POI and Commons IO to remediate CVEs
Signed-off-by: Shubham Kalloli <shubham.kalloli@est.tech>
2026-01-19 17:06:02 +01:00
Sam Brannen b164db35c1 Revise contribution
See gh-36170
2026-01-18 16:59:30 +01:00
Tran Ngoc Nhan 385e62dbf0 Replace getErrors() with getBindingResult() in examples
DataBinder#getErrors was removed in v4.0.0.M1.

Closes gh-36170

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-01-18 16:55:32 +01:00
Sam Brannen 4d4adeb2c6 Polish Javadoc 2026-01-18 16:52:04 +01:00
Juergen Hoeller 7aa862f5ec Make scope fully configurable
Closes gh-36171
2026-01-18 15:55:36 +01:00
Juergen Hoeller 2d2809f45c Consistently throw Task/InvocationRejectedException on access rejected
Closes gh-36167
2026-01-18 15:39:58 +01:00
Michał Pisarski 3f390d55f0 Add overloaded sendAndReceive methods to JmsOperations and JmsTemplate to use explicit response queue
Signed-off-by: Michał Pisarski <pisekfm@o2.pl>
2026-01-17 00:16:15 +01:00
Juergen Hoeller 2b96a61063 Apply transactionIsolationLock in EclipseLinkConnectionHandle as well
Closes gh-36165
2026-01-16 23:12:07 +01:00
Juergen Hoeller c55351aa4a Remove javadoc references to WebLogic API
See gh-36151
2026-01-16 22:50:46 +01:00
Juergen Hoeller 48bedd0af1 Revise DefaultMessageListenerContainer connection recovery
Includes listener validation for consistent back-off behavior.

Closes gh-36143
2026-01-16 22:38:01 +01:00
Juergen Hoeller c1b0e68d6c Bring back WebLogicJtaTransactionManager for WebLogic 15.1.1
Closes gh-36151
2026-01-16 22:37:20 +01:00
rstoyanchev fe2113f5a3 Clear Netty channel attribute
Closes gh-36158
2026-01-16 17:21:27 +00:00
Sam Brannen 2ff2a89f22 Upgrade to Gradle 9.3
Closes gh-36161
2026-01-16 15:41:31 +01:00
Brian Clozel 14641c4299 Next development version (v7.0.4-SNAPSHOT) 2026-01-15 09:26:50 +01:00
Juergen Hoeller 62fd09dfa5 Polishing 2026-01-14 22:05:06 +01:00
Sam Brannen 9df19dedaf Revise wording for PauseMode documentation
See gh-36044
2026-01-14 17:02:22 +01:00
Sam Brannen 01a57a7219 Simplify DefaultContextCache implementation by using entrySet().removeIf() 2026-01-14 13:47:44 +01:00
Sam Brannen b5c2003c51 Fix variable name 2026-01-14 13:44:04 +01:00
Sam Brannen 5f5da06467 Upgrade to JUnit 6.0.2
Closes gh-36149
2026-01-14 13:00:31 +01:00
rstoyanchev 9f19b4074d Exclude DataAccessException and MessagingException in DisconnectedClientHelper
Closes gh-36134
2026-01-14 11:44:43 +00:00
Yanming Zhou a784eb0ab4 Improve DisconnectedClientHelper to better guard ClassNotFoundException
Before this commit, WebClientException is ignored if RestClientException is not present.

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-01-14 11:03:09 +00:00
Sam Brannen fa404063ab Avoid unnecessary pausing of application contexts for tests
In commit 9711db787e, we introduced support for disabling test
application context pausing via a Spring property or JVM system
property, as follows.

-Dspring.test.context.cache.pause=never

However, users may actually be interested in keeping the pausing
feature enabled if contexts are not paused unnecessarily.

To address that, this commit introduces a new
PauseMode.ON_CONTEXT_SWITCH enum constant which is now used by default
in the DefaultContextCache.

With this new pause mode, an unused application context will no longer
be paused immediately. Instead, an unused application context will be
paused lazily the first time a different context is retrieved from or
stored in the ContextCache. This effectively means that an unused
context will not be paused at all if the next test class uses the same
context.

Although ON_CONTEXT_SWITCH is the now the default pause mode, users
still have the option to enable context pausing for all usage scenarios
(not only context switches) by setting the Spring property or JVM
system property to ALWAYS (case insensitive) — for example:

-Dspring.test.context.cache.pause=always

This commit also introduces a dedicated "Context Pausing" section in
the reference manual.

See gh-36117
Closes gh-36044
2026-01-14 11:37:37 +01:00
Sam Brannen 948af8bcc6 Fix typo in Javadoc 2026-01-14 11:37:37 +01:00
Juergen Hoeller e3997e3060 Upgrade to Reactor 2025.0.2 and Micrometer 1.16.2
Includes Vavr 0.11, HtmlUnit 4.21, Checkstyle 13.0

Closes gh-36144
Closes gh-36145
2026-01-14 11:29:29 +01:00
Juergen Hoeller 0323218129 Deprecate PagedListHolder and PropertyComparator for removal
Closes gh-36139
2026-01-13 21:20:38 +01:00
Brian Clozel a62699ccfc Further Gradle deprecation fixes
Closes gh-36132
2026-01-13 09:32:08 +01:00
Yejeong, Ham dd6faf62bb Build: Fix deprecated Groovy syntax in spring-aspects
Replace legacy Groovy DSL property assignment (space-separated) with
the standard assignment operator (=) in spring-aspects.gradle.

The legacy syntax is deprecated in Gradle 9 and will be removed in
Gradle 10. This change eliminates deprecation warnings during the
build and ensures future compatibility.

See gh-36132

Signed-off-by: Yejeong, Ham <dev@thelightway.kr>
2026-01-13 09:31:48 +01:00
rstoyanchev cbc2c63abc Polishing contribution
Closes gh-36125
2026-01-12 12:48:49 +00:00
hojeong 2f83e6b4b5 Update reference for API version without a value
See gh-36125

Signed-off-by: hojeong park <parkhj062@gmail.com>
Signed-off-by: hojeong <parkhj062@gmail.com>
2026-01-12 12:24:13 +00:00
Sam Brannen 19c2506476 Do not restart contexts if pausing is disabled
If the PauseMode is set to NEVER, we never pause contexts and therefore
do not need to restart them.

See gh-36117
2026-01-12 12:24:18 +01:00
Brian Clozel ee4780fab6 Build javadoc against HttpClient 5.6.x 2026-01-12 12:11:26 +01:00
Sam Brannen 8e6d44349d Polishing 2026-01-12 11:50:03 +01:00
Sam Brannen ceb6ab3c74 Introduce ContextCacheTestSuite 2026-01-12 11:48:31 +01:00
Sébastien Deleuze 7140ab5bca Simplify TransactionalOperator.executeAndAwait
This commit simplifies TransactionalOperator.executeAndAwait by removing
Optional. It is based on a proposal by @vlsi refined to handle properly
reactive transaction commits (see related commit
217b6e37a6).

Closes gh-36039
2026-01-12 10:52:39 +01:00
rstoyanchev 615c25d4fa Polishing contribution
Closes gh-36126
2026-01-12 09:51:17 +00:00
Juhwan Lee 3df66580f3 Support property placeholders in HTTP service registry
Implement EmbeddedValueResolverAware to resolve ${...} placeholders
in @HttpExchange URL attributes.

See gh-36126
Signed-off-by: Juhwan Lee <jhan0121@gmail.com>
2026-01-12 08:56:35 +00:00
Sam Brannen 9711db787e Introduce Spring property to disable context pausing for tests
Spring Framework 7.0 introduced support for pausing inactive
application contexts between test classes and restarting them once they
are needed again. If pausing and restarting are fast, this feature does
not have a negative impact on test suites.

However, if the pausing or restarting of certain Lifecycle components
in the application context is slow, that can have a negative impact on
the duration of the overall test suite.

In gh-36044, we hope to find a way to avoid unnecessarily pausing an
application context after a test class if the same context is used by
the next test class that is run. That should help reduce the risk of a
negative impact caused by the pause/restart feature; however, for
certain scenarios that may not be enough. In light of that, this commit
introduces a mechanism for completely disabling the pausing feature via
a Spring property or JVM system property, as follows.

-Dspring.test.context.cache.pause=never

See gh-35168
See gh-36044
Closes gh-36117
2026-01-11 11:42:14 +01:00
Yanming Zhou d3a385d222 Retain original requested bean class for SpringContainedBean
Closes GH-36115

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-01-09 19:52:22 +01:00
Juergen Hoeller 38a397873e Polishing 2026-01-09 19:33:52 +01:00
Juergen Hoeller 73fa708905 Fix SmartFactoryBean type matching for ResolvableType.NONE
Closes gh-36123
2026-01-09 19:33:32 +01:00
rstoyanchev 23a532ed82 Polishing contribution
Closes gh-36097
2026-01-09 15:06:07 +00:00
Nabil Fawwaz Elqayyim e0db67aa3b Fix double encoding in DefaultApiVersionInserter
Ensure that the DefaultApiVersionInserter does not re-encode existing parts
of the input URI by using the 'encoded' flag in UriComponentsBuilder.

This prevents percent-encoded characters (like %20) from being incorrectly
double-encoded to %2520 during the version insertion process.

See gh-36097

Signed-off-by: Nabil Fawwaz Elqayyim <master@nabilfawwaz.com>
2026-01-09 15:06:07 +00:00
Sam Brannen 1370a833ed Further clarify the meaning of maxAttempts in FixedBackOff and ExponentialBackOff
See gh-36119
2026-01-09 15:37:32 +01:00
Sam Brannen 8d4320e9ef Honor headers in AbstractMessageSendingTemplate.convertAndSend() variant
Prior to this commit, the following method in AbstractMessageSendingTemplate
simply ignored the supplied headers map.

convertAndSend(Object, Map<String, Object>, MessagePostProcessor)

Closes gh-36120
2026-01-09 15:04:47 +01:00
Sam Brannen c53a00a6c4 Polish Javadoc 2026-01-09 15:04:47 +01:00
Sam Brannen 00606d2171 Use default destination name with JmsClient.sendAndReceive() and headers
Prior to this commit, if the JmsClient was configured with a default
destination name (instead of a default Destination), invoking the
sendAndReceive() variant which accepts a map of headers resulted in an
exception stating that a default destination is required.

To address that, this commit overrides the
convertSendAndReceive(Object, Map<String, Object>, Class<T>, MessagePostProcessor)
method in JmsMessagingTemplate to add support for both a default
Destination and a default destination name.

Closes gh-36118
2026-01-09 15:04:47 +01:00
Juergen Hoeller 3e5d8d184a Clarify back-off attempts versus retries for BackOff maxAttempts setting
Closes gh-36119
2026-01-09 14:32:59 +01:00
rstoyanchev b69cbad38d Fall back on the value type in BodyInserters if necessary
Closes gh-36078
2026-01-09 11:52:18 +00:00
rstoyanchev 39106b5811 Restore ApiVersionResolver contract
Instead of making it async and having a sync subinterface variant,
this restores ApiVersionResolver to be as it was with an async
subinterface variant.

ApiVersionStrategy, and the infrastructure invoking it, remains
async first, but also accommodates sync resolvers.

This should provide a better balance with backwards compatibility
while also accommodating async version resolution as the less
common scenario.

See gh-36084
2026-01-09 10:25:44 +00:00
rstoyanchev 2f91baa71c Polishing in ApiVersionResolver 2026-01-09 09:38:53 +00:00
rstoyanchev d8e303f95b Merge branch for PR 36084
Resolve conflicts and refactor merged code in AbstractHandlerMapping

See gh-36084
2026-01-08 17:43:35 +00:00
rstoyanchev 8ff89ffda2 Update contribution
- deprecate sync method on ApiVersionResolver
- add SyncApiVersionResolver
- refactor resolverParseAndValidateApiVersion method

See gh-36084
2026-01-08 17:41:27 +00:00
rstoyanchev dcf5d69d94 Rename async methods
See gh-36084
2026-01-08 17:41:19 +00:00
rstoyanchev 7d33a87278 Polishing contribution
See gh-36084
2026-01-08 17:41:11 +00:00
Jonathan Kaplan b878771dca Update ApiVersionResolver to return Mono String
See gh-36084

Signed-off-by: Jonathan Kaplan <jkaplan@empty-nes.com>
2026-01-08 17:41:01 +00:00
Sam Brannen 06f0f2f317 Polishing 2026-01-08 18:32:57 +01:00
Sam Brannen f16474d585 Reliably resolve overloaded write methods in PropertyDescriptorUtils
Prior to this commit, the algorithm behind determineBasicProperties()
in PropertyDescriptorUtils did not reliably resolve the correct write
method when one candidate write method had a parameter type that was a
subtype of another candidate write method whose parameter type was an
exact match for the resolved read method's return type.

In other words, the algorithm always resolved the candidate write
method with the most specific parameter type (similar to covariant
return types) which is not necessarily the resolved read method's
return type.

To address that, this commit ensures that determineBasicProperties()
always selects an exact match for the write method whenever possible.

As an added bonus, determineBasicProperties() no longer invokes
BasicPropertyDescriptor.getWriteMethod(), which avoids triggering the
resolution algorithm multiple times (when multiple write method
candidates exist), resulting in lazy resolution of the write method the
first time client code invokes getWriteMethod().

Closes gh-36113
2026-01-08 18:13:46 +01:00
Sam Brannen dfb17d84d6 Reintroduce deleted text in Javadoc 2026-01-08 18:11:55 +01:00
Sébastien Deleuze eea9130ea6 Fix context class resolution for nested types
This commit introduces ContextClassRequestBodyAdvice which adds a
"contextClass" hint allowing to resolve generics for Optional,
HttpEntity or ServerSentEvent container types.

Closes gh-36111
2026-01-08 16:53:28 +01:00
Sébastien Deleuze d85ac300bb Update JsonView advices Javadoc
Make the documentation relevant for all Jackson converters.
2026-01-08 16:53:19 +01:00
Sébastien Deleuze d4d10dc75d Enable JacksonSmileEncoderTests#annotEncodeServerSentEvent
This test has been fixed at some (unidentified) point and should be
enabled.
2026-01-08 16:49:11 +01:00
Juergen Hoeller 169465cce1 Align InvocationRejectedException javadoc with TaskRejectedException
See gh-36109
See gh-36114
2026-01-08 16:18:14 +01:00
Juergen Hoeller c4d5e3c57d Add task rejection support to SyncTaskExecutor's concurrency throttle
Closes gh-36114
2026-01-08 15:51:17 +01:00
Juergen Hoeller 38f5f4de8e Add configurable throttle policy to @ConcurrencyLimit annotation
Closes gh-36109
2026-01-08 15:50:57 +01:00
Sébastien Deleuze 644072f7ea Refine the AOT Cache creation section
Put Java 25+ snippet first and refine the note.

Closes gh-36108
2026-01-08 14:50:14 +01:00
Mikhail Polivakha 859940b824 Polishing of the AOT cache documentation
See gh-36108
Signed-off-by: Mikhail Polivakha <mikhailpolivakha@email.com>
2026-01-08 14:49:21 +01:00
Sam Brannen 992ae2ea6b Precompute PropertyDescriptor array in SimpleBeanInfoFactory
Closes gh-36112
2026-01-08 13:34:03 +01:00
Sam Brannen 589a10e6e6 Polish Javadoc formatting 2026-01-08 13:25:15 +01:00
Sam Brannen 79bd2b11da Polishing 2026-01-08 13:23:23 +01:00
Sam Brannen 0624c3a597 Introduce tests for non-generic types for PropertyDescriptorUtils
This commit introduces tests for proper support for non-generic types
in PropertyDescriptorUtils.determineBasicProperties(), effectively to
test the status quo and serve as regression tests.
2026-01-08 13:15:53 +01:00
Sébastien Deleuze bf695c058d Configure Jackson XML codecs when present
Closes gh-35752
2026-01-08 11:52:38 +01:00
Sébastien Deleuze a1204a405a Introduce Jackson XML codecs
See gh-35752
2026-01-08 11:52:38 +01:00
rstoyanchev e0aa116217 Re-initialize API version in each HandlerMapping
Each HandlerMapping may have its own ApiVersionStrategy rules, or may not
have one at all. This change ensures independent decisions.

See gh-36059
2026-01-08 09:32:34 +00:00
Philip Bolting 7fdda1cf0f Fix typo in MVC REST Error Responses documentation
Signed-off-by: Philip Bolting <pb@philipbolting.de>
2026-01-08 08:40:31 +01:00
rstoyanchev 05b98b0a32 Suppress API version errors on ERROR dispatch
While an API version may be important for mapping in an ERROR dispatch,
it is more important to allow the original exception to be handled.

Closes gh-36058
2026-01-07 16:00:40 +00:00
rstoyanchev 46efd930f0 Update docs
On the order of a ControllerAdvice that overrides the handling of
built-in exceptions in a scenario with Boot autoconfig.

Closes gh-35982
2026-01-07 16:00:39 +00:00
rstoyanchev a9027ddf76 Refine handling of API version errors
Among HandlerMapping's some may not expect an API version. This is why
those that do must be careful not to raise API validation errors if
they don't match the request.

Closes gh-36059
2026-01-07 16:00:39 +00:00
rstoyanchev 5551292639 Polishing contribution
Closes gh-35989
2026-01-07 16:00:39 +00:00
Minkyu Park 1240962d68 Optimize single-char wildcard path matching performance
Use lazy evaluation in SingleCharWildcardedPathElement to avoid
unnecessary Character.toLowerCase() calls.
Resolves performance TODO from 2017.

Closes gh-36095

Signed-off-by: Minkyu Park <rb6609@naver.com>
2026-01-07 14:37:54 +01:00
Brian Clozel 9ef4ceb047 Polishing contribution
Closes gh-36083
2026-01-07 14:29:13 +01:00
hayden.rear c7413cbdfc Configure HttpMessageConverters as a list
This commit adds a new `configureMessageConvertersList` method on the
builder to add/remove/move converters in the resulting list before they
are individually post-processed.

This allows to re-introduce a behavior that was missing with the new
contract: the ability to append a converter at the end of the list.

See gh-36083

Signed-off-by: hayden.rear <hayden.rear@gmail.com>
2026-01-07 14:29:05 +01:00
Sam Brannen e94aaab288 Improve exception message for JPA entity scanning 2026-01-07 13:13:27 +01:00
Sébastien Deleuze c5044bfdbc Refine multipart-forms.adoc
See gh-36094
2026-01-07 12:49:25 +01:00
Tran Ngoc Nhan 9abe4b46ca Fix Kotlin example in Multipart Content
Closes gh-36094
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-01-07 12:20:59 +01:00
Sébastien Deleuze 192da6229c Fix locale interceptor code snippet
See gh-36105
See gh-36099
2026-01-07 09:52:33 +01:00
Sébastien Deleuze e1402fd252 Upgrade Antora dependencies
Closes gh-36105
2026-01-07 09:51:04 +01:00
Sébastien Deleuze 253eb28458 Update CBOR Jackson codec Javadoc
See gh-20513
2026-01-06 18:26:26 +01:00
Brian Clozel 97cd9dd03b Support HttpComponents 5.6
This commit updates the HttpComponents HttpClient to refer to the parsed
`HttpEntity` for the content-related HTTP response headers such as
encoding and body length.

Closes gh-36100
2026-01-06 16:56:45 +01:00
Sébastien Deleuze 3027d78f40 Modernize the DispatcherServlet Locale documentation
The Java sample for "Locale Interceptor" shows a
`urlHandlerMapping.setUrlMap(Map.of("...` line due the inability to
disable the code chomping Asciidoctor extension with the code include
one. It will be fixed by a subsequent commit or a bug fix in
https://github.com/spring-io/asciidoctor-extensions.

Closes gh-36099
2026-01-06 11:04:05 +01:00
Sébastien Deleuze d752e80356 Add missing line to MVC config interceptors snippet
To ensure consistency with Kotlin and XML snippets.
2026-01-06 11:04:05 +01:00
Sam Brannen e7f019bd3f Introduce tests for PropertyDescriptorUtils with bounded generics
As a follow up to commit 4b07edbaeb, this commit introduces tests for
PropertyDescriptorUtils.determineBasicProperties() using types with
bounded generics.

Note, however, that the following test effectively fails, since
PropertyDescriptorUtils.determineBasicProperties() does not match the
behavior of java.beans.Introspector. Consequently, this test method
currently changes the expected write method type conditionally.

resolvePropertiesWithUnresolvedGenericsInSubclassWithOverloadedSetter()

See gh-36019
2026-01-05 17:12:59 +01:00
Sébastien Deleuze 6939cb90df Add ServerRequest.bindAndAwait Kotlin extension
Closes gh-36092
2026-01-02 18:06:27 +01:00
Sébastien Deleuze 3ddaf51f5d Remove @EnableWebFlux from documentation code snippets
Like what we did for `@EnableWebMvc`, we want to remove `@EnableWebFlux`
from typical code snippets extending WebFluxConfigurer to make them more
Spring Boot friendly.

Closes gh-36091
2026-01-02 18:06:27 +01:00
Sébastien Deleuze 6a28f06b2e Extract some WebFlux functional snippets
See gh-36089
2026-01-02 18:06:27 +01:00
Sébastien Deleuze 5ecece91dc Polishing
See gh-36089
2026-01-02 18:06:26 +01:00
Tran Ngoc Nhan 13d7a6c480 Fix Kotlin snippets in "CORS" and "Functional Endpoints" sections
Closes gh-36089
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-01-02 18:05:34 +01:00
Sébastien Deleuze 6e66af15a6 Extract remaining WebMVC configuration snippets
Closes gh-36088
2025-12-31 12:15:12 +01:00
Sébastien Deleuze cd8e38448c Remove the "Other Web Frameworks" documentation
Closes gh-36086
2025-12-31 10:58:44 +01:00
Sébastien Deleuze 93ce99ea06 Polishing 2025-12-31 10:58:44 +01:00
Sébastien Deleuze bf8a1600e5 Add missing override annotations to PropagationContextElement
Closes gh-36087
2025-12-31 10:58:43 +01:00
Sébastien Deleuze 96eee8c8b1 Make nullability flexible in ConverterFactory#getConverter
This commits udpates ConverterFactory#getConverter to accept both
nullable and non-null T in the Converter return value.

Flexible nullability at ConverterFactory type level would have been
ideal, but is not possible due to how Kotlin deals with Class<T> when
T is nullable.

See gh-36063
2025-12-30 16:07:39 +01:00
Tran Ngoc Nhan b8ed4f2ba8 Correct encode Javadoc for UriComponents and UriComponentsBuilder
Closes gh-36040
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-12-30 15:26:08 +01:00
Tran Ngoc Nhan 0048f01074 Fix links in client-builder.adoc
Closes gh-36079
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-12-30 15:11:52 +01:00
Sébastien Deleuze 0b904a878d Fix indentation in framework-docs.gradle 2025-12-30 15:04:14 +01:00
Sébastien Deleuze 9c78f84915 Modernize the view technologies section
Closes gh-35450
2025-12-30 15:03:34 +01:00
Sébastien Deleuze a55309d478 Null-mark org.springframework.test.web.support package
See gh-36054
2025-12-29 17:09:53 +01:00
Sébastien Deleuze 46fb7c026c Upgrade to nullability plugin 0.0.9
This commit also replaces Arch Unit packageInfoShouldBeNullMarked() rule
by either configuring requireExplicitNullMarking = false when the whole
module does not have JSpecify annotations, or explicit @NullUnmarked
when some have and some don't.

See gh-36054
2025-12-29 17:09:53 +01:00
Manu Sridharan d36244ee56 Update to NullAway 0.12.15 and fix new warnings
Closes gh-36054
Signed-off-by: Manu Sridharan <msridhar@gmail.com>
2025-12-29 17:09:52 +01:00
Sam Brannen 4b07edbaeb Reliably resolve generic read/write methods in PropertyDescriptorUtils
Prior to this commit, the determineBasicProperties() method in
PropertyDescriptorUtils did not reliably resolve read/write methods in
type hierarchies with generics. This utility method is used by
SimpleBeanInfoFactory which is used by BeanUtils and BeanWrapperImpl.
Thus, failure to reliably resolve read/write JavaBeans methods resulted
in bugs in certain scenarios.

For example, BeanUtils.copyProperties() randomly failed to copy certain
properties if the write method for the property could not be resolved.

To address such issues, this commit revises the implementation of
PropertyDescriptorUtils as follows.

1) Read methods with covariant return types are now consistently
   resolved correctly.

2) If multiple ambiguous write methods are discovered, the algorithm now
   checks for an exact match against the resolved generic parameter type
   as a fallback.

Closes gh-36019
2025-12-29 12:18:23 +02:00
Brian Clozel eb3bfc0d65 Document HttpHeaders#toSingleValueMap() case-sensitive behavior
This commit updates the `HttpHeaders` javadoc to better reflect that
`asSingleValueMap()`, `asMultiValueMap()`, and `toSingleValueMap()` all
return case-sentitive map implementations.

Closes gh-36070
2025-12-29 11:02:28 +01:00
木葉 Scarlet d077e043d6 Consistently declare @⁠Nullable on parameter in equals() implementations
Closes gh-36075

Signed-off-by: 木葉 Scarlet <93977077+mukjepscarlet@users.noreply.github.com>
2025-12-29 11:43:49 +02:00
Sam Brannen 7212fbe36a Polishing 2025-12-29 11:43:23 +02:00
Juergen Hoeller 5b6c231788 Use dedicated ApplicationEventFactory interface in EventPublicationInterceptor
See gh-36072
2025-12-25 11:25:54 +01:00
Juergen Hoeller aeb0115605 Introduce MethodRollbackEvent for @Transactional rollbacks
Closes gh-36073
2025-12-24 18:54:39 +01:00
Juergen Hoeller 08104100d3 Introduce generalized MethodFailureEvent for use in EventPublicationInterceptor
Closes gh-36072
2025-12-24 18:50:04 +01:00
Brian Clozel 214cb2c1e1 Polishing contribution
Closes gh-36056
2025-12-23 15:33:20 +01:00
Terry Tao 26e0f550b0 Fix LinkedCaseInsensitiveMap entrySet case-insensitivity
See gh-36056

Signed-off-by: Terry Tao <yueyang.tao@gmail.com>
2025-12-23 15:33:14 +01:00
Brian Clozel 012fb29097 Fix nullness mismatch for Converter/ConverterFactory
In gh-35947, the `Converter` contract was refined to allow for nullable
return values. This created a mismatch with the `ConverterFactory`
contract.

This commit fixes this mismatch by allowing nullable return values in
`Converter` instances created by `ConverterFactory`.

Fixes gh-36063
2025-12-23 11:37:44 +01:00
Juergen Hoeller 92a43c007a Introduce MethodRetryEvent for @Retryable execution
Closes gh-35382
2025-12-23 09:28:23 +01:00
Brian Clozel fc1ff88ede Avoid duplicate flushes in String Http converter
Prior to this commit, the `StringHttpMessageConverter` would perform a
flush after writing the body, via `StreamUtils#copy`. This operation is
not needed as a flush is already performed by the abstract class.

Flush calls by HTTP message converters is being reconsidered altogether
in gh-35427, but we should first remove this extra operation.

Closes gh-36065
2025-12-22 15:34:41 +01:00
Juergen Hoeller fc2e1dd2e5 Avoid redirection for JUnit javadoc link 2025-12-21 22:07:14 +01:00
Juergen Hoeller ffd2e03a9f Upgrade to Log4J 2.25.3, Protobuf 4.33.2, Selenium 4.39 2025-12-21 22:01:11 +01:00
Juergen Hoeller fd6e15bb4d Align execute(TaskCallback) declaration with return value nullability
See gh-36057
2025-12-21 21:44:10 +01:00
Juergen Hoeller 85c6fb0fd0 Add invoke(Runnable) as variant of invoke(Supplier)
See gh-36052
2025-12-21 21:40:50 +01:00
Juergen Hoeller 0b2bb7e751 Declare TaskCallback return value as potentially nullable
Closes gh-36057
2025-12-20 15:21:14 +01:00
Juergen Hoeller faa17abdae Introduce invoke(Supplier) with last original RuntimeException propagated
Closes gh-36052
2025-12-20 15:20:58 +01:00
Brian Clozel 89ca8e6976 Document how to discard response body with WebTestClient
This commit better documents the ways to discard the response body with
`WebTestClient`.

Closes gh-35953
2025-12-19 16:48:57 +01:00
Brian Clozel 7353ab41d2 Fix memory leak in WiretapConnector
Prior to this commit, we found in gh-35953 that using the `WebTestClient`
the following way leaks data buffers:

```
var body = client.get().uri("download")
  .exchange()
  .expectStatus().isOk()
  .returnResult()
  .getResponseBodyContent();
```

Here, the test performs expectations on the response status and headers,
but not on the response body. The WiretapConnector already supports this
case by subscribing to the Flux response body in those cases and
accumulating the entire content as a single byte[].

Here, the `DataBuffer` instances are not decoded by any `Decoder` and
are not released. This results in a memory leak.

This commit ensures that the automatic subscription in
`WiretapConnector` also releases the buffers automatically as the DSL
does not allow at that point to go back to performing body expectations.

Fixes gh-36050
2025-12-19 16:10:33 +01:00
Stéphane Nicoll f1db0ef036 Do not display error location when unknown
Closes gh-36041
2025-12-17 14:33:14 +01:00
Stéphane Nicoll e9a4b93477 Expose compiler warnings in CompilationException
This commit improves TestCompiler to expose both errors and warnings
instead of an opaque message. When compilation fails, both errors and
warnings are displayed.

This is particularly useful when combined with the `-Werror` option
that turns the presence of a warning into an error.

Closes gh-36037
2025-12-17 14:33:14 +01:00
Juergen Hoeller 86e89d53a9 Do not attempt nested PropertyHandler resolution for argument conversion
Includes fix for return type declaration in PropertyAccessor subclasses.

See gh-36024
2025-12-17 14:30:44 +01:00
Juergen Hoeller c813577908 Consistently use DefaultParameterNameDiscoverer.getSharedInstance()
This includes MethodParameter resolving getParameterName() by default now.
initParameterNameDiscovery(null) can be used to suppress such resolution.

Closes gh-36024
2025-12-17 13:39:02 +01:00
Brian Clozel ec6b7730a2 Polishing contribution
Closes gh-36032
2025-12-17 12:35:30 +01:00
jher235 fc29d88778 Use StringBuilder in JdbcTemplate for batch updates
See gh-36032

Signed-off-by: jher235 <tim668666@gmail.com>
2025-12-17 12:35:30 +01:00
Brian Clozel 033df68da6 Fix Javadoc links 2025-12-17 10:21:30 +01:00
Brian Clozel df5b06dabc Fix RfcUriParser parsing for single char fragments
Prior to this commit, the `RfcUriParser` would ignore URI fragments if
their length is < 2. This commit fixes the length check to allow for
single char fragments when parsing URIs.

Fixes gh-36029
2025-12-17 09:51:53 +01:00
Juergen Hoeller 3d8d7ffa1e Upgrade to AspectJ 1.9.25, Tomcat 11.0.15, Netty 4.2.9, Jackson 3.0.3, EclipseLink 5.0.0-B13, Mockito 5.21, Checkstyle 12.3 2025-12-16 13:55:36 +01:00
Juergen Hoeller 6d5a512d90 Suppress serial warning 2025-12-16 13:54:40 +01:00
Sébastien Deleuze d4e4250bb1 Remove JavaScript/Kotlin from ScriptEngine documentation
Closes gh-27919
2025-12-15 18:43:09 +01:00
Sam Brannen 93bc022a46 Extract CopyPropertiesTests as nested test class in BeanUtilsTests 2025-12-15 18:11:35 +01:00
Sam Brannen a4c72c8fcf Polish integration tests 2025-12-15 15:05:05 +01:00
Juergen Hoeller 3d7862abb6 Upgrade to Hibernate ORM 7.2.0.Final 2025-12-15 14:27:39 +01:00
Juergen Hoeller 7fd0c5041d Use default ConstraintValidatorFactory for provider-internal validators
Closes gh-36012
2025-12-15 14:26:58 +01:00
Juergen Hoeller d99ace81c1 Enforce publicly accessible method for externalClassLoader(ClassLoader)
Closes gh-36012
2025-12-14 14:48:33 +01:00
Sam Brannen ed451c107f Polishing 2025-12-13 17:11:05 +01:00
Sam Brannen 452257eb96 Revise contribution
See gh-36022
2025-12-13 17:10:06 +01:00
Tran Ngoc Nhan a7863a0877 Fix typos and grammar in reference manual
Closes gh-36022

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-12-13 16:50:39 +01:00
Sam Brannen 1da0e13a2b Polishing 2025-12-12 15:41:23 +01:00
Stéphane Nicoll ee6a156275 Refresh GitHub Actions 2025-12-12 11:51:11 +01:00
Brian Clozel 0b6fe8dcc5 Next development version (v7.0.3-SNAPSHOT) 2025-12-11 17:34:57 +01:00
Juergen Hoeller e2c9dc7138 Revert to previous behavior for 7.0.2 (based on Boot/Data impact)
Preparing the revised behavior for 7.1 instead.

See gh-31456
2025-12-11 15:37:41 +01:00
Sam Brannen 1818161f58 Ensure bottom-up semantics in resolveDefaultContextConfigurationAttributes()
Closes gh-31456
2025-12-11 13:37:32 +01:00
Sam Brannen 8916ee9f81 Set inheritLocations to true in ContextConfigurationAttributes constructor
Closes gh-36000
2025-12-11 13:06:50 +01:00
Brian Clozel d835fe311d Do not send null HTTP header value in JdkClientHttpRequest
Prior to this commit, the `JdkClientHttpRequest` would add all values
from `HttpHeaders` to the native request builder. This could cause
`NullPointerException` being thrown at runtime because the `HttpClient`
does not support that.

This commit replicates a fix that was applied to the
`SimpleClientHttpRequest`, turning null values into empty "".

Fixes gh-35996
2025-12-11 09:45:30 +01:00
rstoyanchev 0eefac21c9 Polishing contribution
Closes gh-35758
2025-12-10 18:17:12 +00:00
Samuel Gulliksson e99791f289 Improve i18n-support for NoResourceFoundException.
Return the requested resource as ErrorResponse.getDetailMessageArguments,
making it usable with message customization and i18n.

See gh-35758

Signed-off-by: Samuel Gulliksson <samuel.gulliksson@gmail.com>
2025-12-10 18:17:12 +00:00
Sam Brannen 658775b914 Avoid unnecessary list creation & processing in AbstractTestContextBootstrapper
Closes gh-35995
2025-12-10 18:56:57 +01:00
Sam Brannen ea7a1d789e Resolve ContextLoader only once in AbstractTestContextBootstrapper
Closes gh-35994
2025-12-10 18:56:50 +01:00
Sam Brannen 4ae471df01 Resolve all default context configuration within @⁠Nested hierarchy
Prior to this commit, if an enclosing test class (such as one annotated
with @⁠SpringBootTest or simply @⁠ExtendWith(SpringExtension.class))
was not annotated with @⁠ContextConfiguration (or @⁠Import with
@⁠SpringBootTest), the ApplicationContext loaded for a @⁠Nested test
class would not use any default context configuration for the enclosing
test class.

Effectively, a default XML configuration file or static nested
@⁠Configuration class for the enclosing test class was not discovered
by the AbstractTestContextBootstrapper when attempting to build the
MergedContextConfiguration (application context cache key).

To address that, this commit introduces a new
resolveDefaultContextConfigurationAttributes() method in
ContextLoaderUtils which is responsible for creating instances of
ContextConfigurationAttributes for all superclasses and enclosing
classes. This effectively enables AbstractTestContextBootstrapper to
delegate to the resolved SmartContextLoader to properly detect a
default XML configuration file or static nested @⁠Configuration class
even if such classes are not annotated with @⁠ContextConfiguration.

Closes gh-31456
2025-12-10 18:56:42 +01:00
Sam Brannen 75e3f44a7b Update Javadoc due to changes in retry support
See gh-35940
2025-12-10 16:45:43 +01:00
Juergen Hoeller adcd7cb4cb Introduce RetryListener#onRetryableExecution callback with RetryState
Closes gh-35940
2025-12-10 15:09:33 +01:00
Sam Brannen d0be180a69 Make @​Retryable and RetryTemplate timeout tests more robust
See gh-35963
2025-12-10 14:22:42 +01:00
Sam Brannen 3731fed4ca Revise MultiValueMapCollector implementation and tests
See https://github.com/spring-projects/spring-data-commons/issues/3420
Closes gh-35958
2025-12-10 13:35:00 +01:00
u214578 bfc02cda0c Introduce MultiValueMapCollector for use with streams
See https://github.com/spring-projects/spring-data-commons/issues/3420
See gh-35958

Signed-off-by: Florian Hof <florian.hof@sbb.ch>
2025-12-10 13:28:59 +01:00
Sam Brannen f734d04a0d Fix grammar 2025-12-10 13:28:59 +01:00
Sam Brannen ce4c9ebe3c Polishing 2025-12-10 12:31:26 +01:00
Brian Clozel 7c4801304d Upgrade to Reactor 2025.0.1
Closes gh-35985
2025-12-09 22:19:53 +01:00
Brian Clozel 2731183420 Upgrade to Micrometer 1.16.1
Closes gh-35984
2025-12-09 22:18:03 +01:00
Sam Brannen 38cf4ab3fc Make RetryTemplate timeout tests more robust
See gh-35963
2025-12-09 17:03:41 +01:00
Sam Brannen 2137ec70d2 Make @​Retryable timeout tests more robust
See gh-35963
2025-12-09 16:56:53 +01:00
Sam Brannen 61201db704 Improve error message for preemptive timeout in RetryTemplate
The error message in such cases now indicates that the retry process
is being aborted preemptively due to pending sleep time.

For example:

  Retry policy for operation 'myMethod' would exceed timeout (5 ms) due
  to pending sleep time (10 ms); preemptively aborting execution

See gh-35963
2025-12-09 16:46:44 +01:00
Sam Brannen 2643c6212f Delete obsolete test code 2025-12-09 16:39:20 +01:00
Sam Brannen b46328a000 Fix broken assertions in @​Retryable timeout tests
See gh-35963
2025-12-09 16:38:05 +01:00
Sam Brannen cc4c693db7 Log RetryException for @Retryable methods
To improve diagnostics, this commit logs a DEBUG message including the
RetryException thrown by RetryTemplate when it's used behind the scenes
for @Retryable method invocations.

Closes gh-35983
2025-12-09 16:24:00 +01:00
Sam Brannen a206ea8b12 Make @​Retryable timeout tests more robust
See gh-35963
2025-12-09 16:10:43 +01:00
Sam Brannen 9f1d9fe82c Support timeouts in @​Retryable and RetryPolicy
Specifically, this commit introduces:

- timeout and timeoutString attributes in @​Retryable

- a default getTimeout() method in RetryPolicy

- a timeout() method in RetryPolicy.Builder

- an onRetryPolicyTimeout() callback in RetryListener

- support for checking exceeded timeouts in RetryTemplate (also used
  for imperative method invocations with @​Retryable)

- support for checking exceeded timeouts in reactive pipelines with
  @​Retryable

Closes gh-35963
2025-12-09 14:06:35 +01:00
Juergen Hoeller ab33000750 Do not keep target connection after failed settings
Includes aligned setReadOnly exception suppression.

Closes gh-35980
2025-12-09 12:59:27 +01:00
Juergen Hoeller e2ab9cd5da Use composed cache key for different SmartFactoryBean object types
Closes gh-35974
2025-12-09 12:59:19 +01:00
Sam Brannen 103db5429a Use AtomicIntegerAssert 2025-12-09 12:43:18 +01:00
Sam Brannen 68f8139206 Polishing 2025-12-08 17:11:38 +01:00
Sam Brannen a9da900b5b Fix test logic 2025-12-08 17:10:27 +01:00
Brian Clozel e7e4b3559a Polishing contribution
Closes gh-35978
2025-12-08 16:10:20 +01:00
Johnny Lim feb77f924a Fix SubscriberInputStream.resume()
See gh-35978

Signed-off-by: Johnny Lim <izeye@naver.com>
2025-12-08 16:10:05 +01:00
Brian Clozel 12c3dc0cbe Fix compressed HEAD requests handling in JDK client
Prior to this commit, the `JdkClientHttpRequestFactory` would support
decompressing gziped/deflate encoded response bodies but would fail if
the response has no body but has a "Content-Encoding" response header.
This happens as a response to HEAD requests.

This commit ensures that only responses with actual message bodies are
decompressed.

Fixes gh-35966
2025-12-08 15:23:55 +01:00
Juergen Hoeller df27627516 Accept assignable match for covariant return type
See gh-35936
2025-12-08 12:41:43 +01:00
Sam Brannen 939aa84214 Revise type-level nullability in ConvertingComparator
This commit revises the type-level nullability declaration in
ConvertingComparator in order to adapt to recent nullability changes in
Converter.

This commit also revises the workaround in commit 53d9ba879d.

See gh-35947
2025-12-08 11:22:14 +01:00
Brian Clozel 9f77f401ad Complete Propagator.Getter implementation
As of Micrometer Tracing 1.6.0, the `Propagator.Getter` interface
adds a new `getAll` method with a default implementation return a
singleton collection.

This commit adds the missing implementation override in both Servlet and
Reactor web server contexts.

Fixes gh-35965
2025-12-08 11:07:30 +01:00
Sébastien Deleuze f19f1a667c Add support for package-private BeanRegistrar
Closes gh-35803
2025-12-05 17:04:51 +01:00
Sébastien Deleuze 69207c6c16 Introduce BeanFactoryInitializationCode#getClassName
See gh-35803
2025-12-05 17:04:51 +01:00
Sébastien Deleuze f61832ecb8 Fix indentation 2025-12-05 17:04:51 +01:00
Juergen Hoeller 14790493f4 Upgrade to Log4J 2.25.2, Groovy 5.0.3, Jetty 12.1.5, Jetty Reactive HttpClient 4.1.4, Checkstyle 12.2 2025-12-05 17:03:57 +01:00
Juergen Hoeller 53d9ba879d Suppress NullAway warning for nullable Annotation return value 2025-12-05 16:53:24 +01:00
Juergen Hoeller 9d2d9ae0ff Reinstate stopOrder test
See gh-35964
2025-12-05 16:30:00 +01:00
Juergen Hoeller c74af40288 Stop already started Lifecycle beans on cancelled refresh
Closes gh-35964
2025-12-05 16:14:27 +01:00
Juergen Hoeller 196c1dd51c Handle absolute file URLs in getClassPathManifestEntriesFromJar
Closes gh-35682
2025-12-05 16:13:30 +01:00
Sam Brannen 44689b9ec0 Simplify RestTestClientIntegrationTests and remove duplicate field 2025-12-05 16:00:42 +01:00
Sam Brannen b916dc962e Document that annotations which reference types not present are ignored
Add warnings to the class-level Javadoc for MergedAnnotations,
AnnotatedTypeMetadata, AnnotationMetadata, and MethodMetadata to point
out that annotations may be ignored if their attributes reference types
that are not present in the classpath.

Closes gh-35959
2025-12-05 15:50:02 +01:00
Tran Ngoc Nhan 87d0113b25 Correct Reactive Libraries reference link
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-12-05 14:09:02 +00:00
rstoyanchev cee185ce3b Append query on redirect in UrlHandlerFilter
Closes gh-35873
2025-12-05 12:35:32 +00:00
rstoyanchev e45727d4fa Polishing in InMemoryWebSessionStore
Closes gh-35866
2025-12-05 12:29:11 +00:00
Mengqi Xu bc088ebdef Allow configuring default maxIdleTime on InMemoryWebSessionStore.
See gh-35866

Signed-off-by: Mengqi Xu <2663479778@qq.com>
2025-12-05 12:28:37 +00:00
Sam Brannen f1cf91c9f9 Polishing 2025-12-05 12:22:24 +01:00
Sébastien Deleuze d36475cb4c Use flexible generic type level nullability in Converter
Allow defining converters that return non-null values by
leveraging flexible generic type level nullability in
org.springframework.core.convert.converter.Converter.

Closes gh-35947
2025-12-05 07:28:52 +01:00
Sébastien Deleuze 8b6d7e0da7 Refine KotlinDetector#hasSerializableAnnotation
Refine KotlinDetector#hasSerializableAnnotation in order to detect
deeply nested generic types.

Closes gh-35960
2025-12-04 15:54:03 +01:00
Sam Brannen 0a86a7e3a8 Use == instead of instanceof for primitive array type checks
Closes gh-35962
2025-12-04 15:06:08 +01:00
rstoyanchev 8edde374bb Lower bad requests to DEBUG level in AbstractHandshakeHandler
Closes gh-35930
2025-12-04 09:07:55 +00:00
rstoyanchev 35b58cd0ee Avoid http - web.utils package cycle
Closes gh-35952
2025-12-04 09:07:55 +00:00
Juergen Hoeller dfc900c7c4 Add @Override to existing resetCaches() methods
See gh-35845
See gh-35840
2025-12-04 07:09:21 +01:00
Juergen Hoeller 07c0213f20 Polishing 2025-12-04 00:12:31 +01:00
Juergen Hoeller 667851c0fa Avoid computeIfAbsent for createMappings which calls back into same map
Closes gh-35944
2025-12-04 00:12:22 +01:00
Juergen Hoeller 96aadc2b12 Add resetCaches() method to general CacheManager interface
Closes gh-35845
See gh-35840
2025-12-04 00:12:13 +01:00
Sam Brannen 2c6ccaea05 Use simple type name for meta-annotation in log message
In contrast to the previous commit, a warning similar to the following
is now logged in such cases.

WARN o.s.c.a.MergedAnnotation -
  Failed to introspect meta-annotation @MyAnnotation on class
  example.Config: java.lang.TypeNotPresentException:
  Type example.OptionalDependency not present

See gh-35927
2025-12-03 17:15:53 +01:00
Sam Brannen 62d09be2ae Log warning if meta-annotation is ignored due to types not present
Prior to this commit, if a meta-annotation could not be loaded because
its attributes referenced types not present in the classpath, the
meta-annotation was silently ignored.

To improve diagnostics for such use cases, this commit introduces WARN
support in IntrospectionFailureLogger and revises AttributeMethods.canLoad()
to log a warning if a meta-annotation is ignored due to an exception
thrown while attempting to load its attributes.

For example, a warning similar to the following is now logged in such
cases.

WARN o.s.c.a.MergedAnnotation -
  Failed to introspect meta-annotation @example.MyAnnotation on class
  example.Config: java.lang.TypeNotPresentException:
  Type example.OptionalDependency not present

This commit also improves log messages in AnnotationTypeMappings.

Closes gh-35927
2025-12-03 17:00:24 +01:00
Stéphane Nicoll 47f65b3dff Use correct product name for IntelliJ IDEA 2025-12-02 16:54:56 +01:00
Sam Brannen c7e24a5c26 Update antora-extensions to 1.14.7
Closes gh-35949
2025-12-02 15:33:56 +01:00
Sam Brannen a493bd959d Fix nullability in TestContextAnnotationUtils.findAnnotationDescriptor() 2025-12-02 15:32:32 +01:00
Juergen Hoeller 92e9543ad4 Select method with resolved return type match (among multiple candidates)
Removes unnecessary array type check for parameters of candidate methods.

Closes gh-35936
2025-12-01 23:25:59 +01:00
ivonaest 68231aa08c Upgrade json-path to 2.10.0
Closes gh-35924
Signed-off-by: ivonaest <ivona.cvija@est.tech>
2025-12-01 15:27:45 +01:00
Juergen Hoeller 71d18ebabc Improve debug log for received message 2025-12-01 15:03:08 +01:00
Juergen Hoeller 3ccb0786db Clear remaining invoker resources when releasing shared Connection
Closes gh-35932
2025-12-01 15:03:00 +01:00
rstoyanchev 15c16d2c3a FragmentsRendering exposes its fragments
Closes gh-35775
2025-12-01 11:17:40 +00:00
John Niang 5dcb85db8d BindingContext constructor uses given ReactiveAdapterRegistry arg
Closes gh-35771

Signed-off-by: John Niang <johnniang@foxmail.com>
2025-12-01 11:07:11 +00:00
rstoyanchev 4ae03ecd40 Use channelId for ReactorNettyWebSocketSession's id
Closes gh-35883
2025-12-01 11:01:04 +00:00
jnizet 1603045c7d Avoid passing null as argument marked as non-nullable
Closes gh-35933
Signed-off-by: jnizet <jb@ninja-squad.com>
2025-12-01 10:29:20 +01:00
Juergen Hoeller ace2b2bac9 Upgrade to Hibernate ORM 7.2.0.CR3 2025-11-30 11:32:33 +01:00
Juergen Hoeller f082c435e1 Polishing 2025-11-30 11:31:10 +01:00
Juergen Hoeller c6810334ca Move extended web data binders to common support packages
This resolves cyclic dependencies between function and annotation-based packages.

See gh-35800
2025-11-30 11:31:04 +01:00
Juergen Hoeller 3b90311c17 Revise ApplicationContext#getId() nullability to non-null
Closes gh-35925
2025-11-28 13:58:11 +01:00
Sam Brannen 946fc65712 Stop linking to 6.1.22-SNAPSHOT reference docs
With this commit, we now include snapshots for main (which currently
correlates to 7.0.x), 6.2.x, and 7.0.x to 9.*.x.

Closes gh-35923

(cherry picked from commit 305a512a55)
2025-11-28 13:00:22 +01:00
Juergen Hoeller fd25e2f468 Use concurrent set for reactive transaction synchronizations
Closes gh-35921
2025-11-28 10:24:21 +01:00
Sébastien Deleuze 46ceedf992 Refine AbstractKotlinSerializationHttpMessageConverter#canWrite
AbstractKotlinSerializationHttpMessageConverter#writeInternal is able to
resolve the ResolvableType from the Object parameter when the provided
one via the ResolvableType parameter is not resolvable, but
AbstractKotlinSerializationHttpMessageConverter#canWrite lacks of
such capability.

This commit refines
AbstractKotlinSerializationHttpMessageConverter#canWrite to resolve the
ResolvableType from the Class<?> parameter when the provided one via the
ResolvableType parameter is not resolvable.

Closes gh-35920
2025-11-27 16:52:45 +01:00
Brian Clozel a4b3111928 Make HttpEntity headers mutables
Since its inception, instantiating an `HttpEntity` makes its
`HttpHeaders` read-only. While immutability is an interesting design
principle, here we shouldn't enforce this.

For example, developers can expect to instantiate a `ResponseEntity`
and still mutate its headers.

Closes gh-35888
2025-11-27 16:37:47 +01:00
Juergen Hoeller 4c4161c8c0 Cache resolved singleton beans in injected Provider instance
Includes alignment for direct Optional injection points, consistently registering an autowiredBeanNames entry for an Optional as well as a non-Optional injection result.

Closes gh-35373
Closes gh-35919
2025-11-27 16:01:57 +01:00
Juergen Hoeller 61d5413c23 Tighten cacheable decision behind @Lazy injection point
Closes gh-35917
2025-11-27 16:00:43 +01:00
Brian Clozel 08e6d762d2 Always buffer response body in RestTestClient
Prior to this commit, `RestTestClient` tests could only perform
expectations on the response without consuming the body. In this case,
the client could leak HTTP connections with the underlying HTTP library
because the response was not entirely read.

This commit ensures that the response is always fully drained before
performing expectations. The client is configured to buffer the response
content, so further body expectations are always possible.

Fixes gh-35784
2025-11-27 15:50:00 +01:00
Sébastien Deleuze 7a19cbb452 Change AbstractSmartHttpMessageConverter canRead/canWrite overrides
Extending AbstractSmartHttpMessageConverter typically requires to
override both Class and ResolvableType variants of canRead. This was not
intended as SmartHttpMessageConverter interface has default methods
doing the conversion from Class parameters to ResolvableType ones, but
AbstractHttpMessageConverter overrides it.

This commit changes AbstractSmartHttpMessageConverter canRead/canWrite
overrides from ResolvableType to Class ones that delegate to the
ResolvableType variants. It also refines
AbstractJacksonHttpMessageConverter accordingly.

Closes gh-35916
2025-11-27 15:38:35 +01:00
Juergen Hoeller 2f1e1d483a Remove early adaptation to JTA 2.1 setReadOnly method
The UserTransaction read-only semantics are still in discussion. If they turn out to be stricter than Spring's read-only hint, we should only apply them when configured with an explicit enforceReadOnly=true flag at the Spring JtaTransactionManager level (similar to the same-named flag in DataSourceTransactionManager).

See gh-35915
See gh-35633
2025-11-27 13:16:45 +01:00
Sam Brannen 24d152cdab Convert sentence to tip in Kotlin testing chapter
This commit also moves the text to a more appropriate section of the
chapter.
2025-11-27 12:37:06 +01:00
Sam Brannen cc530d4df2 Support RuntimeBeanReference(name, type) in AOT-generated code
The RuntimeBeanReference(name, type) constructor was introduced in 7.0;
however, BeanDefinitionPropertyValueCodeGeneratorDelegates in our AOT
infrastructure was not updated to support the new constructor.

This commit revises BeanDefinitionPropertyValueCodeGeneratorDelegates
to ensure that AOT generated code for a RuntimeBeanReference uses the
RuntimeBeanReference(name, type) constructor, thereby retaining the
originally configured bean name.

See gh-35101
Closes gh-35913
2025-11-27 11:37:46 +01:00
Juergen Hoeller 6c3132cb8c Narrow method annotation check in hasQualifier to setter methods
Closes gh-35908
2025-11-26 23:01:55 +01:00
Juergen Hoeller a15274d431 Revise volatile access to singletonInstance field
For defensiveness against a singletonInstance/initialized visibility mismatch, we accept the locking overhead for pre-initialized null values (where we need the initialized field) in favor of a defensive fast path for non-null values (where we only need the singletonInstance field).

Closes gh-35905
2025-11-26 17:20:11 +01:00
Tran Ngoc Nhan 45d4fd3b7e Fix broken Javadoc links to methods
Closes gh-35899
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-11-26 17:05:16 +01:00
Sam Brannen 3fd5d69939 Remove JUnit 4 based meta-annotation example
This commit also converts the examples from XML configuration files to
@⁠Configuration classes.

Closes gh-35903
2025-11-26 16:37:04 +01:00
Sébastien Deleuze 8647c44364 Add dynamic ObjectToObjectConverter hints
This commit refines BindingReflectionHintsRegistrar with additional
dynamic hints for application-defined types, main core Java conversion
ones being already covered by ObjectToObjectConverterRuntimeHints.

Closes gh-35847
2025-11-26 16:17:41 +01:00
Sam Brannen 6504177e7b Refer to "Spring Tools" instead of "Spring Tools for Eclipse"
Closes gh-35901
2025-11-26 16:11:41 +01:00
Sam Brannen c1125699bb Document that the SpringExtension requires JUnit Jupiter 6.0 or higher
Closes gh-35900
2025-11-26 15:47:21 +01:00
Juergen Hoeller f58d0f6aae Consistent namespace element declarations 2025-11-26 15:09:05 +01:00
Juergen Hoeller c1b6bfb681 Expose non-existent resources at the end of the sorted result
Closes gh-35895
2025-11-26 15:08:24 +01:00
Juergen Hoeller 9d4abb63d8 Clarify JMS sessionTransacted flag for local versus global transaction
Closes gh-35897
2025-11-26 15:06:22 +01:00
rstoyanchev a9a404266c Data binding from pathvars and headers in fn handlers
Closes gh-35800
2025-11-26 12:30:48 +00:00
rstoyanchev b29f4ed37e Minor refactoring in DefaultServerRequest
Ensure bind logic is shared across DefaultServerRequest and
BuiltServerRequest.

See gh-35800
2025-11-26 12:30:48 +00:00
rstoyanchev 4847ee80b0 Add required type to TypeMismatchException message args
Closes gh-35837
2025-11-26 12:30:48 +00:00
Sam Brannen f4ee120a42 Use current links to JUnit documentation
Closes gh-35892
2025-11-26 13:22:26 +01:00
Sam Brannen e625a28f6d Fix formatting for backticks in Kotlin docs 2025-11-26 13:15:56 +01:00
Sam Brannen 45c1cd9295 Link to Spring Framework Artifacts wiki page
This commit revises the Integration Testing chapter to reference the
"Spring Framework Artifacts" wiki page instead of the nonexistent
"Dependency Management" section of the reference manual.

Closes gh-35890
2025-11-26 12:55:01 +01:00
Sébastien Deleuze 2641b5d783 Polishing
See gh-35861
2025-11-26 10:27:01 +01:00
Sébastien Deleuze dc0c463137 Keep using ZoneId.of("GMT") in HttpHeaders
Otherwise some header values are changed from "GMT" to "Z" and
some tests are broken. We don't want to change the current
runtime behavior, so this commit reverts the related change to
keep using ZoneId.of("GMT") in HttpHeaders.

Closes gh-35861
2025-11-26 10:27:00 +01:00
Vincent Potucek 83bbf16e6c Modernize java.time API usages
See gh-35861
Signed-off-by: Vincent Potucek <vpotucek@me.com>
2025-11-26 10:24:34 +01:00
Juergen Hoeller 3686b89ab5 Revise proxyTargetClass handling in ResilientMethodsConfiguration and ProxyAsyncConfiguration
An annotation-specified proxyTargetClass attribute must only be applied when true, otherwise we need to participate in global defaulting.

Closes gh-35863
2025-11-25 18:03:04 +01:00
Sébastien Deleuze 85ca9f46dd Support reading unresolvable types in AbstractJacksonHttpMessageConverter
Closes gh-35889
2025-11-25 16:00:04 +01:00
Sébastien Deleuze e2287020c3 Polishing
See gh-35889
2025-11-25 16:00:04 +01:00
Sébastien Deleuze 9e18c75ff1 Fix ApiVersionConfigurer Kotlin code sample
Closes gh-35887
2025-11-25 14:51:31 +01:00
Sébastien Deleuze fb9f31d101 Update reference documentation to use Jackson 3
Closes gh-35886
2025-11-25 13:31:39 +01:00
Sébastien Deleuze 4ee0a8ee33 Refine Kotlin Serialization codec type checks
ServerSentEvent and String checks, removed from
KotlinSerializationSupport in Spring Framework 7.0, are reintroduced by
this commit at the right level (KotlinSerializationSupport for
ServerSentEvent and KotlinSerializationString(Decoder|Encoder) for
String).

Closes gh-35885
2025-11-25 13:31:39 +01:00
Sébastien Deleuze f3908832c5 Add WebFlux SSE support with GSON
Closes gh-35884
2025-11-25 13:31:39 +01:00
Sébastien Deleuze c10266e57e Fix handling of ServerSentEvent with Jackson encoder
This commit fixes ServerSentEvent handling with Jackson encoder
when no Accept header is specified.

It also moves the String checks to the JSON codec level, as they do not
make sense for binary formats.

Closes gh-35872
2025-11-25 13:31:38 +01:00
Sébastien Deleuze 1b6b163f24 Polishing 2025-11-25 12:37:45 +01:00
github-actions[bot] 8642a39a03 Update Antora Spring UI to v0.4.25
Closes gh-35876

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-11-24 14:44:34 +01:00
github-actions[bot] f62cc98a97 Update Antora Spring UI to v0.4.22
Closes gh-35860
2025-11-24 10:12:11 +01:00
Tran Ngoc Nhan c599775a9e Refine nullability of Assert#noNullElements
Closes gh-35868
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-11-24 09:42:44 +01:00
Brian Clozel 4bc97ad532 Next development version (v7.0.2-SNAPSHOT) 2025-11-20 11:53:27 +01:00
Sam Brannen abec289e9f Stop mentioning non-existent NestedServletException
NestedServletException has been removed from the framework.
2025-11-19 17:32:19 +01:00
Juergen Hoeller 3026f0a49b Lazily initialize ProblemDetail for picking up actual status code
Closes gh-35829
2025-11-19 17:21:32 +01:00
Sam Brannen 9fe4e7798d Fix link to MockMvc test in HtmlUnit section
See gh-35853
2025-11-19 17:17:50 +01:00
Sam Brannen d178930186 Polishing 2025-11-19 17:11:17 +01:00
Tran Ngoc Nhan 91d2a51f3f Fix cross-reference links in HtmlUnit sections
Closes gh-35853

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-11-19 16:53:49 +01:00
Juergen Hoeller f456674529 Polishing 2025-11-19 16:19:14 +01:00
Juergen Hoeller 35b8fbf901 Remove javadoc references to deprecated PropertiesBeanDefinitionReader
Closes gh-35836
2025-11-19 16:18:56 +01:00
Sébastien Deleuze 1d1851f48a Refine RestOperations Kotlin extensions nullability
This commit aligns RestOperationsExtensions.kt nullability with the
Java APIs one, like what has been done in gh-35846 for JdbcOperations.

Closes gh-35852
2025-11-19 16:08:51 +01:00
Sébastien Deleuze 23f0cfb925 Fix JdbcOperations Kotlin extensions
This commit updates JdbcOperationsExtensions.kt to:
 - Properly use the spread operator for invoking Java methods with
   a varargs parameter
 - Align JdbcOperationsExtensions return values nullability
   with the Java API (breaking change)
 - Use varargs where Java counterpart does (breaking change, undo some
   changes from gh-34668)
 - Use nullable args instead of non-nullable ones

 Closes gh-35846
2025-11-19 15:55:00 +01:00
Brian Clozel 2cca56064e Restrict "validateMultiReleaseJar" task to Java 25+
This commit configures the "validateMultiReleaseJar" Gradle task only if
the current Java runtime for Gradle is 25+.

Closes gh-35850
2025-11-19 13:55:27 +01:00
Yanming Zhou e0353fe75f Fix buildSrc:test failing on JDKs before JDK 25 with Non-English locale
See https://github.com/spring-projects/spring-framework/issues/35777#issuecomment-3551591336

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-11-19 17:43:12 +08:00
rstoyanchev f80b79bc45 Configure JsonPath in RestTestClient with MappingProvider
Closes gh-35793
2025-11-18 15:46:57 +00:00
rstoyanchev adffd3dcf6 Fix JsonConverterDelegate initialization in RestTestClient
If the RestClient was built with default message converters, then
in mutate, the saved builder also has 0 converters, and adding a
interferes with default registrations.

We need to check if there are no converters at all, and if so
use the default registrations.

See gh-35793
2025-11-18 15:46:57 +00:00
rstoyanchev 284a28659d Add isEmpty() to HttpMessageConverters
See gh-35793
2025-11-18 15:46:57 +00:00
Juergen Hoeller 57a1d4007b Fix getCacheNames() concurrent access in NoOpCacheManager
Closes gh-35842
2025-11-18 13:37:39 +01:00
Juergen Hoeller bc3431f435 Add resetCaches() method to Caffeine/ConcurrentMapCacheManager
Closes gh-35840
2025-11-18 13:37:14 +01:00
Juergen Hoeller de5b9aab55 Narrow Aware interface exclusion check to BeanFactoryAware only
Closes gh-35835
2025-11-18 13:36:29 +01:00
Sébastien Deleuze f72891c24d Upgrade to Gradle 9.2.1
Closes gh-35839
2025-11-18 10:13:56 +01:00
Sam Brannen fac8708857 Migrate CronTriggerTests to @⁠ParameterizedClass
This commit migrates CronTriggerTests to @⁠ParameterizedClass as a proof
of concept for how this can be applied across the code base.

See gh-35833
2025-11-17 16:36:57 +01:00
Sam Brannen 0342cd0904 Merge HtmlCharacterEntityDecoderTests into HtmlUtilsTests
See gh-35711
2025-11-17 15:27:51 +01:00
Brian Clozel e0fd42981a Fix compilation warnings
See gh-35711
2025-11-17 15:24:44 +01:00
Brian Clozel 87d95dc30a Polishing contribution
Closes gh-35477
2025-11-17 15:07:48 +01:00
potato 47de8b05e6 Fix HtmlUtils unescape for supplementary chars
See gh-35477

Signed-off-by: potato <65760583+juntae6942@users.noreply.github.com>
2025-11-17 15:07:42 +01:00
Patrick Strawderman 3b6be3d4d3 Fix single-check idiom in UnmodifiableMultiValueMap
Read the respective fields only once in the values(), entrySet(), and
keySet() methods.

Closes gh-35822

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2025-11-17 15:02:53 +01:00
github-actions[bot] 6115c3966c Update Antora Spring UI to v0.4.20
Closes gh-35813
2025-11-17 14:23:26 +01:00
Sam Brannen 09a8bbc0c7 Polish contribution
See gh-35817
2025-11-17 12:20:12 +01:00
Patrick Strawderman ed75906834 Fix Spliterator characteristics in ConcurrentReferenceHashMap
The Spliterators returned by values, entrySet, and keySet incorrectly
reported the SIZED characteristic, instead of CONCURRENT. This could
lead to bugs when the map is concurrently modified during a stream
operation.

For keySet and values, the incorrect characteristics are inherited from
AbstractMap, so to rectify that the respective methods are overridden,
and custom collections are provided that report the correct Spliterator
characteristics.

Closes gh-35817

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2025-11-17 11:55:38 +01:00
Sébastien Deleuze 4756a4be23 Polishing
See gh-35820
2025-11-17 11:33:56 +01:00
Tran Ngoc Nhan 40c5c5d5f0 Add Kotlin code samples for KT-22208
Closes gh-35820
Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-11-17 11:33:56 +01:00
Sébastien Deleuze 6b8552b4c1 Refine ParameterizedPreparedStatementSetter nullability
This commit refines ParameterizedPreparedStatementSetter nullability
to ensure consistency with JdbcTemplate#batchUpdate.

Closes gh-35749
2025-11-17 10:31:56 +01:00
Brian Clozel f42eea183e Polishing tests
Closes gh-35678
2025-11-17 09:39:50 +01:00
Sam Brannen ebcfe113d1 Disable flaky failWhileSendingMultipartRequest() test
See gh-35678
2025-11-15 15:55:10 +01:00
Sam Brannen b133c2b346 Document semantics of SpringExtension.getApplicationContext()
Since getApplicationContext() was originally not intended to be part of
the public API, its Javadoc is intentionally sparse. However, since it
is actually a public API used by third parties, this commit improves the
documentation for getApplicationContext() by pointing out that invoking
the method actually results in the context being eagerly loaded, which
may not be desired.

This commit also updates the Javadoc for supportsParameter() along the
same lines.

Closes gh-35764
2025-11-15 15:44:21 +01:00
Sam Brannen 648629fab2 Polish Javadoc for SpringExtension 2025-11-15 15:42:32 +01:00
Sam Brannen f2bf227cd0 Upgrade to testng-engine 1.1.0 2025-11-15 12:42:24 +01:00
Brian Clozel 1260081436 Add WebClient integration test for multipart
This commit adds an integration test for `WebClient`, specifically
testing that a failure happening while pulishing the request body is
reported on the main reactive pipeline.

See gh-35678
2025-11-14 16:34:15 +01:00
Tran Ngoc Nhan 18d8d458e3 Fix typos in tests
Closes gh-35815

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-11-13 13:43:54 +01:00
Brian Clozel 1aa520162b Next development version (v7.0.1-SNAPSHOT) 2025-11-13 11:33:12 +01:00
Brian Clozel 333031e64c Merge branch '6.2.x' 2025-11-13 10:11:56 +01:00
Brian Clozel ed444eb0c1 Next development version (v6.2.14-SNAPSHOT) 2025-11-13 10:11:35 +01:00
Juergen Hoeller 888d0f9adc Upgrade to Micrometer 1.16.0
Includes Tomcat 11.0.14, Jackson 3.0.2/2.20.1, Hibernate 7.2.0.CR2, Checkstyle 12.1.2

Closes gh-35811
2025-11-13 09:31:36 +01:00
Brian Clozel 08798e05de Merge branch '6.2.x' 2025-11-13 09:19:56 +01:00
Brian Clozel 89e0273244 Fix UnprocessableContent support in WebClientResponseException
Prior to this commit, `WebClientResponseException` would only support
the deprecated "unprocessable entity" status.
This commit adds the missing support for "unprocessable content" when
creating exceptions with `WebClientResponseException#create`.

Fixes gh-35802
2025-11-13 08:59:35 +01:00
Brian Clozel 8c4b30a9c7 Merge branch '6.2.x' 2025-11-12 21:58:02 +01:00
Brian Clozel 395ddd2ca6 Upgrade to Jetty 12.1.4
Closes gh-35805
2025-11-12 21:52:22 +01:00
Sam Brannen a5a0840f48 Stop implying that HttpHeaders implements java.util.Map 2025-11-12 18:02:30 +01:00
Sam Brannen a54618b498 Simplify HttpHeaders(HttpHeaders) constructor 2025-11-12 17:47:39 +01:00
Sam Brannen d37030b9e1 Polishing 2025-11-12 17:47:39 +01:00
Sam Brannen f62380cc7b Make WebSocketHttpHeaders compatible with HttpHeaders APIs
Prior to this commit (and despite the changes made in commit
4593f877dd), WebSocketHttpHeaders was not compatible with the
HttpHeaders(HttpHeaders) constructor or the copyOf(HttpHeaders) and
readOnlyHttpHeaders(HttpHeaders) factory methods.

To address that, this commit revises the implementation of
WebSocketHttpHeaders so that it only extends HttpHeaders, analogous to
ReadOnlyHttpHeaders. In other words, WebSocketHttpHeaders no longer
stores or delegates to a local HttpHeaders instance.

Closes gh-35792
2025-11-12 17:08:35 +01:00
Sam Brannen 93b72fa080 Polishing 2025-11-12 16:53:24 +01:00
Brian Clozel 3ac7f83900 Relax media type checks in HttpMessageConverters
Prior to this commit, `HttpMessageConverters` would assert that the
given converter in `withXmlConverter` has a media type that is equal to
"application/xml" in its list of supported converters.

This approach would not work if the given converter supports
"application/xml;charset=UTF-8" because of the strict equal check being
performed.

This commit ensures that we only consider the type and subtype of the
considered media types when comparing, removing the parameters from the
picture.

Fixes gh-35801
2025-11-12 15:50:15 +01:00
Sam Brannen deca37da4a Improve Javadoc for new HttpHeaders features 2025-11-12 15:11:33 +01:00
Sam Brannen 347040c5a4 Improve Javadoc for HttpHeaders.formatHeaders() 2025-11-12 14:17:13 +01:00
Juergen Hoeller 8999336458 Make SessionHolder publicly accessible for external resource management
Closes gh-35799
2025-11-12 14:14:04 +01:00
Brian Clozel a8b8468af0 Update Antora UI Spring to v0.4.19
This commit also updates the GitHub workflow for automatic updates to
the currently supported branches.

Closes gh-35798
2025-11-12 12:32:08 +01:00
rstoyanchev b648e226cd Update deprecation notices in WebTestClient 2025-11-12 10:54:46 +00:00
rstoyanchev fb8bbe838d Polishing in RouterFunctions
See gh-35791
2025-11-12 10:52:04 +00:00
rstoyanchev dff0858340 Update generics on WebMvc RouterFunctions.Builder
Same as 7555d0e489, but for WebMvc.

Closes gh-35791
2025-11-12 08:07:36 +00:00
Juergen Hoeller eadc5b09ac Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java
2025-11-11 19:46:12 +01:00
Juergen Hoeller 39d29c8f7e Replace ConcurrentReferenceHashMap with synchronized IdentityHashMap
Closes gh-35788
2025-11-11 19:31:08 +01:00
Sam Brannen 4593f877dd Fix HttpHeaders and WebSocketHttpHeaders interop issues
Since HttpHeaders no longer implements MultiValueMap (see gh-33913),
a few interoperability issues have arisen between HttpHeaders and
WebSocketHttpHeaders.

To address those issues, this commit:

- Revises addAll(HttpHeaders), putAll(HttpHeaders), and putAll(Map) in
  HttpHeaders so that they no longer operate on the HttpHeaders.headers
  field.

- Overrides addAll(String, List), asSingleValueMap(), and
  asMultiValueMap() in WebSocketHttpHeaders.

- Deletes putAll(HttpHeaders), putAll(Map), and forEach(BiConsumer) in
  WebSocketHttpHeaders, since they do not need to be overridden.

This commit also removes unnecessarily overridden Javadoc in
WebSocketHttpHeaders and revises the implementation of several methods
in HttpHeaders so that they delegate to key methods such as get()
instead of directly accessing the HttpHeaders.headers field.

See gh-33913
Closes gh-35792
2025-11-11 18:29:29 +01:00
Sam Brannen a3e8a173a8 Polishing 2025-11-11 16:52:07 +01:00
Juergen Hoeller 15a3f425cb Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java
2025-11-11 15:42:11 +01:00
Sébastien Deleuze 687c40454f Merge branch '6.2.x' 2025-11-11 13:54:35 +01:00
Juergen Hoeller 0552cdb7ed Revise ConcurrentReferenceHashMap for @ConcurrencyLimit race condition
Closes gh-35788
See gh-35794
2025-11-11 13:39:15 +01:00
rstoyanchev 721c40b5c5 Add defaultVersion to set of supported versions
Closes gh-35755
2025-11-11 12:28:28 +00:00
rstoyanchev 7555d0e489 Update generics on WebFlux RouterFunctions.Builder
Consistently allow subtypes of ServerResponse to be returned for any
provided HandlerFunction and HandlerFilterFunction. Both allow use of
subtypes such as EntityServerResponse and RenderingResponse, and
in the end we support any ServerResponse.

Closes gh-35791
2025-11-11 12:28:28 +00:00
Sébastien Deleuze 622251d89a Merge branch '6.2.x' 2025-11-11 13:00:16 +01:00
Sam Brannen e4f8ae0338 Stop setting local port in HtmlUnitRequestBuilder
This commit picks up where commit a0baeae9cf left off.

Specifically, in order to align with the behavior of
AbstractMockHttpServletRequestBuilder, HtmlUnitRequestBuilder no longer
sets the local port in the MockHttpServletRequest.

See gh-35709
2025-11-10 17:20:23 +01:00
Brian Clozel e85afff8a3 Merge branch '6.2.x' 2025-11-10 16:30:50 +01:00
rstoyanchev 9daf99af3f Merge branch '6.2.x' 2025-11-10 14:43:58 +00:00
Sam Brannen c6b4b43076 Merge branch '6.2.x' 2025-11-10 15:39:18 +01:00
Sébastien Deleuze 543390c84f Merge branch '6.2.x' 2025-11-10 12:04:15 +01:00
Sébastien Deleuze 816cee12e5 Change default converters ordering
This commit adds a new withKotlinSerializationCborConverter
method to HttpMessageConverters and updates DefaultHttpMessageConverters
to put JSON and CBOR Kotlin Serialization converters before
their Jackson/GSON/JSONB counterparts with their new default
behavior that only handles classes with `@Serializable` at
type or generics level.

When there is no alternative converter for the same mime type,
Kotlin Serialization converters handle all supported cases.

Closes gh-35761
2025-11-10 11:36:00 +01:00
Sébastien Deleuze d64edc01c0 Prevent Kotlin Serialization converters side effects
This commit updates Kotlin serialization converters to perform
an additional check invoking
KotlinDetector#hasSerializableAnnotation to decide if the
related type should be processed or not.

The goal is to prevent in the default arrangement conflicts
between general purpose converters like Jackson and
Kotlin serialization when both are used.

New constructors allowing to specify a custom predicate
are also introduced.

See gh-35761
2025-11-10 11:35:44 +01:00
Sébastien Deleuze d0f57013b0 Change default codecs ordering and add Jackson CBOR
This commit updates BaseDefaultCodecs by adding Kotlin
Serialization codecs before their Jackson/GSON counterparts
with their new default behavior that only handles classes with
`@Serializable` at type or generics level.

When there is no alternative codec for the same mime type,
Kotlin Serialization codecs handle all supported cases.

This commit also adds missing Jackson CBOR codecs, and moves both
CBOR and Protobuf codecs to a lower priority, as they are less
commonly used than JSON ones, with the same ordering used on
Spring MVC side.

See gh-35761
Closes gh-35787
2025-11-10 11:35:29 +01:00
Sébastien Deleuze 19dd488dd7 Prevent Kotlin Serialization codecs side effects
This commit updates Kotlin serialization codecs to perform
an additional check invoking
KotlinDetector#hasSerializableAnnotation to decide if the
related type should be processed or not.

The goal is to prevent in the default arrangement conflicts
between general purpose codecs like Jackson and
Kotlin serialization when both are used.

New constructors allowing to specify a custom predicate
are also introduced.

See gh-35761
2025-11-10 11:35:02 +01:00
Sébastien Deleuze a68d60768e Introduce KotlinDetector#hasSerializableAnnotation
This commit introduces a KotlinDetector#hasSerializableAnnotation
utility method designed to detect types annotated with
`@Serializable` at type or generics level.

See gh-35761
2025-11-10 11:34:49 +01:00
Sam Brannen 24590092ef Rename maxAttempts to maxRetries in @⁠Retryable and RetryPolicy
Prior to this commit, the maximum number of retry attempts was
configured via @⁠Retryable(maxAttempts = ...),
RetryPolicy.withMaxAttempts(), and RetryPolicy.Builder.maxAttempts().
However, this led to confusion for developers who were unsure if
"max attempts" referred to the "total attempts" (i.e., initial attempt
plus retry attempts) or only the "retry attempts".

To improve the programming model, this commit renames maxAttempts to
maxRetries in @⁠Retryable and RetryPolicy.Builder and renames
RetryPolicy.withMaxAttempts() to RetryPolicy.withMaxRetries(). In
addition, this commit updates the documentation to consistently point
out that total attempts = 1 initial attempt + maxRetries attempts.

Closes gh-35772
2025-11-10 11:15:25 +01:00
Brian Clozel 771517dc36 Ensure that jar verification runs on JDK 25
This commit ensures that the JAR verification task runs on JDK 25 as
this feature has been introduced in https://bugs.openjdk.org/browse/JDK-8355940

Fixes gh-35777
See gh-35773
2025-11-10 09:57:06 +01:00
Sam Brannen 388abf9312 Fix Javadoc link 2025-11-09 16:05:06 +01:00
Sam Brannen e91befa5bb Polishing 2025-11-09 15:24:26 +01:00
Juergen Hoeller 5353c964ef Upgrade to Hibernate Validator 9.1.0.Final 2025-11-08 12:14:16 +01:00
Juergen Hoeller 73dfd08526 Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java
#	spring-core/src/main/java/org/springframework/core/BridgeMethodResolver.java
2025-11-08 10:03:18 +01:00
Sébastien Deleuze d9580fd436 Upgrade to Reactor 2025.0.0
Closes gh-35779
2025-11-08 08:28:42 +01:00
Sam Brannen 386c6cafc9 Fix typo in test 2025-11-07 16:13:16 +01:00
Brian Clozel 1bf8756f20 Add integration tests for validateMultiReleaseJar task
This commit also renames the "validateJar" task to
"validateMultiReleaseJar".

Closes gh-35768
2025-11-07 15:20:27 +01:00
Brian Clozel 06ae7fb2b5 Add jar validation and fix multi-release jar
See gh-35768

Signed-off-by: Clayton Walker <clayton.m.walker@gmail.com>
2025-11-07 15:20:27 +01:00
Brian Clozel 21d3b2d179 Merge branch '6.2.x' 2025-11-07 14:03:40 +01:00
Sam Brannen a0baeae9cf Fix port handling in HtmlUnitRequestBuilder
Prior to this commit, HtmlUnitRequestBuilder set the server port in the
MockHttpServletRequest to -1 if the URL did not contain an explicit
port. However, that can lead to errors in consumers of the request that
do not expect an invalid port number.

In addition, HtmlUnitRequestBuilder always set the remote port in the
MockHttpServletRequest to the value of the server port, which does not
make sense, since the remote port of the client has nothing to do with
the port on the server.

To address those issues, this commit revises HtmlUnitRequestBuilder so
that it:

- Does not set the server and local ports if the explicit or derived
  default value is -1.
- Consistently sets the server and local ports to the same valid value.
- Does not set the remote port.

Closes gh-35709
2025-11-06 15:03:41 +01:00
rstoyanchev 115dee9be1 Fix failing test
See gh-35707
2025-11-06 13:18:41 +00:00
rstoyanchev 09105eb7b2 Option to supply client builder in HttpServiceGroupConfigurer
Closes gh-35707
2025-11-06 11:58:37 +00:00
rstoyanchev 6dd40a0252 Refactoring in HttpServiceProxyRegistryFactoryBean
See gh-35707
2025-11-06 11:58:37 +00:00
Juergen Hoeller f6a3346e3f Polishing 2025-11-06 10:50:53 +01:00
Juergen Hoeller 247d2e3e36 Merge branch '6.2.x' 2025-11-06 10:43:55 +01:00
Juergen Hoeller 49237fceae Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
2025-11-05 19:33:48 +01:00
Brian Clozel 783299d24e Merge branch '6.2.x' 2025-11-05 18:36:15 +01:00
Brian Clozel 9a54fac998 Merge branch '6.2.x' 2025-11-05 15:18:10 +01:00
Sam Brannen 94d7aa2844 Suppress deprecation warnings 2025-11-05 14:55:07 +01:00
Sam Brannen 934394eb2a Document AOT workaround for @⁠PersistenceContext & @⁠PersistenceUnit in tests
Although @⁠PersistenceContext and @⁠PersistenceUnit are still not
supported in tests running in AOT mode, as of Spring Framework 7.0,
developers can inject an EntityManager or EntityManagerFactory into
tests using @⁠Autowired instead of @⁠PersistenceContext and
@⁠PersistenceUnit, respectively.

See commit 096303c477
See gh-33414
Closes gh-31442
2025-11-05 14:30:41 +01:00
rstoyanchev 798931eea8 Merge branch '6.2.x' 2025-11-05 12:24:15 +00:00
rstoyanchev b128f59714 Expose handler to ApiVersionDeprecationHandler implementations
Closes gh-35750
2025-11-05 12:23:59 +00:00
rstoyanchev cd67010518 Update Principal check in TransportHandlingSockJsService
Closes gh-35753
2025-11-05 12:23:59 +00:00
Juergen Hoeller 585b4e08e8 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessor.java
#	spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceManagedTypesBeanRegistrationAotProcessorTests.java
2025-11-05 12:54:30 +01:00
Sébastien Deleuze e5fccd1fbb Upgrade nullability plugin to 0.0.8
Closes gh-35751
2025-11-05 11:07:53 +01:00
rstoyanchev 3b0cc2821f Restore section id's in RestTestClient docs
Recent commit a23c37 changed those due to a change in the structure,
but there is no need, and it is better to not break existing links.

See gh-35701
2025-11-05 10:06:06 +00:00
rstoyanchev 02e928e4e3 Docs for the WebTestClient AssertJ integration
Closes gh-35737
2025-11-05 10:06:06 +00:00
rstoyanchev 7445f542f4 AssertJ support for WebTestClient
Closes gh-35737
2025-11-05 10:06:06 +00:00
rstoyanchev cd8690254b Polishing in RestTestClient AssertJ support
See gh-35701
2025-11-05 10:06:05 +00:00
rstoyanchev 125002844e Add JsonConverterDelegate
The JsonConverterDelegate interface replaces usages of
HttpMessageContentConverter to provides the flexibility to use either
message converters or WebFlux codecs.

HttpMessageContentConverter is deprecated, and replaced with a package
private copy (DefaultJsonConverterDelegate) in the
org.springframework.test.json package that is accessible through
a static method on JsonConverterDelegate.

See gh-35737
2025-11-05 10:04:56 +00:00
Brian Clozel 5f895d7b1f Merge branch '6.2.x' 2025-11-05 10:51:54 +01:00
Sébastien Deleuze 5e213b2407 Upgrade nullability plugin to 0.0.7
Closes gh-35751
2025-11-04 14:19:43 +01:00
Sam Brannen b019ebee6e Document that @⁠MockitoSpyBean cannot spy on a scoped proxy
See gh-35722
2025-11-04 13:42:22 +01:00
Sam Brannen c0c94d5d86 Reject attempt to use @⁠MockitoSpyBean with a scoped proxy
Prior to this commit, an attempt to use @⁠MockitoSpyBean to spy on a
scoped proxy configured with
@⁠Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) resulted in an
exception thrown by Mockito when the spy was stubbed. The exception
message stated "Failed to unwrap proxied object" but did not provide
any further insight or context for the user.

The reason is that ScopedProxyFactoryBean is used to create such a
scoped proxy, which uses a SimpleBeanTargetSource, which is not a
static TargetSource. Consequently,
SpringMockResolver.getUltimateTargetObject(Object) is not able to
unwrap the proxy.

In order to improve diagnostics for users, this commit eagerly detects
an attempt to spy on a scoped proxy and throws an exception with a
meaningful message. The following is an example, trimmed stack trace
from the test suite.

org.springframework.beans.factory.BeanCreationException:
  Error creating bean with name 'myScopedProxy': Post-processing of
  FactoryBean's singleton object failed
  ...
Caused by: java.lang.IllegalStateException:
  @⁠MockitoSpyBean cannot be applied to bean 'myScopedProxy', because
  it is a Spring AOP proxy with a non-static TargetSource. Perhaps you
  have attempted to spy on a scoped proxy, which is not supported.
    at ...MockitoSpyBeanOverrideHandler.createSpy(MockitoSpyBeanOverrideHandler.java:78)

Closes gh-35722
2025-11-04 13:27:05 +01:00
Brian Clozel ad22a99993 Merge branch '6.2.x' 2025-11-03 17:09:57 +01:00
Brian Clozel e6a076017b Configure custom Kotlin Serialization converter
Prior to this commit, `HttpMessageConverters` would consider the Kotlin
Serialization JSON converter as an alternative to the Jackson variant.
As seen in related issues, this converter is more commonly used for
annotated classes specifically and applications often rely on Jackson
acting as a fallback for types not supported by Kotlin Serialization.

This commit enables applications to configure such a converter on
`HttpMessageConverters` and order it ahead of of the JSON one.

Closes gh-35733
2025-11-03 14:33:12 +01:00
Sam Brannen 1fc446b3fc Provide AOT support for @⁠Nested classes in a @⁠ParameterizedClass
This commit adds AOT support for discovering @⁠Nested test classes
within a @⁠ClassTemplate test class, which includes
@⁠ParameterizedClass test classes.

Closes gh-35744
2025-11-03 12:25:37 +01:00
Sam Brannen 096303c477 Use @⁠Autowired EntityManager in Jupiter JPA tests
Switching from @⁠PersistenceContext to @⁠Autowired for dependency
injection in tests allows such tests to participate in AOT processing.

Note, however, that we still have TestNG-based tests that use
@⁠PersistenceContext — for example, AbstractEjbTxDaoTestNGTests.

See gh-29122
See gh-31442
See gh-33414
2025-11-03 12:06:57 +01:00
Sam Brannen 2f47efe2d3 Polishing 2025-11-03 12:05:34 +01:00
Sébastien Deleuze 6e7957fc22 Merge branch '6.2.x' 2025-11-03 11:15:49 +01:00
rstoyanchev 1ee05cc180 Update contribution
Closes gh-35698
2025-11-03 09:51:25 +00:00
Thomas Recloux 8e046b8a3c Clone RestTestClientBuilder in mutate()
See gh-35698

Signed-off-by: Thomas Recloux <trecloux@purse.eu>
2025-11-03 09:32:19 +00:00
rstoyanchev 183a9466c5 Add dedicated ApiVersionResolver implementations
Closes gh-35747
2025-11-03 09:19:38 +00:00
Juergen Hoeller 29a76a6c70 Merge branch '6.2.x'
# Conflicts:
#	spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpResponseWrapper.java
2025-11-02 20:42:43 +01:00
Juergen Hoeller 2b526efe65 Polishing 2025-11-02 17:38:50 +01:00
Juergen Hoeller a8410aa601 Merge branch '6.2.x'
# Conflicts:
#	spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java
#	spring-jdbc/src/test/java/org/springframework/jdbc/datasource/DataSourceTransactionManagerTests.java
2025-11-02 17:37:13 +01:00
Sam Brannen 81d69216b1 Rename to MockMvcRestTestClientTests and remove use of SpringExtension
The MockMvcClientHttpRequestFactoryTests variant for RestTestClient was
copied from MockMvcClientHttpRequestFactoryTests which actually uses
MockMvcClientHttpRequestFactory. In addition,
MockMvcClientHttpRequestFactoryTests unnecessarily used the
SpringExtension.

This commit therefore renames the class to MockMvcRestTestClientTests
and removes the use of the SpringExtension.

See gh-29122
2025-11-02 16:47:38 +01:00
Sam Brannen 80b7a34942 Merge branch '6.2.x' 2025-11-02 16:24:42 +01:00
Sam Brannen 9c93ece790 Merge branch '6.2.x' 2025-11-01 14:46:44 +01:00
Sam Brannen 205f3e392d Clean up warnings in tests 2025-11-01 14:38:39 +01:00
Sam Brannen 960df8e7a1 Merge branch '6.2.x' 2025-11-01 14:34:00 +01:00
Juergen Hoeller 0912497e70 Merge branch '6.2.x' 2025-11-01 12:53:27 +01:00
Sam Brannen 324b254849 Upgrade to JUnit 6.0.1 and prevent AOT scanning failure for JUnit 4 tests
This commit upgrades our test suite to use JUnit 6.0.1 and removes the
systemProperty("junit.platform.discovery.issue.severity.critical", "WARNING")
configuration from spring-test.gradle, so that all discovery issues will
fail the build for the spring-test module as well.

In addition, this commit prevents potential AOT test scanning failures
for JUnit 4 tests by setting the
"junit.vintage.discovery.issue.reporting.enabled" configuration
parameter to "false" in TestClassScanner.

See https://github.com/junit-team/junit-framework/issues/5030
Closes gh-35740
2025-11-01 12:28:59 +01:00
Sam Brannen f2cfc692cf Merge branch '6.2.x' 2025-11-01 11:10:34 +01:00
Brian Clozel af026c0373 Review HttpMessageConverters semantics in Builder
Prior to this commit, the `HttpMessageConverters` builder API had
methods like "jsonMessageConverter" for configuring a specific converter
for JSON support. This converter would be always configured at a given
position, even if default converters registration is not requested.
On the other hand, `customMessageConverter` would add any converter
ahead of the list, in all cases. This difference was not conveyed as it
should by the API.

This commit makes the following changes:

* builder methods are renamed to `withJsonConverter` and variants, to
  better convey the fact that those are replacing the default converter
  for a given format.
* `customMessageConverter` is renamed to `addCustomConverter` to better
  reflect the additive aspect.
* the JavaDoc has been updated accordingly
* `withJsonConverter` and others are now only effective if the default
  registration of auto-detected converters is requested. This better
  aligns with the behavior in the reactive codecs configuration

Closes gh-35704
2025-10-31 17:18:28 +01:00
Stéphane Nicoll 03c5ea25f5 Merge branch '6.2.x' 2025-10-31 15:35:41 +01:00
Sébastien Deleuze ce050f152e Upgrade OkHttp to 5.3.0
Closes gh-35729
2025-10-31 06:54:24 +01:00
Juergen Hoeller b2b526162f Polishing 2025-10-30 21:05:47 +01:00
Juergen Hoeller d7acdc54b4 Upgrade to Hibernate Validator 9.1.0.CR1 2025-10-30 21:05:39 +01:00
Sébastien Deleuze a705c6f32a Merge branch '6.2.x' 2025-10-30 19:42:45 +01:00
rstoyanchev a23c3775a8 Docs for the RestTestClient AssertJ integration
Closes gh-35701
2025-10-30 17:34:00 +00:00
Juergen Hoeller d63f1a8bea Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-10-30 17:32:16 +01:00
Sam Brannen 00e1429378 Polish SQLErrorCodeSQLExceptionTranslatorTests 2025-10-30 16:13:38 +01:00
Sam Brannen 2d3c2e3feb Revise contribution
See gh-35380
2025-10-30 16:13:38 +01:00
Dmytro Nosan a41af448ec Ensure SingletonSupplier is singleton even if singletonInstance is null
Previously, SingletonSupplier stored "null" in singletonInstance when
the supplied instance was "null". On subsequent get() calls, this was
treated as "uninitialized" and triggered another attempt to obtain an
instance from the Supplier.

This commit ensures that a "null" returned from the instanceSupplier or
defaultSupplier is handled correctly, so that subsequent calls to get()
return "null" consistently instead of repeatedly invoking the Supplier.

Closes gh-35380

Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
2025-10-30 16:13:13 +01:00
Sébastien Deleuze 7509e257d1 Remove outdated Portlet mentions
Closes gh-35726
2025-10-30 16:02:15 +01:00
Juergen Hoeller e6037a739e Upgrade to Groovy 5.0.2, Tomcat 11.0.13, Jetty 12.1.3, Checkstyle 12.1.1 2025-10-30 15:33:15 +01:00
Juergen Hoeller 34562d3145 Merge branch '6.2.x' 2025-10-30 15:32:36 +01:00
Sébastien Deleuze aeed3c963b Move the "Groovy Bean Definition DSL" section
This commit moves the "Groovy Bean Definition DSL"
section to the Groovy page

Closes gh-35721
2025-10-30 15:06:09 +01:00
Sébastien Deleuze 4880ed5c33 Deprecate the lang XML namespace
And remove the related reference documentation.

Closes gh-35719
2025-10-30 15:03:16 +01:00
Sébastien Deleuze b1cd508016 Deprecate the BeanShell scripting support
Closes gh-35720
2025-10-30 15:03:16 +01:00
Sam Brannen d33f2c6f73 Fix Javadoc links
See gh-35697
2025-10-30 14:43:29 +01:00
rstoyanchev a8349e1c5c AssertJ support for RestTestClient
See gh-35701
2025-10-30 13:30:46 +00:00
Sam Brannen 41ae13df5d Use test-method scoped ExtensionContext in the SpringExtension
As of Spring Framework 6.2.13, we support JUnit Jupiter 5.12's
ExtensionContextScope.TEST_METHOD behavior in the SpringExtension and
the BeanOverrideTestExecutionListener; however, users can only benefit
from that if they explicitly set the following configuration parameter
for their entire test suite, which may have adverse effects on other
third-party JUnit Jupiter extensions.

junit.jupiter.extensions.testinstantiation.extensioncontextscope.default=test_method

For Spring Framework 7.0, in order to support dependency injection into
test class constructors and fields in @⁠Nested test class hierarchies
from the same ApplicationContext that is already used to perform
dependency injection into lifecycle and test methods (@⁠BeforeEach,
@⁠AfterEach, @⁠Test, etc.), we have decided to configure the
SpringExtension to use ExtensionContextScope.TEST_METHOD by default. In
addition, we have decided to provide a mechanism for users to switch
back to the legacy "test-class scoped ExtensionContext" behavior in
case third-party TestExecutionListener implementations are not yet
compatible with test-method scoped ExtensionContext and TestContext
semantics.

This commit achieves the above goals as follows.

- A new @⁠SpringExtensionConfig annotation has been introduced, which
  allows developers to configure the effective ExtensionContext scope
  used by the SpringExtension.

- The SpringExtension now overrides
  getTestInstantiationExtensionContextScope() to return
  ExtensionContextScope.TEST_METHOD.

- The postProcessTestInstance() and resolveParameter() methods in the
  SpringExtension now find the properly scoped ExtensionContext for the
  supplied test class, based on whether the @⁠Nested test class
  hierarchy is annotated with
  @⁠SpringExtensionConfig(useTestClassScopedExtensionContext = true).

See gh-35680
See gh-35716
Closes gh-35697
2025-10-30 13:54:16 +01:00
rstoyanchev b5557160e0 Merge branch '6.2.x' 2025-10-30 12:24:39 +00:00
Sam Brannen 61453bce6c Merge branch '6.2.x' 2025-10-30 11:25:55 +01:00
Sébastien Deleuze 9f9f0a7014 Polish suspending functions support in RSocketServiceMethod
Closes gh-35473
2025-10-30 10:51:58 +01:00
Dmitry Sulman 3190269567 Support suspending functions in RSocketServiceMethod
See gh-35473
Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
2025-10-30 10:51:27 +01:00
Sébastien Deleuze 0bcff38f8e Polishing
Closes gh-34372
2025-10-29 19:25:30 +01:00
Yasumasa Suenaga 706ea2c213 Fix potential CRaC hangup after restoring
See gh-34372
Signed-off-by: Yasumasa Suenaga <yasuenag@gmail.com>
2025-10-29 19:25:22 +01:00
Sébastien Deleuze 9a10b04fe0 Upgrade to Kotlin 2.2.21
Closes gh-35714
2025-10-29 17:09:58 +01:00
Sam Brannen 9c0f714639 Upgrade to Gradle 9.2
This commit upgrades the build to use Gradle 9.2 and reinstates the use
of the Groovy safe-navigation operator (?.) in framework-api.gradle.

See https://github.com/gradle/gradle/issues/35049
See d038269ec3
Closes gh-35713
2025-10-29 17:06:29 +01:00
rstoyanchev 0319fe9211 Deprecate Hamcrest use in WebTestClient
Closes gh-35703
2025-10-29 09:50:36 +00:00
rstoyanchev b4c6300ac6 Remove Hamcrest use from RestTestClient
Closes gh-35702
2025-10-29 09:50:36 +00:00
Juergen Hoeller 92a186b44b Merge branch '6.2.x' 2025-10-28 20:39:56 +01:00
Sébastien Deleuze 830f846766 Merge branch '6.2.x' 2025-10-28 15:39:02 +01:00
Sébastien Deleuze 694224f1a6 Remove outdated Spring version mentions
Close gh-35696
2025-10-28 13:58:09 +01:00
rstoyanchev f07873c966 Merge branch '6.2.x' 2025-10-28 12:07:46 +00:00
Sébastien Deleuze 6ac13d16d8 Relax BeanRegistrar checks on bean definition attributes
This commit allows legit usage of AutoProxyUtils bean definition
attributes with BeanRegistrar.

Closes gh-35645
2025-10-28 12:17:09 +01:00
Sam Brannen 179c63a7c9 Introduce EMPTY_ANNOTATION_ARRAY in ParameterResolutionDelegate 2025-10-28 12:16:11 +01:00
Sébastien Deleuze 7e671abb9f Polish MyBeanRegistrar Kotlin code sample 2025-10-28 10:05:24 +01:00
Sébastien Deleuze 618bce3bd8 Adapt MyBeanRegistrar Kotlin code sample
This commit adapts the MyBeanRegistrar Kotlin code sample to use a
lambda supplier instead of a callable reference since this capability
has been removed.

See gh-35549
Closes gh-35694
2025-10-28 09:51:22 +01:00
Sébastien Deleuze 4356fc11e1 Revert "Add support for callable references to BeanRegistrarDsl"
This reverts commit aa9ab8e545.

See gh-35694
2025-10-28 09:40:22 +01:00
Sébastien Deleuze 8d951c569b Document BeanRegistrarDsl with RouterFunctionDsl
Closes gh-35549
2025-10-27 14:07:43 +01:00
Sam Brannen 65daea1e2a Polish tests for the SpringExtension 2025-10-27 12:18:36 +01:00
Sébastien Deleuze 1ea043db28 Document automatic context propagation
Closes gh-35689
2025-10-27 11:10:53 +01:00
Sam Brannen 24b50650d7 Suppress warnings 2025-10-26 16:06:08 +01:00
Sam Brannen 11587d51b2 Merge branch '6.2.x' 2025-10-26 15:23:39 +01:00
rstoyanchev f0a61cc9c6 Fix test failure caused by previous commit
See gh-35675
2025-10-24 13:18:40 +01:00
rstoyanchev a982c9b481 ObjectUtils uses HexFormat to format byte[]
Also remove equivalent, applied temporarily in FieldError in 6.2.x.

Closes gh-35675
2025-10-24 13:02:57 +01:00
rstoyanchev af86b30aa7 Merge branch '6.2.x' 2025-10-24 13:02:40 +01:00
Sam Brannen c42020e3a7 Merge branch '6.2.x' 2025-10-24 13:57:51 +02:00
rstoyanchev 9331e1e86c Allow Protobuf codec extensions
Closes gh-35403
2025-10-23 12:16:52 +01:00
rstoyanchev 6ebb2071f5 Allow to set MimeType's in ProtobufCodecSupport
See gh-35403
2025-10-23 12:16:52 +01:00
rstoyanchev 754372a1f6 Allow ProtobufHttpMessageConverter extensions
Make ProtobufFormatDelegate protected and visible to subclasses.
Expose constructor that allows passing the delegate in.

See gh-35403
2025-10-23 12:16:52 +01:00
rstoyanchev 87607cccff Polishing in Protobuf support
See gh-35403
2025-10-23 12:16:52 +01:00
Sam Brannen 7c83892b9b Merge branch '6.2.x' 2025-10-22 19:16:07 +02:00
Sam Brannen 5f5b19a898 Merge branch '6.2.x' 2025-10-22 18:59:57 +02:00
Sam Brannen fd6b18a07a Merge branch '6.2.x' 2025-10-22 17:09:38 +02:00
Vedran Pavic c5ec169c83 Update JdkClientHttpRequest javadoc
This commit updates `JdkClientHttpRequest.TimeoutHandler` javadoc to
reference up-to-date JDK issue that tracks improvements to HTTP client's
request timeout handling.

Closes gh-35581

Signed-off-by: Vedran Pavic <vedran@vedranpavic.com>
2025-10-22 15:39:43 +02:00
Brian Clozel 2f66c07b0d Merge branch '6.2.x' 2025-10-22 12:31:35 +02:00
Sébastien Deleuze dce7518be3 Upgrade to Jackson 3.0.1
Closes gh-35677
2025-10-22 08:32:25 +02:00
Brian Clozel 914f83f4a6 Improve RestTemplate to RestClient migration guide
This commit improve the reference documentation in order to:

* highlight the deprecation status of `RestTemplate`
* improve the migration guide for `RestClient`, better explaining
  possible behavior differences and a migration strategy.

Closes gh-35620
2025-10-21 21:54:48 +02:00
Sam Brannen e937d8ee8a Remove reference to @⁠javax.inject.Inject on main 2025-10-21 18:02:12 +02:00
Sam Brannen bda8f20b0b Merge branch '6.2.x' 2025-10-21 17:43:10 +02:00
Sam Brannen 3c14b42f82 Merge branch '6.2.x' 2025-10-21 16:32:00 +02:00
Sam Brannen 711df0259b Merge branch '6.2.x' 2025-10-21 15:38:48 +02:00
Brian Clozel 5923d36de3 Merge branch '6.2.x' 2025-10-21 13:50:25 +02:00
Sébastien Deleuze 3bedf42fbc Fix Jetty multipart client support with Java 25
Closes gh-35531
2025-10-21 12:46:17 +02:00
Sébastien Deleuze 79795c8e09 Avoid compilation error on WebTestClient without Hamcrest
This commit removes JSpecify (TYPE_USE) annotations on
org.hamcrest.Matcher parameters to prevent a related
"Cannot attach type annotations" error when Hamcrest
(optional dependency) is not in the classpath with Java > 22.

Closes gh-35666
2025-10-21 12:18:10 +02:00
Juergen Hoeller 83edf6a4aa Adapt test for MockServletContext version
See gh-35671
2025-10-21 01:07:03 +02:00
Juergen Hoeller 687fc935a8 Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java
#	spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java
#	spring-web/src/testFixtures/java/org/springframework/web/testfixture/servlet/MockServletContext.java
2025-10-21 01:04:38 +02:00
Juergen Hoeller aa625f0ba9 Consistently declare Servlet mock classes with Servlet 6.1 baseline
Closes gh-35671
2025-10-21 00:43:28 +02:00
Juergen Hoeller 7ca2a5dec5 Early support for Jakarta Servlet 6.2 and Jakarta Activation 2.2
Closes gh-35670
2025-10-21 00:42:03 +02:00
Sébastien Deleuze 29d4a91903 Comment broken Jakarta Javadoc URL 2025-10-20 17:39:00 +02:00
Sébastien Deleuze 5fd3c9c449 Fix @Import with multiple bean registrars
This commit uses a MultiValueMap instead of a Map to store bean
registrars, allowing to support multiple bean registrars imported by
the same configuration class.

Closes gh-35653
2025-10-20 17:36:51 +02:00
wakingrufus b65390828e Add a test for multiple bean registrars
This commit add a test for multiple bean registrars imported by the same
configuration class.

See gh-35653
Signed-off-by: wakingrufus <wakingrufus@gmail.com>
2025-10-20 17:36:51 +02:00
Brian Clozel cab46c74d5 Downgrade to JSONassert 1.5.x
Closes gh-34901
2025-10-20 17:14:45 +02:00
Sébastien Deleuze baaddae38e Convert PropagationContextElement to a Java class
In order to avoid having Java types depending on Kotlin types
which breaks the compilation in Eclipse IDE.

Closes gh-35661
2025-10-20 16:40:31 +02:00
Brian Clozel 6d824586bb Polishing contribution
Fixes gh-35659
2025-10-20 15:32:36 +02:00
Damian Malczewski 8a6576eace Make HttpStatus.resolve return non-deprecated one
In previous versions, HttpStatus.resolve (or valueOf) always returned
non-deprecated HTTP status for given code. This was ensured implicitly,
by placing non-deprecated enum entries before their respective
deprecations. This was not ensured for 413 Content Too Large.

See gh-35659

Signed-off-by: Damian Malczewski <damian.m.malczewski@gmail.com>
2025-10-20 15:32:19 +02:00
Brian Clozel 5accc21223 Clean HTTP response headers after decompression in JDK client
Prior to this commit, gh-35225 introduced HTTP response body
decompression support for "gzip" and "deflate" encodings for the
`JdkClientHttpRequestFactory`.

While body decompression works, the client keeps the "Content-Encoding"
and "Content-Length" response headers intact, which misleads further
response handling: the body size has changed and it is not compressed
anymore.

This commit ensures that the relevant response headers are removed from
the HTTP response after decompression.

Fixes gh-35668
2025-10-20 11:38:25 +02:00
Juergen Hoeller b85993c7cb Add test for HibernatePersistenceConfiguration
See gh-35662
2025-10-19 10:45:57 +02:00
Juergen Hoeller 228662ad9f Derive StatelessSession from transactional Session on Hibernate 7.2
Closes gh-35664
See gh-7184
2025-10-19 10:45:43 +02:00
Juergen Hoeller c063249bd4 Consistent support for JPA 3.2 transaction timeout
Closes gh-35663
2025-10-18 15:44:41 +02:00
Juergen Hoeller b261b74793 Merge branch '6.2.x'
# Conflicts:
#	spring-aop/src/main/java/org/springframework/aop/framework/CoroutinesUtils.java
#	spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/DefaultPersistenceUnitManager.java
#	spring-orm/src/main/java/org/springframework/orm/jpa/persistenceunit/MutablePersistenceUnitInfo.java
#	spring-orm/src/test/java/org/springframework/orm/jpa/persistenceunit/PersistenceXmlParsingTests.java
2025-10-18 15:32:19 +02:00
Juergen Hoeller beb224e3f9 Add support for JPA 3.2 PersistenceConfiguration
See gh-35662
2025-10-18 15:05:38 +02:00
Sam Brannen cfb268f6de Suppress warning in SmartPersistenceUnitInfoInvocationHandler 2025-10-18 13:58:11 +02:00
Sam Brannen 0fbebd856f Revise contribution
See gh-35660
2025-10-18 13:50:22 +02:00
Kamil Krzywanski 948367092c Use empty array constants instead of repeatedly creating new ones
Closes gh-35660

Signed-off-by: Kamil Krzywański <kamilkrzywanski01@gmail.com>
Signed-off-by: Kamil Krzywanski <kamilkrzywanski01@gmail.com>
2025-10-18 13:36:06 +02:00
Sam Brannen 687bc7652d Avoid unnecessary import for SpringExtension's Javadoc 2025-10-18 13:35:54 +02:00
Sébastien Deleuze 16851b5128 Merge branch '6.2.x' 2025-10-17 15:46:36 +02:00
Brian Clozel 44de925c5e Add reflection hints for SpringPersistenceUnitInfo
Fixes gh-35655
2025-10-17 14:34:15 +02:00
Dónal Murtagh 22ecab5aab Fix code snippets in Javadoc for exchangeSuccessfully()
Closes gh-35642

Signed-off-by: Dónal Murtagh <donal.murtagh@clarusonesourcing.com>
2025-10-16 18:44:33 +02:00
Brian Clozel a7c43d90fd Merge branch '6.2.x' 2025-10-16 09:32:41 +02:00
Juergen Hoeller 1c64f867c8 Upgrade to Netty 4.2.7
See gh-35637
2025-10-15 19:44:18 +02:00
Juergen Hoeller 527643f142 Merge branch '6.2.x' 2025-10-15 19:41:20 +02:00
rstoyanchev b9d6a90220 Merge branch '6.2.x' 2025-10-15 16:43:06 +01:00
Sébastien Deleuze b46c41bb3a Add first class ParameterizedTypeReference support to BeanRegistrar
This commit replaces ParameterizedTypeReference and ResolvableType
target type customization with the lambda by directly exposing
ParameterizedTypeReference methods at top level, as generics
variants of the class-based existing ones.

Closes gh-35635
2025-10-15 17:05:11 +02:00
Brian Clozel e6481a011b Deprecate "feed" and "document" view packages
Prior to this commit, Spring Framework would ship several abstract
`*View` implementations for rendering PDF, RSS or XLS documents using
well-known libraries. More recently, supporting libraries evolved a lot
with new versions and forks. Spring Framework is not in a position to
efficiently support all variants within the project.

This commit deprecates the relevant classes. Instead, libraries can
reuse existing code and ship optional support for Spring directly.
Often, updating imports and library usage is enough.
As an alternative, applications can decide to perform rendering
direclty in web handlers.

Closes gh-35451
2025-10-15 16:36:24 +02:00
Juergen Hoeller 2e4ca41382 Add getBeanProvider(ParameterizedTypeReference) overload
Closes gh-31444
2025-10-15 16:10:28 +02:00
Sébastien Deleuze 6503f35404 Upgrade nullability plugin to 0.0.6
Closes gh-35644
2025-10-15 15:55:48 +02:00
Sébastien Deleuze d23757cc1f Upgrade to Dokka 2.1.0
Closes gh-35532
2025-10-15 14:17:51 +02:00
Juergen Hoeller 7dc78a4318 Align default order between @EnableAsync and @EnableResilientMethods
Retries async methods with Future return types in non-reactive path.

Closes gh-35643
2025-10-15 13:52:44 +02:00
rstoyanchev f15c12a190 Merge branch '6.2.x' 2025-10-15 12:37:52 +01:00
rstoyanchev 3607f98240 Refine null handling in UriComponentsBuilder#query
Closes gh-35629
2025-10-15 12:31:08 +01:00
Schäfer, H.H. (Hans Hosea) 649bd3ee2d Do not clear queryParams UriComponentsBuilder#query
See gh-35628

Signed-off-by: Schäfer, H.H. (Hans Hosea) <HansHosea.Schaefer@ing.de>
2025-10-15 12:31:08 +01:00
Sam Brannen 1c2a24a8ed Merge branch '6.2.x' 2025-10-15 12:49:16 +02:00
Sébastien Deleuze 8ec9ab6698 Add builder-based constructors to Jackson 3 infrastructure
This commit also polishes documentation, constructor parameter and
field names.

Closes gh-35597
2025-10-15 11:49:55 +02:00
Sam Brannen 3493fc9324 Merge branch '6.2.x' 2025-10-15 11:30:31 +02:00
Brian Clozel 04ae53d6bb Reinstate JakartaEE javadoc linking 2025-10-15 11:11:49 +02:00
Juergen Hoeller 22cb819a14 Upgrade to Micrometer 1.16.0-RC1
Closes gh-35639
2025-10-14 19:26:06 +02:00
Juergen Hoeller 331f62fd03 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
2025-10-14 19:24:48 +02:00
rstoyanchev a78554eea6 Merge branch '6.2.x' 2025-10-14 16:50:53 +01:00
Sébastien Deleuze 0be22a8d71 Merge branch '6.2.x' 2025-10-14 17:45:22 +02:00
Sébastien Deleuze 3b4d6631c8 Upgrade to Reactor 2025.0.0-RC1
Closes gh-35637
2025-10-14 17:23:37 +02:00
rstoyanchev 9a2bfeae2f AbstractMockHttpServletRequestBuilder exposes HttpHeaders
Closes gh-35576
2025-10-14 16:21:23 +01:00
rstoyanchev 9ed3c034f5 AbstractMockHttpServletRequestBuilder uses HttpHeaders internally
See gh-35576
2025-10-14 16:21:23 +01:00
Juergen Hoeller 001fc8e585 Add early support for JTA 2.1 read-only attribute
Closes gh-35633
2025-10-14 13:25:13 +02:00
rstoyanchev 43c13ca043 Polishing contribution
Closes gh-35348
2025-10-14 11:37:40 +01:00
秦利斌 17cf2ad457 MvcUriComponentsBuilder resolves embedded values
See gh-35348

Signed-off-by: 秦利斌 <68638598+Allan-QLB@users.noreply.github.com>
2025-10-14 11:37:24 +01:00
rstoyanchev 00190a1111 Add exchangeSuccessfully to test clients
Closes gh-35582
2025-10-14 11:37:01 +01:00
Sébastien Deleuze 180ea125d2 Stop using --report-unsupported-elements-at-runtime
This commit stop using the --report-unsupported-elements-at-runtime
deprecated option with GraalVM 25+.

Closes gh-35632
2025-10-14 11:49:34 +02:00
Juergen Hoeller fad2068bcb Merge branch '6.2.x' 2025-10-14 11:30:37 +02:00
Sébastien Deleuze 1f2948f78c Stop using --install-exit-handlers
This commit stop using the --install-exit-handlers deprecated option
which is enabled by default with GraalVM 25+.

Closes gh-35557
2025-10-14 10:44:21 +02:00
Juergen Hoeller e901516732 Make SpringPersistenceUnitInfo public for custom bootstrapping purposes
See gh-35622
2025-10-13 23:24:46 +02:00
Brian Clozel 2f8d52fd47 Merge branch '6.2.x' 2025-10-13 18:46:47 +02:00
Brian Clozel f9b691cad4 Revert "Enable new build options for GraalVM 25 native image builds"
This reverts commit 9975113879.
2025-10-13 17:37:03 +02:00
Sébastien Deleuze ec77bb0032 Introduce automatic context propagation in Coroutines
Closes gh-35485
2025-10-13 16:14:25 +02:00
Sam Brannen ea27415b7b Merge branch '6.2.x' 2025-10-13 15:12:50 +02:00
Sam Brannen c2ef11e1fc Remove test prefixes and avoid warnings in JDBC and TX tests 2025-10-13 14:48:03 +02:00
Juergen Hoeller d216236aac Revise PersistenceUnitInfo management for compatibility with JPA 3.2/4.0
Closes gh-35622
2025-10-13 14:23:31 +02:00
Juergen Hoeller b4dcb36b21 Align currentStatelessSession() implementation with currentSession()
See gh-7184
2025-10-13 14:17:07 +02:00
Brian Clozel 252bb8dac7 Stop building against Jakarta Javadoc
The javadoc is missing right now, temporarily disabling linking to the
Jakarta Javadoc.
2025-10-13 13:48:35 +02:00
Brian Clozel 9975113879 Enable new build options for GraalVM 25 native image builds
Closes gh-35616
2025-10-13 11:02:20 +02:00
Dariusz Jędrzejczyk b2c84ac038 Adapt to Reactor 3.8 JSpecify annotations
Closes gh-35501
Signed-off-by: Dariusz Jędrzejczyk <dariusz.jedrzejczyk@broadcom.com>
2025-10-13 09:01:47 +02:00
Sam Brannen 0389684429 Revise contribution
See gh-35352
2025-10-11 19:37:34 +02:00
yongjunhong 8edc7cd542 Reject effectively private handler methods on CGLIB proxied controllers
This commit rejects the invocation of an effectively private handler
method on a CGLIB proxied controller for both Spring MVC and Spring
WebFlux.

Closes gh-35352

Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
Signed-off-by: Yongjun Hong <kevin0928@naver.com>
Signed-off-by: yongjunhong <yongjunh@apache.org>
2025-10-11 19:27:06 +02:00
Sam Brannen a5d9bd64be Test package pattern support for CandidateComponentsIndex and restructure tests 2025-10-11 17:02:54 +02:00
Sam Brannen 0fc7c41ddc Improve Javadoc for CandidateComponentsIndex 2025-10-11 17:00:12 +02:00
Juergen Hoeller 8f29c71e0c Upgrade to Tomcat 11.0.12, Jetty 12.1.2, Jetty Reactive HttpClient 4.1, Hibernate ORM 7.2.0.CR1, EclipseLink 5.0.0-B11, Checkstyle 12.0 2025-10-11 16:14:09 +02:00
Juergen Hoeller fef5627329 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-core/src/main/java/org/springframework/core/task/SyncTaskExecutor.java
2025-10-11 16:09:47 +02:00
Sam Brannen b727dbb802 Introduce tests for CandidateComponentsIndex.hasScannedPackage()
This indirectly tests the implementation of matchPackage(), which was
fixed in the previous commit.

See gh-35497
See gh-35601
2025-10-11 16:00:38 +02:00
NeatGuyCoding 113b9d131c Fix non-pattern package prefix check in CandidateComponentsIndex
Prior to this commit, the non-pattern package prefix check used
packageName.startsWith(basePackage) which incorrectly treats
"com.example2.foo" as a subpackage of "com.example".

Closes gh-35601

Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-10-11 15:45:14 +02:00
Sam Brannen 51d6e8beb0 Polishing 2025-10-11 15:19:28 +02:00
Sam Brannen 5096db4e60 Polishing 2025-10-11 13:45:53 +02:00
Sam Brannen 3eef39e6ab Polish contribution
See gh-35603
2025-10-11 13:29:05 +02:00
Simone Conte 87a7507e3a Introduce queryParamPredicate in AbstractRequestLoggingFilter
Closes gh-35603

Signed-off-by: Simone Conte <conte@adobe.com>
2025-10-11 13:29:05 +02:00
Juergen Hoeller 080bca0b23 Deprecate TransactionCallbackWithoutResult
Closes gh-35606
2025-10-11 13:25:40 +02:00
Juergen Hoeller 8b36736344 Add concurrency throttle and flexible task callback to SyncTaskExecutor
Closes gh-35460
2025-10-11 13:25:30 +02:00
Sam Brannen 26c57cecd2 Fix copy-n-paste error in Javadoc 2025-10-10 18:45:32 +02:00
Sam Brannen 19b4021d26 Polish tests 2025-10-10 18:45:20 +02:00
rstoyanchev e21fa380b3 Merge branch '6.2.x' 2025-10-10 17:25:22 +01:00
Juergen Hoeller 18c93a071c Remove deprecated method (plus JSpecify alignment)
See gh-35594
2025-10-10 17:08:19 +02:00
Juergen Hoeller 8792b395a7 Merge branch '6.2.x' 2025-10-10 17:04:47 +02:00
Sébastien Deleuze 3819e2dc4c Refine StringUtils#splitArrayElementsIntoProperties nullability
Closes gh-35595
2025-10-10 11:22:08 +02:00
Juergen Hoeller edc14c2e15 Merge branch '6.2.x'
# Conflicts:
#	spring-context-indexer/src/main/java/org/springframework/context/index/processor/StandardStereotypesProvider.java
#	spring-context/src/main/java/org/springframework/context/annotation/ClassPathScanningCandidateComponentProvider.java
#	spring-context/src/test/java/org/springframework/context/annotation/ClassPathBeanDefinitionScannerTests.java
2025-10-09 20:37:49 +02:00
Juergen Hoeller 7bc2a7f3f2 Add support for programmatic CandidateComponentsIndex setup
Closes gh-35497
See gh-35472
2025-10-09 20:11:11 +02:00
Sam Brannen 97ae5fde7c Match against exception causes in @⁠Retryable and RetryPolicy
Prior to this commit, our @⁠Retryable support as well as a RetryPolicy
created by the RetryPolicy.Builder only matched against top-level
exceptions when filtering included/excluded exceptions thrown by a
@⁠Retryable method or Retryable operation.

With this commit, we now match against not only top-level exceptions
but also nested causes within those top-level exceptions. This is
achieved via the new ExceptionTypeFilter.match(Throwable, boolean)
support.

See gh-35592
Closes gh-35583
2025-10-09 17:55:03 +02:00
Sam Brannen 58940794cf Polish resilience features 2025-10-09 17:45:17 +02:00
Sam Brannen 670effa02b Support matching against exception causes in ExceptionTypeFilter
Prior to this commit, ExceptionTypeFilter only provided support for
filtering based on exact matches against exception types; however, some
use cases require that filtering be applied to nested causes in a given
exception. For example, this functionality is a prerequisite for
gh-35583.

This commit introduces a new match(Throwable, boolean) method in
ExceptionTypeFilter, where the boolean flag enables matching against
nested exceptions.

See gh-35583
Closes gh-35592
2025-10-09 14:19:03 +02:00
Sam Brannen 6bc3ce4829 Polishing 2025-10-08 15:48:20 +02:00
Sam Brannen d404fdafa0 Prevent ReactorResourceFactory from participating in pause scenarios
Prior to this commit, ReactorResourceFactory was not restarted properly
when the ApplicationContext was resumed by the TestContext Framework
after a context pause. The reason is that the managed LoopResources
were disposed when ConfigurableApplicationContext.pause() was invoked
and reacquired when ConfigurableApplicationContext.restart() was
invoked.

To address that, this commit overrides isPauseable() in
ReactorResourceFactory to return false, thereby avoiding participation
in pause scenarios.

Closes gh-35585
2025-10-08 15:48:20 +02:00
rstoyanchev e0b8cb4fe2 Allow setting ApiVersionInserter to null
It should be possible to reset this, e.g. after call to mutate
a client or a test client.
2025-10-08 13:52:14 +01:00
rstoyanchev 03e379b070 Improve Javadoc for use of ApiVersionInserter
Closes gh-35565
2025-10-08 12:24:37 +01:00
rstoyanchev 00543becf8 Allow explicitly sending no API version
Closes gh-35566
2025-10-08 12:24:37 +01:00
Sébastien Deleuze 891c3e3a1f Fix FilterProvider handling in AbstractJacksonEncoder
Closes gh-35575
2025-10-08 11:29:02 +02:00
rstoyanchev e11cb2d856 Improve converter config in RestClient.Builder
Internally maintain a chain of HttpMessageConverters.ClientBuilder
consumers in addition to the List of converters.

List based methods apply to the list.
HttpMessageConverters based methods are composed into a Consumer.

At build() time prepare a single HttpMessageConverters.ClientBuilder.
Insert list based converters first.
Apply HttpMessageConverters consumers after that.

Deprecate both List methods. Eventually, HttpMessageConverters should
be the main mechanism. In the mean time we layer them as described.

Closes gh-35578
2025-10-08 06:34:53 +01:00
rstoyanchev d057eb2e5d Improve converter config in RestTestClient.Builder
Compose consumers and apply them together from the build method
to allow multiple parties to supply consumers that collaborate
on the same HttpMessageConverters.Builder.

See gh-35578
2025-10-08 06:34:53 +01:00
rstoyanchev 451f2b5a90 Polishing in MockMvcClientHttpRequestFactory
Replace anonymous subclass with inner.
Simplify methods to adapt client-server request and response.
2025-10-08 06:34:53 +01:00
Sam Brannen 7e6874ad80 Polish @⁠Autowired section of the reference manual 2025-10-07 17:17:27 +02:00
Sam Brannen 097463e3b7 Remove outdated reference to JSR 305 in the reference documentation
Closes gh-35580
2025-10-07 17:10:40 +02:00
Sam Brannen 30db2e4fb5 Support Bean Overrides for non-singletons
Prior to this commit, the BeanOverrideBeanFactoryPostProcessor rejected
any attempt to override a non-singleton bean; however, due to interest
from the community, we have decided to provide support for overriding
non-singleton beans via the Bean Override mechanism — for example, when
using @⁠MockitoBean, @⁠MockitoSpyBean, and @⁠TestBean.

With this commit, we now support Bean Overrides for non-singletons: for
standard JVM runtimes as well as AOT processing and AOT runtimes. This
commit also documents that non-singletons will effectively be converted
to singletons when overridden and logs a warning similar to the
following.

WARN: BeanOverrideBeanFactoryPostProcessor - Converting 'prototype' scoped bean definition 'myBean' to a singleton.

See gh-33602
See gh-32933
See gh-33800
Closes gh-35574
2025-10-07 15:33:18 +02:00
Sam Brannen ff9a349271 Introduce findAnnotatedBeans(ListableBeanFactory) in ControllerAdviceBean
This commit introduces a new findAnnotatedBeans(ListableBeanFactory)
override for the existing findAnnotatedBeans(ApplicationContext) method.

Closes gh-35571
2025-10-07 12:37:07 +02:00
NeatGuyCoding 6aeb9d16e8 Fix Javadoc link and remove unnecessary semicolon
Closes gh-35573

Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-10-06 16:54:08 +02:00
Sam Brannen c6e5cfe03d Use consistent naming for Bean Override test classes 2025-10-06 15:26:51 +02:00
Juergen Hoeller 3a1a0e6e95 Merge branch '6.2.x' 2025-10-06 14:10:05 +02:00
Wars a32d0b17d1 Remove unused application startup call
AbstractApplicationContext.applicationStartup can only be injected after the instance construction. This metrics point has no practical effect at present and can be removed safely.

Closes gh-35570
Signed-off-by: Wars <wars@wars.cat>
2025-10-06 09:29:29 +02:00
Sébastien Deleuze d6fbe257f5 Upgrade to Jackson 3.0.0
Closes gh-35521
2025-10-05 15:17:59 +02:00
Sam Brannen d81f1a55c2 Test SpEL Map access/indexing support for nonexistent keys
This commit introduces two tests to verify the status quo.

- mapAccessThroughIndexerForNonexistentKey(): demonstrates that map
  access via the built-in support in the Indexer returns `null` for a
  nonexistent key.

- nullAwareMapAccessor(): demonstrates that users can implement and
  register a custom extension of MapAccessor which reports that it can
  read any map (ignoring whether the map actually contains an entry for
  the given key) and returns `null` for a nonexistent key.

See gh-35534
2025-10-04 17:43:47 +02:00
Sam Brannen eb11070c19 Overhaul and simplify SpEL MapAccessTests 2025-10-04 17:41:39 +02:00
Juergen Hoeller 80f1d95404 Upgrade to Hibernate ORM 7.1.2 2025-10-03 18:05:41 +02:00
Juergen Hoeller e2168edc8f No synchronization (and no caching) for SmartFactoryBean invocations
See gh-35545
See gh-35101
2025-10-03 17:56:11 +02:00
Juergen Hoeller 2170b40213 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java
2025-10-03 17:34:42 +02:00
Juergen Hoeller 54b43d4a88 Merge branch '6.2.x'
# Conflicts:
#	spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLExceptionSubclassTranslator.java
#	spring-jdbc/src/main/java/org/springframework/jdbc/support/SQLStateSQLExceptionTranslator.java
2025-10-03 14:54:04 +02:00
Sam Brannen 4e2d5d4d64 Merge branch '6.2.x' 2025-10-03 14:18:24 +02:00
rstoyanchev 8a719117e3 Fix copy-paste error from recent change
See gh-35562
2025-10-03 09:21:55 +01:00
Juergen Hoeller 37319fc367 Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/cglib/core/CodeEmitter.java
2025-10-02 21:56:12 +02:00
Nurlan Turdaliev b4d501f888 Remove redundant object allocation in cglib proxy method calls
* Fixes gh-35542

Signed-off-by: Nurlan Turdaliev <nurlan0000@gmail.com>
2025-10-02 21:22:19 +02:00
rstoyanchev 8631345b71 Refine Jackson 3 vs 2 setup in CodecConfigurer
Closes gh-35562
2025-10-02 17:35:33 +01:00
Juergen Hoeller 1333669e2c Introduce SimpleDestinationResolver as new default for common setups
Closes gh-35456
2025-10-02 18:28:59 +02:00
Sam Brannen c5a79fdf99 Stop using javadoc.io for external Javadoc links
Since our build was failing intermittently, we have decided to stop
using javadoc.io for external Javadoc links for the time being.
2025-10-02 14:24:09 +02:00
Juergen Hoeller 7089bdcc3a Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java
2025-10-02 13:17:45 +02:00
Sam Brannen c08610ee58 Revert nullability changes in reactive transaction support
After further consideration, we have decided to revert the
nullability changes in the reactive TransactionCallback and
TransactionalOperator.

See gh-35561
2025-10-02 12:47:37 +02:00
Sam Brannen 1e83de072c Merge branch '6.2.x' 2025-10-02 11:45:43 +02:00
Sébastien Deleuze 1243f40ee6 Merge branch '6.2.x' 2025-10-02 10:20:09 +02:00
Stéphane Nicoll e91abd442a Simplify MockHttpServletRequestBuilders hierarchy
Closes gh-33231
2025-10-02 09:22:33 +02:00
Brian Clozel d98179e137 Enforce custom string converter in HttpMessageConverters
Prior to this commit, configuring a custom `StringHttpMessageConverter`
would be overwritten when the `registerDefaults()` option is enabled.

Fixes gh-35563
2025-10-01 20:18:39 +02:00
Juergen Hoeller 56b082dec7 Merge branch '6.2.x' 2025-10-01 19:58:49 +02:00
Brian Clozel b59fec21d8 Merge branch '6.2.x' 2025-10-01 19:41:22 +02:00
Sébastien Deleuze acc3783509 Merge branch '6.2.x' 2025-10-01 19:26:06 +02:00
rstoyanchev c765b035e5 Merge branch '6.2.x' 2025-10-01 16:14:13 +01:00
Sam Brannen 563919befd Revise nullability of Transaction[Callback|Operations|Operator]
This commit revises the nullability declarations in TransactionCallback,
TransactionOperations, and TransactionalOperator.

Closes gh-35561
2025-10-01 16:58:33 +02:00
rstoyanchev f071f95899 Merge branch '6.2.x' 2025-10-01 14:46:47 +01:00
Sam Brannen 96e90e10b9 Merge branch '6.2.x' 2025-10-01 13:21:05 +02:00
Sébastien Deleuze 5138305e0b Fix SingletonSupplier.ofNullable(T) nullability
See gh-35559
2025-10-01 12:01:17 +02:00
Sam Brannen 48ec990a17 Fix typos 2025-10-01 11:53:01 +02:00
Sébastien Deleuze 1e3f8651b8 Refine SingletonSupplier<T> static methods nullability
SingletonSupplier<T> supplier-based static methods nullability should
be refined to accept in a flexible way nullable or non-nullable T.

Closes gh-35559
2025-10-01 11:38:33 +02:00
Stéphane Nicoll a2c0e1cec8 Fix typos 2025-10-01 11:23:00 +02:00
Stéphane Nicoll 8cad5711f5 Add Kotlin extensions for RestTestClient
Closes gh-35558
2025-10-01 10:56:34 +02:00
Stéphane Nicoll 741107969a Always invoke ConfigurationBeanNameGenerator
Previously, if a ConfigurationBeanNameGenerator is used to parse
configuration classes, it is not invoked for `Bean` methods that provide
a specific bean name. This doesn't give a chance to an implementation to
tune such a bean, if required.

This commit updates the signature of ConfigurationBeanNameGenerator to
provide the identified bean name on the `@Bean` declaration,if any, and
to always invoke it.

Closes gh-35505
2025-10-01 10:34:38 +02:00
Sam Brannen 969517bce1 Upgrade to JUnit 6.0
Closes gh-35124
2025-09-30 13:27:47 +02:00
Sam Brannen 834755203e Merge branch '6.2.x' 2025-09-30 12:46:33 +02:00
Sam Brannen 2bd6422db9 Update @⁠ConcurrencyLimit documentation
This commit updates the reference manual in order to reflect recent
changes made to @⁠ConcurrencyLimit.

See gh-35461
See gh-35470
See gh-35523
2025-09-29 17:41:59 +02:00
Sam Brannen b9e0a48e95 Revise documentation for @⁠Retryable 2025-09-29 17:38:50 +02:00
Sam Brannen 8dd64602e8 Avoid warnings with AssertJ APIs 2025-09-29 17:11:42 +02:00
Sam Brannen 60673a0e32 Upgrade com.gradleup.shadow plugin to 9.2.2 2025-09-27 17:01:01 +02:00
rstoyanchev 7f03487875 Polishing contribution
Closes gh-35510
2025-09-26 17:44:42 +01:00
KNU-K e4a431e536 Refactor toString method in SockJsFrame
See gh-35510

Signed-off-by: KNU-K <knukang334@gmail.com>
2025-09-26 17:34:09 +01:00
rstoyanchev 2e915a3934 Provide access to API version in controller method
Closes gh-35424
2025-09-26 17:32:38 +01:00
Sam Brannen 7ba736dc06 Stop overriding default methods in TrackingTestNGTestListener
At some point, TestNG started implementing listener methods as interface
default methods, so we no longer need to override those methods with
empty implementations.
2025-09-26 14:56:03 +02:00
Sam Brannen 1b3aeba5ee Merge branch '6.2.x' 2025-09-25 17:55:22 +02:00
rstoyanchev ba0de1edce Merge branch '6.2.x' 2025-09-25 12:22:29 +01:00
Sam Brannen 34be8e266d Revise nullability for Core Retry after upgrade to NullAway 0.12.10
This commit revises the nullability declarations in Retryable,
RetryOperations, and RetryTemplate after the upgrade to NullAway 0.12.10.

See gh-35492
2025-09-25 11:38:33 +02:00
Sam Brannen 5df082132d Polish contribution
See gh-35535
2025-09-25 10:28:00 +02:00
Yanming Zhou 871076ef97 Add serialVersionUID in LinkedCaseInsensitiveMap
Closes gh-35535

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-09-25 10:27:19 +02:00
Manu Sridharan e834a3a80c Nullability fixes for AtomicReference variables
Closes gh-35514
Signed-off-by: Manu Sridharan <msridhar@gmail.com>
2025-09-25 07:39:44 +02:00
Sam Brannen 051adf267f Introduce MapAccessor in SpEL and deprecate existing implementation
Prior to this commit, the MapAccessor for SpEL resided in the
org.springframework.context.expression package in the spring-context
module; however, it arguably should reside in the spring-expression
module so that it can be used whenever SpEL is used (without requiring
spring-context).

This commit therefore officially deprecates the MapAccessor in
spring-context for removal in favor of a new copy of the implementation
in the org.springframework.expression.spel.support package in the
spring-expression module.

Closes gh-35537
2025-09-24 16:52:27 +02:00
Sam Brannen 27b2243b43 Test status quo for canRead() and read() in SpEL MapAccessor
See gh-35534
2025-09-24 16:06:37 +02:00
Brian Clozel 20aac6dd8d Add Gson codecs for WebFlux
This commit adds new `GsonEncoder` and `GsonDecoder` for serializing and
deserializing JSON in a reactive fashion.

Because `Gson` itslef does not support decoding JSON in a non-blocking
way, the `GsonDecoder` does not support decoding to `Flux<*>` types.

Closes gh-27131
2025-09-23 17:09:41 +02:00
Sam Brannen d84bf18408 Upgrade to JUnit 6.0 RC3
See gh-35124
2025-09-23 16:19:54 +02:00
Sébastien Deleuze 7edb0b3397 Upgrade the build to Java 25
See gh-35531
Closes gh-35530
2025-09-23 15:57:21 +02:00
Sébastien Deleuze aa272b4cd9 Upgrade to Dokka 2.1.0-Beta
Required for Java 25 support.

Closes gh-35532
2025-09-23 15:57:21 +02:00
Sébastien Deleuze c79e4e230b Reinstantiate checks for kotlin-reflect
This commit reinstantiates checks for kotlin-reflect (via static final
fields for faster Java code paths and better native code removal) which
were removed as part of gh-34275, which did not consider the
increasingly popular use cases where kotlin-stdlib is present in the
classpath as a transitive dependency in Java applications.

Closes gh-35511
2025-09-22 18:33:38 +02:00
Sébastien Deleuze 7635ac38f6 Use uppercase for classpath-related static final field names
Closes gh-35525
2025-09-22 18:32:14 +02:00
Sam Brannen 5ac3c40689 Prevent empty declaration of @⁠ConcurrencyLimit
As a follow-up to gh-35461 and a comment left on the Spring Blog, we
have decided to prevent empty declarations of @⁠ConcurrencyLimit,
thereby requiring users to explicitly declare the value for the limit.

Closes gh-35523
2025-09-22 18:18:53 +02:00
Sam Brannen 8b254ad25e Improve Javadoc for ConcurrencyThrottleSupport 2025-09-22 18:12:31 +02:00
Sam Brannen 73ad1ebffb Introduce @⁠ConcurrencyLimit(limit) and revise contribution
This commit introduces a new `limit` attribute in @⁠ConcurrencyLimit as
an alias for the existing `value` attribute. This commit also renames
the `valueString` attribute to `limitString`.

See gh-35461
See gh-35470
2025-09-22 16:09:58 +02:00
Hyunsang Han 91f112a918 Add placeholder resolution support for @⁠ConcurrencyLimit
See gh-35461
Closes gh-35470

Signed-off-by: Hyunsang Han <gustkd3@gmail.com>
2025-09-22 15:19:07 +02:00
Sam Brannen 23b8c61b99 Upgrade to ArchUnit 1.4.1 for Java 25 support
https://github.com/TNG/ArchUnit/releases/tag/v1.4.1
2025-09-22 14:37:46 +02:00
Sam Brannen 0c61ac956b Add missing @⁠Override annotations
... and suppress "serial" warnings
2025-09-22 13:20:37 +02:00
rstoyanchev f504d051ab Polishing in HTTP interface clients docs 2025-09-22 11:35:46 +01:00
rstoyanchev e9e19f5ed7 Update references to HTTP service clients in docs
Closes gh-35522
2025-09-22 11:35:46 +01:00
Sébastien Deleuze 79738d921a Upgrade to Jackson 3.0.0-rc10
See gh-35521
2025-09-22 11:16:25 +02:00
Brian Clozel 33897bb398 Merge branch '6.2.x' 2025-09-19 18:09:06 +02:00
Brian Clozel c129e8a599 Merge branch '6.2.x' 2025-09-19 17:51:33 +02:00
Sam Brannen d038269ec3 Upgrade to Gradle 9.1
This commit upgrades the build to use Gradle 9.1.

To achieve that, the following changes were necessary.

- Stop using Groovy safe-navigation operator (?.) in
  framework-api.gradle due to a NullPointerException.

- Switch from the io.github.goooler.shadow plugin to the
  com.gradleup.shadow plugin, since the former is no longer maintained
  and the latter is a fork that replaces it.

Closes gh-35508
2025-09-19 17:40:32 +02:00
Sam Brannen d82a578f31 Merge branch '6.2.x' 2025-09-19 11:24:32 +02:00
Sam Brannen 01c8f04d98 Improve Javadoc for ConfigurableApplicationContext 2025-09-18 18:31:29 +02:00
Sam Brannen cb485b666f Polishing 2025-09-18 18:31:29 +02:00
Sam Brannen abdc3200b2 Restructure and polish the classpath scanning chapter 2025-09-18 18:31:29 +02:00
Sam Brannen dbb9bf939c Revise contribution
See gh-35491
2025-09-18 18:00:11 +02:00
Byeong-Uk Park fe04bfcadb Document placeholder and pattern support for @⁠ComponentScan
- JavaDoc: clarify that basePackages/value resolve ${…} via Environment
  and accept Ant-style package patterns (e.g., com.example.**); note
  patterns don’t apply to basePackageClasses.

- Reference: add “Property placeholders and Ant-style patterns”
  subsection in classpath-scanning.adoc with Java/Kotlin + properties
  examples.

See gh-35288
Closes gh-35491

Signed-off-by: Byeong-Uk Park <114344042+Rockernun@users.noreply.github.com>
2025-09-18 18:00:11 +02:00
Juergen Hoeller 015edb33cd Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-09-17 18:27:04 +02:00
Juergen Hoeller fa5ebbc1a8 Upgrade to Hibernate 7.1.1, Groovy 5.0.1, Commons Pool 2.12.1, SnakeYAML 2.5, Protobuf 4.32.1, ActiveMQ 5.17.7 and Artemis 2.42, EasyMock 5.6, AssertJ 3.27.4, XMLUnit 2.10.4, Dom4J 2.2
Includes downgrade to Log4J 2.25.1 from 3.0.0 beta (for Spring Framework 7.0 RC1)
2025-09-17 17:37:36 +02:00
rstoyanchev 11dd0d6118 Provide access to raw content in RestTestClient
Closes gh-35399
2025-09-17 15:50:59 +01:00
Sébastien Deleuze 23d1b0e881 Polishing 2025-09-17 15:17:23 +02:00
Sébastien Deleuze da0a36bfd6 Upgrade to NullAway 0.12.10 and refine nullability
Closes gh-35492
2025-09-17 15:17:23 +02:00
rstoyanchev 8ac5cdb47e Fix typo
See gh-35494
2025-09-17 11:55:37 +01:00
rstoyanchev c7121d048c Replace X-API-Version with API-Version
Closes gh-35494
2025-09-17 11:48:49 +01:00
Stéphane Nicoll 88812edc35 Merge branch '6.2.x' 2025-09-16 16:11:08 +02:00
Sébastien Deleuze 84bd44e5de Use nullable body consistently in HttpClientErrorException
Closes gh-35482
2025-09-15 10:18:04 +02:00
Sébastien Deleuze 2faed3cdbb Refine PropagationContextElement
This commit apply several refinements to PropagationContextElement:
 - Capture the ThreadLocal when instantiating the
   PropagationContextElement in order to support dispatchers switching
   threads
 - Remove the constructor parameter which is not idiomatic and breaks
   the support when switching threads, and use instead the
   updateThreadContext(context: CoroutineContext) parameter
 - Make the kotlinx-coroutines-reactor dependency optional
 - Make the properties private

The Javadoc and tests are also updated to use the
`Dispatchers.IO + PropagationContextElement()` pattern performed
outside of the suspending lambda, which is the typical use case.

Closes gh-35469
2025-09-12 17:26:07 +02:00
Brian Clozel 20e1149dde Fix synchronization in ResponseBodyEmitter
See gh-35423
Fixes gh-35466
2025-09-12 09:12:33 +02:00
Sébastien Deleuze 7a5d3a55fe Refine EntityManagerRuntimeHints for Hibernate 7.1+
This commit adds support for Hibernate 7.1+ SqmQueryImpl class in
EntityManagerRuntimeHints, keeps the support for the former
QuerySqmImpl class for Hibernate 7.0 compatibility and adds a
related test.

Closes gh-35462
2025-09-11 15:24:55 +02:00
Brian Clozel e89056cd69 Merge branch '6.2.x' 2025-09-11 09:40:49 +02:00
Juergen Hoeller f2972d8b38 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-orm/src/main/java/org/springframework/orm/jpa/JpaTransactionManager.java
2025-09-10 18:39:50 +02:00
Juergen Hoeller 59804ab396 Align JpaTransactionManager default for nestedTransactionAllowed flag
Closes gh-35457
2025-09-10 17:41:25 +02:00
rstoyanchev dd60fddaf0 Always process SSE "data:" line
ServerSentEventHttpMessageReader now always processes "data:"
lines, including empty lines, as per SSE spec.

Closes gh-35412
2025-09-10 16:22:23 +01:00
rstoyanchev 3702031f82 Improve docs on versioning by path segment
Closes gh-35421
2025-09-10 16:22:23 +01:00
Sam Brannen 15c5cf472b Merge branch '6.2.x' 2025-09-10 14:29:17 +02:00
Sébastien Deleuze 86fb62c059 Upgrade to Kotlin 2.2.20
Closes gh-35414
2025-09-10 14:03:30 +02:00
Brian Clozel ef2a403df6 Add PropagationContextElement Kotlin operator
Prior to this commit, the Micrometer context-propagation project would
help propagating information from `ThreadLocal`, Reactor `Context` and
other context objects. This is already well supported for Micrometer
Observations.

In the case of Kotlin suspending functions, the processing of tasks
would not necessarily update the `ThreadLocal` when the function is
scheduled on a different thread.

This commit introduces the `PropagationContextElement` operator that
connects the `ThreadLocal`, Reactor `Context` and Coroutine `Context`
for all libraries using the "context-propagation" project.

Applications must manually use this operator in suspending functions
like so:

```
suspend fun suspendingFunction() {
  return withContext(PropagationContextElement(currentCoroutineContext())) {
    logger.info("Suspending function with traceId")
  }
}
```

Closes gh-35185
2025-09-09 21:42:08 +02:00
Juergen Hoeller 21e52a4283 Upgrade to Tomcat 11.0.11 and EclipseLink 5.0.0-B10 2025-09-09 18:54:52 +02:00
Juergen Hoeller f7b0d44bfd Upgrade to Reactor 2025.0.0-M7 and Micrometer 1.16.0-M3
Closes gh-35452
Closes gh-35453
2025-09-09 18:50:10 +02:00
Juergen Hoeller 2c547e9051 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-09-09 18:48:30 +02:00
Brian Clozel 39db0e0af2 Merge branch '6.2.x' 2025-09-09 16:56:29 +02:00
Sébastien Deleuze 563dccbbda Add debug logging when no CORS configuration
Closes gh-35314
2025-09-09 15:53:34 +02:00
Sébastien Deleuze f8823ddc11 Polish JSP documentation
This commit ensures consistency with the documentation of other view
resolvers.

See gh-35444
2025-09-09 13:36:10 +02:00
Sébastien Deleuze dff489d0cf Refine JSP documentation contribution
This commit refines the JSP view resolver documentation contribution
by using tabs for Java and XML configuration, with Java displayed by
default.

Closes gh-35444
2025-09-09 13:28:17 +02:00
DongNyoung Lee 1abd1d767d Update mvc-jsp.adoc
See gh-35444
Signed-off-by: DongNyoung Lee <121621378+Dongnyoung@users.noreply.github.com>
2025-09-09 11:55:19 +02:00
Sébastien Deleuze 7baf6d12b0 Merge branch '6.2.x' 2025-09-09 11:28:09 +02:00
Juergen Hoeller 1107a43b65 Upgrade to Jetty 12.1 onWebSocketClose signature
Includes switch to catching Throwable instead of Exception.

See gh-35345
2025-09-08 19:09:56 +02:00
Juergen Hoeller 3fb3b3d1b9 Upgrade to Jetty 12.1 onWebSocketClose signature
See gh-35345
2025-09-08 18:55:52 +02:00
Juergen Hoeller ad796fb1a8 Upgrade to Jetty 12.1.1, Netty 4.2.6, Checkstyle 11.0.1 2025-09-08 18:28:16 +02:00
Juergen Hoeller 5be5843cb7 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-09-08 18:23:37 +02:00
Juergen Hoeller a053e6594c Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/io/Resource.java
#	spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java
#	spring-core/src/test/java/org/springframework/util/FileSystemUtilsTests.java
#	spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java
2025-09-08 17:30:43 +02:00
Juergen Hoeller b8f71b2321 Add DataFieldMaxValueIncrementer for SQLite (migrated from Spring Batch)
Closes gh-35440
2025-09-08 17:03:18 +02:00
Juergen Hoeller 27221581a1 Expose getFilePath() on Resource interface for consistent NIO support
Closes gh-35435
2025-09-08 17:03:07 +02:00
Sam Brannen 114c3f7c9c Avoid unnecessary imports for Javadoc 2025-09-08 15:04:33 +02:00
Sam Brannen 8f34a67024 Polish core retry internals 2025-09-08 15:03:50 +02:00
rstoyanchev 9849094586 Merge branch '6.2.x' 2025-09-08 13:56:19 +01:00
rstoyanchev 736383e6cb Remove HttpServiceClient annotation
Closes gh-35431
2025-09-08 13:56:07 +01:00
Sam Brannen e93a6a7230 Improve wording for retry exceptions 2025-09-08 14:39:46 +02:00
Sam Brannen 1786eb2901 Introduce RetryInterruptedException to address off-by-one error
Prior to this commit, a RetryException thrown for an
InterruptedException returned the wrong value from getRetryCount().
Specifically, the count was one more than it should have been, since the
suppressed exception list contains the initial exception as well as all
retry attempt exceptions.

To address that, this commit introduces an internal
RetryInterruptedException which accounts for this off-by-one error.

Closes gh-35434
2025-09-08 14:22:52 +02:00
Sam Brannen b2cdfbadf1 Introduce onRetryPolicyInterruption() callback in RetryListener
In RetryTemplate, if we encounter an InterruptedException while
sleeping for the configured back-off duration, we throw a
RetryException with the InterruptedException as the cause.

However, prior to this commit, that RetryException propagated to the
caller without notifying the registered RetryListener.

To address that, this commit introduces a new
onRetryPolicyInterruption() callback in RetryListener as a companion to
the existing onRetryPolicyExhaustion() callback.

Closes gh-35442
2025-09-08 13:47:23 +02:00
Sébastien Deleuze 13d36a51de Upgrade to Jackson 3.0.0-rc9 and 2.20.0
Closes gh-35439
2025-09-08 10:07:33 +02:00
Sam Brannen bce44b007d Document programmatic retry support in the reference manual
Closes gh-35436
2025-09-07 17:58:28 +02:00
Sam Brannen 7484b9c491 Consistently include exceptions for previous attempts in RetryException
In RetryTemplate, if we encounter an InterruptedException while
sleeping for the configured back-off duration, we throw a
RetryException with the InterruptedException as the cause.

However, in contrast to the specification for RetryException, we do not
currently include the exceptions for previous retry attempts as
suppressed exceptions in the RetryException which is thrown in such
scenarios.

In order to comply with the documented contract for RetryException,
this commit includes exceptions for previous attempts in the
RetryException thrown for an InterruptedException as well.

Closes gh-35434
2025-09-06 16:39:22 +02:00
Sam Brannen 7b2730c271 Include current exception in log message for failed retry attempt
Prior to this commit, we included the initial exception in the log
message for the initial invocation of a retryable operation; however,
we did not include the current exception in the log message for
subsequent attempts.

For consistency, we now include the current exception in log messages
for subsequent retry attempts as well.

Closes gh-35433
2025-09-06 16:16:38 +02:00
Sébastien Deleuze d218b0899a Invalid Nullness information for Kotlin properties
This commit adds support for Kotlin properties to Nullness
forMethodReturnType and forParameter methods.

Closes gh-35419
2025-09-05 17:43:08 +02:00
Sébastien Deleuze d2bdf11b39 Refine Nullness for Kotlin functions returning Unit
Should have unspecified nullness like for Java void/Void.

Closes gh-35420
2025-09-05 11:16:27 +02:00
Sam Brannen e5b58effa3 Deprecate put(MergedContextConfiguration, ApplicationContext) in ContextCache
Closes gh-35415
2025-09-04 15:04:41 +02:00
Sébastien Deleuze 02b3a2bf34 Upgrade to Kotlin 2.2.10
Closes gh-35414
2025-09-04 14:37:44 +02:00
Sam Brannen ca62119cb3 Evict context from ContextCache before loading a new context
Since Spring Framework 4.2, DefaultContextCache supported an LRU (least
recently used) eviction policy via a custom LruCache which extended
LinkedHashMap. The LruCache reacted to LinkedHashMap's
removeEldestEntry() callback to remove the LRU context if the maxSize
of the cache was exceeded.

Due to the nature of the implementation in LinkedHashMap, the
removeEldestEntry() callback is invoked after a new entry has been
stored to the map.

Consequently, a Spring ApplicationContext (C1) was evicted from the
cache after a new context (C2) was loaded and added to the cache,
leading to failure scenarios such as the following.

- C1 and C2 share an external resource -- for example, a database.
- C2 initializes the external resource with test data when C2 is loaded.
- C1 cleans up the external resource when C1 is closed.
- C1 is loaded and added to the cache.
- C2 is loaded and added to the cache before C1 is evicted.
- C1 is evicted and closed.
- C2 tests fail, because C1 removed test data required for C2.

To address such scenarios, this commit replaces the custom LruCache
with custom LRU eviction logic in DefaultContextCache and revises
the put(MergedContextConfiguration, ApplicationContext) method to
delegate to a new evictLruContextIfNecessary() method.

This commit also introduces a new put(MergedContextConfiguration,
LoadFunction) method in the ContextCache API which is overridden by
DefaultContextCache to ensure that an evicted context is removed and
closed before a new context is loaded to take its place in the cache.

In addition, DefaultCacheAwareContextLoaderDelegate has been revised to
make use of the new put(MergedContextConfiguration, LoadFunction) API.

Closes gh-21007
2025-09-04 14:13:10 +02:00
Sam Brannen 8eca3a3eaf Polishing 2025-09-04 14:10:17 +02:00
Sam Brannen 80a7371510 Merge branch '6.2.x' 2025-09-03 16:29:55 +02:00
Juergen Hoeller 410eff641c Merge branch '6.2.x' 2025-09-03 15:46:13 +02:00
Sam Brannen e53e413a21 Merge branch '6.2.x' 2025-09-03 14:53:20 +02:00
rstoyanchev 79151a0bc2 Spring MVC recognizes gRPC streams
For this to work, a compatible message converter is necessary,
but only available in spring-grpc.

See gh-35401
2025-09-02 20:38:59 +01:00
rstoyanchev 10a288c986 Polishing in StatusHandler
See gh-35391
2025-09-02 15:38:03 +01:00
Johnny Lim d32b7e9b4a Polish gh-35358
Signed-off-by: Johnny Lim <izeye@naver.com>
2025-09-02 23:13:27 +09:00
Sam Brannen 6dc5bf7634 Clean up warnings related to deprecated HttpStatus values, etc. 2025-09-02 12:50:57 +02:00
Sam Brannen 521764e68b Fix links, @⁠since tags, formatting, etc. in RestTestClient 2025-09-02 12:31:17 +02:00
Brian Clozel 942fbf3032 Polishing contribution
Closes gh-34683
2025-09-01 11:50:22 +02:00
Mengqi Xu 7b3c4e5893 Add support for Forwarded By HTTP headers
See gh-34683

Signed-off-by: Mengqi Xu <2663479778@qq.com>
2025-09-01 11:49:59 +02:00
Park Sung Jun 1653ec3b44 Add tests for applyRelativePath method in StringUtils
Closes gh-35397

Signed-off-by: Park Sung Jun <junstin119@gmail.com>
2025-09-01 09:25:55 +02:00
Sam Brannen 746fc335c2 Merge branch '6.2.x' 2025-08-29 17:25:56 +02:00
Brian Clozel 9979de99fd Do not decompress HTTP responses when compression disabled
This commit refines changes made in gh-35225 so as to not decompress
HTTP responses if decompression support is not enabled.

Closes gh-35225
2025-08-29 16:47:58 +02:00
rstoyanchev 441b14b0c1 Handle error responses in RestClientAdapter
Closes gh-35375
2025-08-29 16:04:45 +03:00
rstoyanchev f22d1eab23 Add createException to ConvertibleClientHttpResponse
Closes gh-35391
2025-08-29 16:04:45 +03:00
rstoyanchev 21e6d7392d Re-order methods and polishing
In StatusHandler and DefaultConvertibleClientHttpResponse.

See gh-35391
2025-08-29 16:04:45 +03:00
Gustav a585beac49 Fix typo in websocket doc (#35393)
Signed-off-by: Gustav <69737612+gustaavv@users.noreply.github.com>
2025-08-29 13:17:18 +02:00
rstoyanchev 0c02443965 Consistently support no value params in query string
Closes gh-35329
2025-08-29 10:25:37 +03:00
rstoyanchev 268706abd2 Polishing in AbstractMockHttpServletRequestBuilder
See gh-35329
2025-08-29 10:22:43 +03:00
Johnny Lim 737f66d922 Restore mixed use of uri() and queryParam()
for query parameters in AbstractMockHttpServletRequestBuilder.

See gh-35329

Signed-off-by: Johnny Lim <izeye@naver.com>
2025-08-29 09:13:51 +03:00
rstoyanchev 11cb062357 Assert versionRequired and defaultVersion
Closes gh-35387
2025-08-28 15:50:33 +03:00
rstoyanchev a7e3a438c9 Correctly apply required API version validation
Closes gh-35386
2025-08-28 15:50:33 +03:00
Brian Clozel 442a2d0ca2 Merge branch '6.2.x' 2025-08-27 13:40:41 +02:00
Brian Clozel 81b4020fc6 Do not load concrete types in annotation metadata
This change fixes a regression introduced in the previous commit.

Closes gh-35252
2025-08-26 21:58:15 +02:00
Brian Clozel 2b7f88ee44 Fix annotation arrays support in ClassFile metadata
As of gh-33616, Spring now supports metadata reading with the ClassFile
API on JDK 24+ runtimes. This commit fixes a bug where
`ArrayStoreException` were thrown when reading annotation attribute
values for arrays.

Fixes gh-35252
2025-08-26 18:40:35 +02:00
rstoyanchev d8804c798b RestTestClient correctly exposes the response body
Closes gh-35385
2025-08-26 18:22:32 +03:00
Sam Brannen 55c315eb12 Merge branch '6.2.x' 2025-08-26 11:06:24 +02:00
Brian Clozel 18eb2a6073 Polishing contribution
Closes gh-35225
2025-08-25 19:12:24 +02:00
spicydev 4101714830 Add compression support in JdkClientHttpRequestFactory
This commit ensures that the "Accept-Encoding" header is present for HTTP
requests sent by the `JdkClientHttpRequestFactory`. Only "gzip" and
"deflate" encodings are supported.

This also adds a custom `BodyHandler` that decompresses HTTP response
bodies if the "Content-Encoding" header lists a supported variant.

This feature is enabled by default and can be disabled on the request
factory.

See gh-35225

Signed-off-by: spicydev <vivek@mirchi.dev>
[brian.clozel@broadcom.com: squash commits]
Signed-off-by: Brian Clozel <brian.clozel@broadcom.com>
2025-08-25 19:11:38 +02:00
Sébastien Deleuze fdfd15b9b3 Refine null-safety tooling introduction
Closes gh-35383
2025-08-25 14:39:59 +02:00
Brian Clozel 7112efee1b Align HttpStatus with RFC9110
This commit updates the `HttpStatus` enum with the latest changes in
RFC9110:

* deprecate "413 Payload Too Large" in favor of "413 Content Too Large"
* deprecate "418 I'm a teapot" as it was meant as a joke and is now
  marked as unused
* Introduce new "421 Misdirected Request"
* deprecate "422 Unprocessable Entity" in favor of
  "422 Unprocessable Content"
* deprecate "509 Bandwidth Limit Exceeded" as it's now unassigned
* deprecate "510 Not Extended" as it's now marked as "historic"

The relevant exceptions, test matchers and more have been updated as a
result.

Closes gh-32870
2025-08-25 14:30:57 +02:00
Sam Brannen 606b689fb1 Merge branch '6.2.x' 2025-08-24 14:02:27 +02:00
Juergen Hoeller a1f5f6aa92 Merge branch '6.2.x' 2025-08-24 10:32:31 +02:00
Sam Brannen 9e9d716d7a Merge branch '6.2.x' 2025-08-23 13:46:25 +02:00
Juergen Hoeller e6f2b6a2a3 Upgrade to Netty 4.2.4 2025-08-22 23:21:59 +02:00
Juergen Hoeller acd68261e5 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-08-22 23:07:29 +02:00
Juergen Hoeller 56269d76e5 Merge branch '6.2.x' 2025-08-22 22:02:24 +02:00
Juergen Hoeller a46023134a Polishing 2025-08-22 21:05:16 +02:00
Brian Clozel d128dd2616 Make StartupStep AutoCloseable
This commit mames `StartupStep` extend `AutoCloseable` in order to allow
the try/with resources syntax and making the `step.end()` call
transparent.

Closes gh-35277
2025-08-22 19:24:11 +02:00
Sébastien Deleuze dc26aaa0ec Use JsonMapper instead of ObjectMapper when relevant
This commit updates Jackson 3 JSON support to use JsonMapper
instead of ObjectMapper in converters, codecs and view constructors.

As a consequence, AbstractJacksonDecoder, AbstractJacksonEncoder,
AbstractJacksonHttpMessageConverter and JacksonCodecSupport are
now parameterized with <T extends ObjectMapper>.

Closes gh-35282
2025-08-22 18:39:23 +02:00
Juergen Hoeller 8f4107953d Perform retryable proceed() call on invocableClone()
Closes gh-35353
2025-08-21 17:38:07 +02:00
NeatGuyCoding 57fa52262e Fix @⁠HttpServiceClient example in reference manual
Closes gh-35363

Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-08-21 12:09:34 +02:00
Juergen Hoeller f64ff2866a Expose RetryException to onRetryPolicyExhaustion (also in the signature)
Includes getRetryPolicy and getRetryListener accessors in RetryTemplate.

Closes gh-35334
2025-08-21 11:54:27 +02:00
Juergen Hoeller 2489cced0f Expose RetryException#getRetryCount() and accept maxAttempts(0)
Closes gh-35351
Closes gh-35362
2025-08-20 23:15:40 +02:00
Sam Brannen 472f844256 Merge branch '6.2.x' 2025-08-20 16:42:56 +02:00
Brian Clozel 208bb48254 Document OpenTelemetry HTTP server convention
Closes gh-35358
2025-08-20 16:16:26 +02:00
Tommy Ludwig 7e45f609a2 Add test for OpenTelemetryServerRequestObservationConvention
See gh-35358
2025-08-20 16:16:23 +02:00
Tommy Ludwig 3269751887 OTel semantic conventions for HTTP server for Servlet-based instrumentation
Adds an ObservationDocumentation and ObservationConvention implementation
that follows the OpenTelemetry semantic convention for HTTP Server
metrics and spans.

See gh-35358
2025-08-20 16:16:01 +02:00
Sam Brannen c942b21dea Generate consistent validation error messages in RetryPolicy
Closes gh-35355
2025-08-20 14:38:36 +02:00
Brian Clozel fce7b3d420 Remove Undertow-specific support and testing
Undertow does not support Servlet 6.1, we need to remove compatibility
tests as well as Undertow-specific classes for WebSocket and reactive
support.

Closes gh-35354
2025-08-20 10:32:33 +02:00
Sam Brannen 887ef75700 Remove redundant declarations of JSpecify's @⁠NonNull annotation
Closes gh-35341
2025-08-19 17:30:47 +02:00
Sam Brannen bb2a259d85 Wrap exceptionally long lines 2025-08-19 17:28:11 +02:00
Sébastien Deleuze 7a2a167f34 Upgrade nullability plugin to 0.0.4
This commit also includes related refinements of
JdbcTemplate#getSingleColumnRowMapper and
ObjectUtils#addObjectToArray.

Closes gh-35340
2025-08-19 15:31:57 +02:00
Sam Brannen 5d325ca0fc Improve wording for transactional rollback rule semantics
Closes gh-35346
2025-08-19 13:32:35 +02:00
Sam Brannen 68762b5f86 Merge branch '6.2.x' 2025-08-19 12:34:42 +02:00
Brian Clozel 4791565630 Polishing
See gh-35345
2025-08-19 11:12:06 +02:00
Brian Clozel 3fba265b60 Upgrade to Jetty 12.1.0
Jetty 12.1 is Jakarta EE11 compliant.

Closes gh-35345
2025-08-19 09:36:16 +02:00
Sébastien Deleuze 3dc2aa79a4 Fix HttpEntity support with Kotlin Serialization
This commit adds HttpEntity type unwrapping logic to
KotlinRequestBodyAdvice and KotlinResponseBodyAdvice.

Closes gh-35281
2025-08-18 12:01:48 +02:00
Brian Clozel 0d2a0d7b9e Fix '**' parsing within a PathPattern segment
Prior to this commit, a regexp path segment ending with a double wilcard
(like "/path**") would be incorrectly parsed as a double wildcard
segment ("/**").

This commit fixes the incorrect parsing.

Fixes gh-35339
2025-08-18 10:44:15 +02:00
Sam Brannen a999dd13f5 Document semantics of RetryException regarding cause and suppressed exceptions
Closes gh-35337
2025-08-17 19:17:27 +02:00
Sam Brannen 9d57dabe2f Rename exception variables to clarify intent 2025-08-17 19:17:27 +02:00
Sam Brannen ed2fb61ce9 Remove duplicated word in Javadoc 2025-08-17 18:19:33 +02:00
Sam Brannen a803ecdf26 Test expected behavior for RetryTemplate with zero retries 2025-08-17 17:59:14 +02:00
Sam Brannen 72afc66507 Make RetryTemplateTests more robust 2025-08-17 17:57:07 +02:00
Sam Brannen c38606610c Supply correct exception to RetryListener.onRetryPolicyExhaustion()
Prior to this commit, RetryTemplate supplied the wrong exception to
RetryListener.onRetryPolicyExhaustion(). Specifically, the execute()
method in RetryTemplate supplied the final, composite RetryException to
onRetryPolicyExhaustion() instead of the last exception thrown by the
Retryable operation.

This commit fixes that bug by ensuring that the last exception thrown by
the Retryable operation is supplied to onRetryPolicyExhaustion().

Closes gh-35334
2025-08-16 16:07:37 +02:00
Sam Brannen 9982369982 Revise nullability in RetryException
See gh-35332
2025-08-16 15:01:24 +02:00
Stéphane Nicoll 532911eb93 Mark RetryException#getCause non null
This commit simplifies RetryException to always require a root cause
and mark it as not nullable. Such exception is the exception thrown by
the retryable operation and should always be available as it explains
why the invocation was a candidate for retrying in the first place.

Closes gh-35332
2025-08-16 09:20:02 +02:00
Sébastien Deleuze 498b0c231b Always provision Java 24 for the CI Gradle build
See gh-35007
2025-08-14 20:03:08 +02:00
Sébastien Deleuze 06386d561b Merge branch '6.2.x' 2025-08-14 16:15:26 +02:00
Sébastien Deleuze c6f1f719c3 Formatting issue in RestTestClient documentation
Closes gh-35328
2025-08-14 15:59:28 +02:00
Stéphane Nicoll a23230b6c0 Merge branch '6.2.x' 2025-08-14 09:55:29 +02:00
Stéphane Nicoll fcc092d77e Merge branch '6.2.x' 2025-08-14 09:07:15 +02:00
Stéphane Nicoll 367b229ff6 Merge branch '6.2.x' 2025-08-14 08:48:15 +02:00
Sébastien Deleuze 1af95a0704 Upgrade to Jackson 3.0.0-rc8 and 2.20.0-rc1
Closes gh-35295
2025-08-13 23:03:40 +02:00
rstoyanchev 8ec0c21b0a MockMvc handles param without values
Closes gh-35210
2025-08-13 15:23:04 +01:00
Juergen Hoeller 9f9b33c2ac Upgrade to Reactor 2025.0.0-M6, Micrometer 1.16.0-M2, Jetty 12.1.0.beta3
Includes Checkstyle 11.0, Groovy 5.0 RC1, JRuby 10.0.2, MockK 1.14.5

Closes gh-35310
Closes gh-35311
Closes gh-35233
2025-08-13 00:48:37 +02:00
Juergen Hoeller 39de72a361 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-08-13 00:07:25 +02:00
Sébastien Deleuze 0389e3e3af Revert "Use JsonMapper instead of ObjectMapper when relevant"
This reverts commit d115f36400.

See gh-35282
2025-08-12 15:21:20 +02:00
Sébastien Deleuze 49b28be1be Fix JacksonJsonSockJsMessageCodec imports
Closes gh-35309
2025-08-12 10:43:07 +02:00
Sébastien Deleuze d115f36400 Use JsonMapper instead of ObjectMapper when relevant
This commit updates Jackson 3 support to use JsonMapper instead
of ObjectMapper in converter, codec and view constructors.

Closes gh-35282
2025-08-12 10:36:37 +02:00
Sébastien Deleuze bde806b7fc Upgrade SDKMAN to Java 24.0.2 2025-08-12 10:26:30 +02:00
rstoyanchev 83b7bef572 Polishing contribution
Closes gh-35227
2025-08-12 06:57:28 +01:00
Fabrice Bibonne bfcf4ea818 Document HTTP range request constraints
See gh-35227

Signed-off-by: Fabrice Bibonne <fabrice.bibonne@gmail.com>
2025-08-12 06:57:28 +01:00
rstoyanchev 553f289ddb Polishing contribution
Closes gh-35307
2025-08-12 06:43:10 +01:00
Phillip Webb 169b7015d2 Only add httpServiceProxyRegistry bean when necessary
Update `AbstractHttpServiceRegistrar` so that the
`httpServiceProxyRegistry` bean  is only added when registrations
are found.
2025-08-12 06:31:24 +01:00
rstoyanchev fbe96a8112 Polishing contribution
Closes gh-35224
2025-08-12 06:30:08 +01:00
Songdoeon b89dcb1a1a Subscription.unsubscribe() returns Receiptable
See gh-35224

Signed-off-by: Songdoeon <ehdjs9583@naver.com>
2025-08-12 06:11:35 +01:00
Juergen Hoeller 876b7d4209 Upgrade to Hibernate ORM 7.1
Closes gh-35308
2025-08-11 22:43:02 +02:00
rstoyanchev 8f1ade55d9 Update contribution
Closes gh-35273
2025-08-11 16:32:23 +01:00
SRIRAM9487 4d6a921df5 Add HTTP method support to MappedInterceptor
This enhancement enables finer control over interceptor application
based on HTTP methods, aligning with modern Spring 7.x practices.

- Extend MappedInterceptor with include/exclude HTTP methods
- Add constructors for interceptor implementations
- Update InterceptorRegistration with fluent methods
- Keep existing constructors and methods for compatibility
- Update matches() to check HTTP method conditions

See gh-35273

Signed-off-by: SRIRAM9487 <sriram9487tk@gmail.com>
2025-08-11 16:32:23 +01:00
Sam Brannen 15d3692669 Update assertion in JdbcClientIntegrationTests 2025-08-11 17:53:05 +03:00
Sam Brannen 0efa04f32c Merge branch '6.2.x' 2025-08-11 17:49:36 +03:00
Juergen Hoeller 29203d7293 Merge branch '6.2.x' 2025-08-11 14:34:17 +02:00
Sam Brannen a65ebec3d8 Merge branch '6.2.x' 2025-08-11 11:29:03 +03:00
rstoyanchev 29521e2f8a Merge branch '6.2.x' 2025-08-08 12:31:28 +01:00
rstoyanchev 89ba0fd6df Polishing contribution
Closes gh-35294
2025-08-08 12:08:22 +01:00
Christoph 96deb27211 Make type in ProblemDetail nullable
See gh-35294

Signed-off-by: Christoph Wagner <cwagner@dimedis.de>
Signed-off-by: Christoph <cwagner@dimedis.de>
2025-08-08 11:54:03 +01:00
rstoyanchev a0542f023c Merge branch '6.2.x' 2025-08-08 11:50:58 +01:00
Juergen Hoeller 2f262afc51 Add documentation section on proxy type defaults and @Proxyable
See gh-35286
See gh-35296
2025-08-06 21:11:07 +02:00
Juergen Hoeller 573c5d96b9 Merge branch '6.2.x'
# Conflicts:
#	spring-aop/src/main/java/org/springframework/aop/framework/AbstractAdvisingBeanPostProcessor.java
2025-08-06 19:03:14 +02:00
Juergen Hoeller d5408c047d Introduce @Proxyable annotation for bean-specific proxy type
Closes gh-35296
See gh-35293
2025-08-06 18:32:01 +02:00
Juergen Hoeller df86a9973d Introduce @Proxyable annotation for bean-specific proxy type
Closes gh-35296
See gh-35293
2025-08-06 18:26:40 +02:00
Juergen Hoeller 9edb96ae57 Introduce default ProxyConfig bean and exposed interfaces attribute
Taken into account by all proxy processors, this enables consistent proxy type defaulting in Spring Boot as well as consistent opting out for specific bean definitions.

Closes gh-35286
Closes gh-35293
2025-08-06 14:51:13 +02:00
Juergen Hoeller 4ad9396b15 Update CountDownLatch for non-pauseable beans
See gh-35269
2025-08-04 15:27:56 +02:00
Sam Brannen 61df497785 Revise reference docs regarding new ApplicationContext pause() support
See gh-35269
2025-08-04 12:05:26 +03:00
Sam Brannen e590341ca7 Revise Javadoc regarding new ApplicationContext pause() support
See gh-35269
2025-08-04 11:50:47 +03:00
Juergen Hoeller 4bfc129f84 Merge branch '6.2.x' 2025-08-01 21:17:54 +02:00
Juergen Hoeller 03a8933f58 Add transactional support for StatelessSession (next to regular Session)
Exposes JPA-style shared proxy instances through LocalSessionFactoryBean.

Closes gh-7184
2025-08-01 17:18:43 +02:00
Brian Clozel ec87d90c9b Post process outgoing messages in JMS clients
Prior to this commit, the `JmsTemplate` would use `MessagePostProcessor`
for mutating JMS messages before they are being sent, but only if the
method takes a post processor as an argument.
The main use case so far is to mutate messages after they've been
created by a `MessageConverter` from a payload.

This commit updates the `JmsClient` to use `MessagePostProcessor` more
broadly, for all outgoing messages (converted or not). This brings an
interception-like mechanism for clients to enrich the message before
being sent.

This change also updates the `JmsClient` static factories and
introduces a Builder, allowing for more configuration options: multiple
message converters and message post processors.

Closes gh-35271
2025-08-01 15:40:32 +02:00
Juergen Hoeller 149d468ce4 Introduce ConfigurableApplicationContext.pause() and SmartLifecycle.isPauseable()
Closes gh-35269
2025-08-01 15:08:15 +02:00
rstoyanchev 96bc1f50c7 Add interceptors and converters to RestTestClient.Builder
Closes gh-35268
2025-08-01 13:31:37 +01:00
rstoyanchev 2b1a815167 Add supportedVersionPredicate to ApiVersionConfigurer
Closes gh-35267
2025-08-01 12:35:18 +01:00
rstoyanchev 87838aa4c5 PathApiVersionResolver is not nullable
Closes gh-35265
2025-07-31 15:32:12 +01:00
rstoyanchev da361699a4 Add MediaType parameter to ApiVersionInserter
Closes gh-35259
2025-07-31 15:32:12 +01:00
rstoyanchev 08ccf46399 Rename request param version strategy to query param
Closes gh-35263
2025-07-31 15:32:12 +01:00
rstoyanchev 18ee8adaeb Check resolver set when API version config customized
Closes gh-35256
2025-07-31 15:32:12 +01:00
NeatGuyCoding 5a3bad6d61 fix remove useless "s"
Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-07-31 11:42:02 +01:00
rstoyanchev d661550b48 Update docs for HttpServiceClient
Closes gh-35244
2025-07-31 05:22:49 +01:00
rstoyanchev c8b2a0f830 Rename HttpServiceClientRegistrarSupport
to AbstractClientHttpServiceRegistrar since it is a registrar and
an extension of Abstract[HttpServiceRegistrar]. Also, a more
friendly name for use in application configuration.

See gh-35244
2025-07-31 05:22:44 +01:00
rstoyanchev 9dbe304cf6 Revise method order in AbstractHttpServiceRegistrar
See gh-35244
2025-07-31 05:22:29 +01:00
rstoyanchev 0fc9e4ec1c Exclude HttpServiceClient from GroupRegistry scan
The detect methods in the GroupRegistry that find all interfaces
with HttpExchange annotations now exclude HttpServiceClient
interfaces that are instead supported by a dedicated registrar.

This ensures there is no overlap between the HttpServiceClient
registrar scan and the ImportHttpServices registrar scan or
the scan of any other custom registrar.

See gh-35244
2025-07-31 05:22:06 +01:00
rstoyanchev 09917fad7b Fix bean name for ApiVersionStrategy in WebFlux config 2025-07-30 13:55:00 +01:00
rstoyanchev 279bce7124 Add HttpServiceClient and registrar
See gh-35244
2025-07-30 13:27:12 +01:00
rstoyanchev da443020e0 Rename AnnotationHttpServiceRegistrar
Align with the name of the import annotation.
In preparation of adding a client annotation with another registrar.

See gh-35244
2025-07-30 13:27:12 +01:00
rstoyanchev 4ae5d0d1fe Polishing in RestTestClient reference docs
Closes gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev f57828708a Polishing in RestTestClient tests
See gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev 88ddc9d45d Polishing in [Rest|Web]TestClient Assertions
See gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev 6cc1310274 Add API versioning to RestTestClient
See gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev 862ffee385 Update RestTestClient ExchangeResult
to expose request and URI template information and to have toString

See gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev 34f259778e Further alignment of RestTestClient and WebTestClient
See gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev 2732b603dc Update RestTestClient builder hierarchy
Add concrete classes with specified generics for each MockMvc setup
Ensure Builder methods return the concrete class

See gh-34428
2025-07-30 07:13:48 +01:00
rstoyanchev db4696ceae Align RestTestClient and WebTestClient structure
See gh-34428
2025-07-30 07:13:48 +01:00
Rob Worsnop 934b8fc799 Common base classes for WebTestClient/RestTestClient Assertions
Fixes gh-31275

Signed-off-by: Rob Worsnop <rworsnop@gmail.com>
2025-07-30 07:13:48 +01:00
Rob Worsnop 37dcca54d2 Add RestTestClient
See gh-34428

Signed-off-by: Rob Worsnop <rworsnop@gmail.com>
2025-07-30 07:13:48 +01:00
rstoyanchev 336a5d0ac8 Add container for MockMvcServerServerSpec hierarchy
See gh-34428
2025-07-30 07:13:48 +01:00
Brian Clozel e838444e81 Merge branch '6.2.x' 2025-07-29 21:49:24 +02:00
Juergen Hoeller 321a804449 Merge branch '6.2.x' 2025-07-28 22:07:53 +02:00
Juergen Hoeller dacaf7fd56 Align @Nullable annotation 2025-07-28 20:33:33 +02:00
Juergen Hoeller 2a0a1fa67a Merge branch '6.2.x'
# Conflicts:
#	spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/GenericTableMetaDataProvider.java
2025-07-28 20:32:30 +02:00
rstoyanchev 2c32c770d5 Polishing in VersionRequestCondition
See gh-35237
2025-07-28 09:06:19 +01:00
rstoyanchev 2238121350 Prefer mapping without version for unversioned request
Closes gh-35237
2025-07-28 08:48:05 +01:00
rstoyanchev 48506db996 Avoid IllegalStateException for unversioned request
Closes gh-35236
2025-07-28 08:47:57 +01:00
Juergen Hoeller c7fbf7809f Provide @WebSocketScope annotation and public SCOPE_WEBSOCKET constant
Closes gh-35235
2025-07-26 11:38:02 +02:00
Juergen Hoeller 7316aab048 Align @Nullable annotation 2025-07-25 22:43:57 +02:00
Juergen Hoeller eaccb56de9 Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/io/support/PathMatchingResourcePatternResolver.java
2025-07-25 22:42:14 +02:00
Brian Clozel 444573d4b5 Display original request URI in NoResourceFoundException message
This commit ensures that the original request URI is displayed in
`NoResourceFoundException` error messages when logged. Without this
change, it can be confusing to see only the attempted resource path.
There are cases where the original request was not meant for resource
handling and we want to understand why this wasn't processed by another
handler.

The Problem Detail attribute has not been changed as the "instance"
attribute already displays the request path.

Closes gh-34553
2025-07-25 15:04:59 +02:00
Brian Clozel d06255214e Support wildcard path elements at the start of path patterns
Prior to this commit, the `PathPattern` and `PathPatternParser` would
allow multiple-segments matching and capturing with the following:

* "/files/**" (matching 0-N segments until the end)
* "/files/{*path}" (matching 0-N segments until the end and capturing
  the value as the "path" variable)

This would be only allowed as the last path element in the pattern and
the parser would reject other combinations.

This commit expands the support and allows multiple segments matching at
the beginning of the path:

* "/**/index.html" (matching 0-N segments from the start)
* "/{*path}/index.html" (matching 0-N segments until the end and capturing
  the value as the "path" variable)

This does come with additional restrictions:

1. "/files/**/file.txt" and "/files/{*path}/file.txt" are invalid,
   as multiple segment matching is not allowed in the middle of the
   pattern.
2. "/{*path}/files/**" is not allowed, as a single "{*path}" or "/**"
   element is allowed in a pattern
3. "/{*path}/{folder}/file.txt"  "/**/{folder:[a-z]+}/file.txt" are
   invalid because only a literal pattern is allowed right after
   multiple segments path elements.

Closes gh-35213
2025-07-25 13:24:18 +02:00
Sébastien Deleuze ed2cad3af0 Merge branch '6.2.x' 2025-07-23 16:30:12 +02:00
Brian Clozel 4bb191d51c Upgrade to Jetty 12.1.0.beta2
Closes gh-35233
2025-07-23 11:19:35 +02:00
Sam Brannen c6e46cf91f Merge branch '6.2.x' 2025-07-21 13:24:47 +03:00
Sébastien Deleuze 1ef6c6398a Upgrade to Jackson 3.0.0-rc6 and 2.19.2
Closes gh-35228
2025-07-21 11:15:18 +02:00
Sam Brannen fbc5ff80f4 Implement AutoCloseable in GzippedFiles 2025-07-18 15:45:59 +03:00
Stéphane Nicoll dd8313f200 Migrate to Palentir's JavaPoet
Closes gh-35214
2025-07-17 16:25:46 +02:00
Sébastien Deleuze 200b3ea023 Restore Java 17 compatibility in KotlinConventions
See gh-35211
2025-07-17 12:13:19 +02:00
Sébastien Deleuze c2a162a48b Link to the right Framework version in the KDoc
See gh-35211
2025-07-17 09:59:00 +02:00
Brian Clozel 8b4ff8c56b Merge branch '6.2.x' 2025-07-17 09:55:35 +02:00
Sébastien Deleuze adc64d5cbc Upgrade to Dokka 2.0.0
See https://kotlinlang.org/docs/dokka-migration.html

Closes gh-35211
2025-07-16 18:27:10 +02:00
Juergen Hoeller 6f725dc7aa Upgrade to MockK 1.14.4 2025-07-16 15:34:11 +02:00
Juergen Hoeller 75cb826b7b Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-07-16 15:33:50 +02:00
Juergen Hoeller 17382fe079 Re-initialize Quartz ConnectionProvider on context restart
Closes gh-35208
2025-07-16 15:21:49 +02:00
rstoyanchev 6f5a7eed76 Add section on Range requests to reference
Closes gh-35052
2025-07-16 13:50:41 +01:00
Brian Clozel 4bf048cfcf Configure ByteBuddy agent on test tasks
This commit replaces the Mockito agent configuration with a single
bytebuddy agent configuration that addresses both Mockito and mockk on
tests.

Closes gh-35207
2025-07-16 13:50:20 +02:00
Brian Clozel ebe1f65e21 Apply Mockito Java Agent to Kotlin tests too
See gh-35207
2025-07-15 21:58:53 +02:00
Juergen Hoeller 28471c33ae Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-web/src/main/java/org/springframework/http/server/observation/DefaultServerRequestObservationConvention.java
#	spring-web/src/main/java/org/springframework/http/server/reactive/observation/DefaultServerRequestObservationConvention.java
2025-07-15 21:26:38 +02:00
Brian Clozel bb88ec9ea5 Configure Mockito Java agent in Test tasks
Closes gh-35207
2025-07-15 21:00:20 +02:00
Juergen Hoeller eac490d320 Upgrade to Reactor 2025.0.0-M5 and Micrometer 1.16.0-M1
Includes Netty 4.2.3

Closes gh-35169
Closes gh-35170
2025-07-15 20:40:59 +02:00
Sébastien Deleuze 20a1261574 Make rootObject parameter consistently nullable
MethodBasedEvaluationContext and CacheEvaluationContext should allow a
nullable rootObject constructor parameter like
StandardEvaluationContext does.

Closes gh-35206
2025-07-15 17:49:30 +02:00
Sam Brannen 4fdf40e39e Fix Checkstyle configuration for nullability annotations
While assessing #35195, I noticed the following issues with our
Checkstyle configuration regarding nullability annotations.

- "^(?!org\.jspecify|\.annotations).*(NonNull|Nullable)$" contains a "|".

- "^(?!org\.jspecify|\.annotations).*(NonNull|Nullable)$" matches against
  NonNull but not against Nonnull, and therefore incorrectly permits
  usage of javax.annotation.Nonnull.

- Some of the Checkstyle suppressions no longer apply.

This commit addresses all of the above issues and updates several tests
to use example annotations other than javax.annotation.Nonnull where
feasible.

See gh-35195
Closes gh-35205
2025-07-15 16:50:21 +02:00
Sam Brannen aac61b86c8 Revert "Disallow @org.jetbrains.annotations.Nullable imports"
This reverts commit 6e6280a42c.

See gh-35114
See gh-35195
2025-07-15 16:45:55 +02:00
rstoyanchev e3f1bc8422 Allow resolution of optional HandlerMethod
Closes gh-35067
2025-07-15 15:39:49 +01:00
Sébastien Deleuze 19086835a7 Upgrade tests to OkHttp 5.x
See https://square.github.io/okhttp/changelogs/changelog/#version-500.

Closes gh-35183
2025-07-15 16:20:07 +02:00
Juergen Hoeller b76e748ecf Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-07-15 16:01:21 +02:00
Brian Clozel ad007caebc Refine multipart converter registration in HttpMessageConverters
As of #33894, `HttpMessageConverters` auto-detects converters and use
custom-provided ones to configure a collection of converters for the
client or the server.
Right now the multipart converter is only configured if core converters
(JSON, XML...) are configured/detected. We do not reuse the base
converters (resource, string, byte array) for the multipart converter
as it applies different encoding defaults (ISO for the main ones, UTF-8
for multipart).

This commit refines the configuration to not only include the multipart
converter when core converters are present, but also if any other
converter was configured.

Closes gh-35203
2025-07-15 14:45:28 +02:00
Sam Brannen 2e0cc63616 Implement DisplayNameCustomizer properly 2025-07-15 10:46:48 +02:00
Sam Brannen 7d628b6298 Polish Resilience Features section of reference manual 2025-07-15 10:39:49 +02:00
Sam Brannen dbe89abd7b Pause unused application contexts in the TestContext framework
Since the introduction of the Spring TestContext Framework in 2007,
application contexts have always been stored in the context cache in a
"running" state. However, leaving a context running means that
components in the context may continue to run in the background. For
example, JMS listeners may continue to consume messages from a queue;
scheduled tasks may continue to perform active work, etc.; and this can
lead to issues within a test suite.

To address such issues, this commit introduces built-in support for
pausing application contexts when they are not in use and restarting
them if they are needed again.

Specifically, the TestContextManager now marks a test's application
context as "unused" after execution of the test class has ended, and
the underlying ContextCache then "stops" the application context if no
other test class is currently using the context. When a
TestExecutionListener later attempts to obtain a paused application
context -- for example, for a subsequent test class that shares the
same application context -- the ContextCache ensures that context is
restarted before returning it.

See https://github.com/spring-projects/spring-boot/issues/28312
See gh-35171
Closes gh-35168
2025-07-14 18:29:02 +02:00
Sam Brannen f3757cedb9 Polish context caching section 2025-07-14 18:27:01 +02:00
Sam Brannen 4107ddc5e2 Remove obsolete Checkstyle suppression
See commit 7606a929c9
See gh-35107
2025-07-14 18:26:54 +02:00
Sam Brannen 5c6622fd77 Introduce ApplicationContextEvent.getSource() with covariant return type
Prior to this commit, ApplicationContextEvent inherited getSource()
from java.util.EventObject.getSource() which has an Object return type.

This commit introduces a local getSource() implementation in
ApplicationContextEvent with an ApplicationContext covariant return
type, analogous to TestContextEvent in spring-test.

Closes gh-35197
2025-07-14 14:13:13 +02:00
Juergen Hoeller 096670f31d Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java
2025-07-13 16:36:02 +02:00
Juergen Hoeller 1145054971 Introduce ConfigurationBeanNameGenerator for @Bean-annotated methods
Includes FullyQualifiedConfigurationBeanNameGenerator implementation.

Closes gh-33448
2025-07-13 16:08:05 +02:00
Brian Clozel b48f65aed6 Update milestone release action
See gh-35188
2025-07-12 19:09:27 +02:00
Brian Clozel 2ea17a2c43 Merge branch '6.2.x' 2025-07-12 18:42:42 +02:00
Sam Brannen ff1e5a87b3 Introduce ContextRestartedEvent as a subtype of ContextStartedEvent
Prior to this commit, there was no way to differentiate between an
ApplicationContext "start" and "restart" in terms of events. This was
due to the fact that a ContextStartedEvent was fired for both
AbstractApplicationContext.start() and
AbstractApplicationContext.restart().

To assist developers who may wish to differentiate between "start" and
"restart" events, this commit introduces a new ContextRestartedEvent as
a subtype of ContextStartedEvent. In addition,
AbstractApplicationContext.restart() now publishes a
ContextRestartedEvent instead of a ContextStartedEvent.

By making ContextRestartedEvent a subtype of ContextStartedEvent,
applications can still expect ContextStoppedEvent/ContextStartedEvent
event pairs for consistent lifecycle semantics, and they can optionally
check if the ContextStartedEvent is a ContextRestartedEvent.
Alternatively, applications can explicitly react to a
ContextRestartedEvent.

See gh-35168
See gh-35171
Closes gh-35194
2025-07-12 18:14:05 +02:00
Sam Brannen 8eedfdf66a Polishing 2025-07-12 17:18:33 +02:00
Juergen Hoeller 64de254b58 Merge branch '6.2.x' 2025-07-11 22:50:47 +02:00
Brian Clozel b59dca9c7f Align HttpMessageConverters builder with WebFlux codecs variants
As of #33894, we introduced a new `HttpMessageConverters` API.
While this achieved our goal of focusing converters classpath detection
in a single place and avoiding waste, a single `HttpMessageConverters`
instance for both client and server added more complexity for developers.

This commit aligns the API here with the WebFlux `CodecsConfigurer` to
opt for a client/server flavor as the first step in the builder.
While this make the sharing of converter instances between server and
client impossible, this allows for a simpler API and separates concerns.

Closes gh-35187
2025-07-11 17:07:28 +02:00
Sam Brannen ddaf13b8ed Merge branch '6.2.x' 2025-07-11 15:52:54 +02:00
Juergen Hoeller 22a23322f3 Polishing 2025-07-10 20:05:47 +02:00
Juergen Hoeller e9c402cd0f Upgrade to Hibernate ORM 7.0.5 and Caffeine 3.2.1 2025-07-10 20:05:13 +02:00
Juergen Hoeller 4ca8a8abbe Merge branch '6.2.x'
# Conflicts:
#	framework-docs/modules/ROOT/pages/core/null-safety.adoc
#	framework-docs/modules/ROOT/pages/core/validation/error-code-resolution.adoc
#	framework-docs/modules/ROOT/pages/integration/cds.adoc
#	framework-docs/modules/ROOT/pages/integration/jms/sending.adoc
#	framework-docs/modules/ROOT/pages/integration/rest-clients.adoc
#	framework-docs/modules/ROOT/pages/languages/kotlin/bean-definition-dsl.adoc
#	framework-docs/modules/ROOT/pages/languages/kotlin/null-safety.adoc
#	framework-docs/modules/ROOT/pages/languages/kotlin/web.adoc
#	framework-docs/modules/ROOT/pages/web/webflux/config.adoc
#	framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc
#	framework-docs/modules/ROOT/pages/web/webmvc/mvc-http2.adoc
2025-07-10 19:42:14 +02:00
Juergen Hoeller 481a74a202 Add reference documentation for @Retryable and @ConcurrencyLimit
See gh-35133
See gh-34529
2025-07-10 17:14:08 +02:00
Juergen Hoeller 200934c673 Add reference documentation for JmsClient next to JmsTemplate
See gh-32501
2025-07-10 17:13:58 +02:00
Juergen Hoeller a3e9f0c16d Add bindSynchronizedResource with automatic unbinding after transaction completion
Closes gh-35182
2025-07-10 17:13:51 +02:00
Brian Clozel 0a705f467d Configure custom converters ahead in HttpMessageConverters
This commit aligns `HttpMessageConverters` with the WebFlux codecs
configuration by adding custom converters first, before the
auto-detected and well-known ones.

This is a general approach in Spring Framework, where custom
implementations are more likely to handle specific uses cases and should
be involved before considering the more general implementations.

Fixes gh-35177
2025-07-10 16:56:06 +02:00
Sam Brannen 440bf94cee Improve URLs in Validation chapter of the reference manual
In order to improve the user experience with URLs for sections of the
Validation chapter, this commit makes the following changes to page
names in the "validation" folder.

- beans-beans.html --> data-binding.html

- conversion.html --> error-code-resolution.html

Some of the section anchors in data-binding.html have also been
renamed. For example, #beans-beans is now #data-binding-property-binding.

Closes gh-35181
2025-07-10 14:03:28 +02:00
Sam Brannen cc59acb7ab Fix type conversion example 2025-07-10 12:16:50 +02:00
Sam Brannen 7d394a0564 Merge branch '6.2.x' 2025-07-10 11:53:38 +02:00
Sébastien Deleuze 197de07634 Document a NullAway limitation 2025-07-10 10:52:38 +02:00
Sébastien Deleuze b8015d87ef Use flexible generics nullness in RestClient ExchangeFunction
Closes gh-35180
2025-07-10 10:39:51 +02:00
Sam Brannen 78bf41ca83 Merge branch '6.2.x' 2025-07-09 17:41:53 +02:00
rstoyanchev 47d9182f56 Merge branch '6.2.x' 2025-07-09 12:51:37 +01:00
Sam Brannen 7ea619aefb Merge branch '6.2.x' 2025-07-09 12:56:33 +02:00
rstoyanchev 99e4815d9e Merge branch '6.2.x' 2025-07-09 11:03:49 +01:00
rstoyanchev c23edae4db HttpRequestValues.Processor exposes MethodParameter[]
Closes gh-35148
2025-07-09 10:54:46 +01:00
Juergen Hoeller 523552ac2e Introduce ConfigurableApplicationContext.restart() method
Closes gh-35171
2025-07-08 18:50:05 +02:00
Sébastien Deleuze b48da4c0c2 Upgrade to Kotlin Serialization 1.9.0
See gh-34453
2025-07-08 12:33:04 +02:00
Sébastien Deleuze 2d7323bb7f Update Spring MVC message converters documentation
Closes gh-35166
2025-07-07 18:15:44 +02:00
Sébastien Deleuze a61b297967 Specify flexible generics nullness in spring-jdbc
This commit leverages flexible generics nullness at method and
type level when relevant in spring-jdbc.

Due to https://github.com/uber/NullAway/issues/1075, some related
`@SuppressWarnings("NullAway")` have been added.

JdbcOperations Kotlin extensions have been refined accordingly.

Closes gh-34911
2025-07-07 16:35:25 +02:00
Juergen Hoeller 2b56b759af Fix JmsClient visibility
See gh-32501
2025-07-07 16:06:28 +02:00
Sam Brannen 2f202ffcde Add compileOnly dependency on JSR-305 annotations for Reactor
After the upgrade to Selenium 4.33.0 in commit 1051592ae8, the
spring-test module began to fail as follows.

/home/runner/.gradle/caches/modules-2/files-2.1/io.projectreactor/reactor-core/3.8.0-M4/3195c7882f5833915a74ee18d58857cabc29b4c6/reactor-core-3.8.0-M4.jar(/reactor/util/annotation/Nullable.class):
  warning: Cannot find annotation method 'when()' in type 'Nonnull':
    class file for javax.annotation.Nonnull not found
warning: unknown enum constant When.MAYBE
  reason: class file for javax.annotation.meta.When not found
error: warnings found and -Werror specified
1 error
2 warnings

To address that, this commit introduces a compileOnly dependency on
"com.google.code.findbugs:jsr305".
2025-07-07 15:57:14 +02:00
Sam Brannen b1222ccab7 Polish contribution
See gh-35086
2025-07-07 15:37:24 +02:00
Renato Mameli b901afffd0 Fix consumes handling for interface @RequestBody
Previously, @RequestBody(required = false) annotations declared
on interface methods were ignored when resolving the consumes
condition. This caused mappings to incorrectly require a request
body with a Content-Type such as application/json, even when no
body was provided.

This change uses AnnotatedMethod to retrieve parameter annotations
from both the implementation and its interfaces, ensuring that the
required flag is respected and body presence is evaluated correctly.

Closes gh-35086

Signed-off-by: Renato Mameli <renatomamel410@gmail.com>
2025-07-07 15:34:40 +02:00
Juergen Hoeller a2d495de9f Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
#	spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java
2025-07-07 14:40:50 +02:00
Juergen Hoeller 9406e7ee2a Add additional javadoc notes on 7.0
See gh-34709
See gh-34757
2025-07-07 14:08:43 +02:00
Juergen Hoeller 56f16a8817 Add usage examples to JmsClient javadoc
See gh-32501
2025-07-07 14:08:33 +02:00
Yanming Zhou 4969f6b742 Improve BeanFactoryExtensionsTests
Comparing to Java's `BeanFactory.getBean(Class<T> requiredType)`, Kotlin's `BeanFactory.getBean<T>()` supports generic type as `T`, this commit add test to cover that and add assertions.

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-07-07 13:38:02 +02:00
Yanming Zhou 410a9ce108 Mark applicable Scope's methods as default
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-07-07 13:37:47 +02:00
Yanming Zhou 88257f7dfd Discard further rows once maxRows has been reached
See https://github.com/spring-projects/spring-framework/issues/34666#issuecomment-2773151317

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-07-07 13:37:31 +02:00
NeatGuyCoding d957f8bb5d Fix copy-n-paste errors in JmsClient Javadoc
Closes gh-35163

Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-07-07 12:41:35 +02:00
Sam Brannen 14767d64b5 Merge branch '6.2.x' 2025-07-07 12:36:14 +02:00
Sam Brannen a80305ee71 Skip initialization of a NullBean
Prior to this commit, AbstractAutowireCapableBeanFactory's
initializeBean() method always attempted to initialize a NullBean.

However, invokeInitMethods() (which is invoked by initializeBean())
skips processing of a NullBean, which is logical since a NullBean will
never contain init-methods.

In practice, initialization and post-processing of a NullBean should
not result in any change to the NullBean.

This commit therefore skips initialization of a NullBean altogether.

Closes gh-35165
2025-07-07 11:12:28 +02:00
rstoyanchev 1982c7e020 Support 404 handling for HttpExchange interfaces
Closes gh-32105
2025-07-07 09:12:22 +01:00
rstoyanchev 340468cf4b Use toString for WebFilter checkpoint
Closes gh-34702
2025-07-07 09:12:22 +01:00
Sam Brannen 19ce8c3d01 Merge branch '6.2.x' 2025-07-05 14:10:41 +02:00
Sam Brannen 32b56a35c6 Short-circuit matching algorithm in InstanceFilter
In commit 97522cfa36, I implemented a
short-circuiting matching algorithm in DefaultRetryPolicy for includes
and excludes, which was later copied to MethodRetrySpec.

After we switched to using ExceptionTypeFilter, I realized that the
matching algorithm in InstanceFilter (the superclass of
ExceptionTypeFilter) does not exhibit the same short-circuiting
characteristics.

In light of that, this commit revises the matching algorithm in
InstanceFilter to mirror the original short-circuiting algorithm in
DefaultRetryPolicy.

See gh-35058
See gh-35109
See gh-35160
Closes gh-35161
2025-07-05 13:13:52 +02:00
Sam Brannen 17df4b4c38 Support direct matching against exceptions in ExceptionTypeFilter
Prior to this commit, ExceptionTypeFilter only supported matching
against an exception type. However, most use cases involve matching
against an exception instance. Moreover, every use case within the core
Spring Framework uses ExceptionTypeFilter to match against concrete
exception instances.

This commit therefore introduces an overloaded match(Throwable) method
in ExceptionTypeFilter in order to provide support for the most common
use cases.

See gh-35109
Closes gh-35160
2025-07-05 13:13:47 +02:00
Sam Brannen 33f51b183d Add missing tests for ExceptionTypeFilter 2025-07-05 12:15:14 +02:00
Juergen Hoeller 0111329214 Consistently introspect constructor-provided JmsTemplate
See gh-32501
2025-07-04 21:50:20 +02:00
Juergen Hoeller 8cb901825b Merge branch '6.2.x'
# Conflicts:
#	spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
#	spring-jms/src/main/java/org/springframework/jms/core/JmsTemplate.java
#	spring-messaging/src/main/java/org/springframework/messaging/core/AbstractDestinationResolvingMessagingTemplate.java
#	spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessageReceivingTemplate.java
#	spring-messaging/src/main/java/org/springframework/messaging/core/AbstractMessagingTemplate.java
#	spring-messaging/src/main/java/org/springframework/messaging/core/MessageRequestReplyOperations.java
#	spring-messaging/src/main/java/org/springframework/messaging/core/MessageSendingOperations.java
2025-07-04 18:31:13 +02:00
Sam Brannen d510b738f4 Match if empty by default in InstanceFilter and ExceptionTypeFilter
Prior to this commit, the constructors for InstanceFilter and
ExceptionTypeFilter required one to supply the matchIfEmpty flag.
However, users will typically want that to be true. Moreover, we always
supply true for the matchIfEmpty flag within the Spring Framework.

This commit therefore makes the matchIfEmpty flag optional by
introducing overloaded constructors for InstanceFilter and
ExceptionTypeFilter that only accept the includes and excludes
collections.

In addition, this commit overhauls the Javadoc for InstanceFilter and
ExceptionTypeFilter, fixing several issues in the documentation.

Furthermore, this commit applies consistent @⁠Nullable declarations
in ExceptionTypeFilter.

Closes gh-35158
2025-07-04 18:16:52 +02:00
Sam Brannen 46c40e7b96 Require explicit constraints in @⁠Contract
Prior to this commit, the value attribute in @⁠Contract was declared as
follows.

    String value() default "";

That allowed empty declarations such as @⁠Contract or @⁠Contract();
however, a contract is not useful without declared constraints.

To address that, this commit removes the `default ""` declaration in
order to force users to provide explicit constraints.

Although one could technically still declare the annotation without
constraints via @⁠Contract(""), it's unlikely that anyone would
intentionally do that.

Closes gh-35157
2025-07-04 18:16:52 +02:00
Juergen Hoeller 6dc3c11828 Introduce JmsClient with configurable settings per operation
Closes gh-32501
Closes gh-26840
2025-07-04 17:36:33 +02:00
Juergen Hoeller 842f582afc Specify fetchSize/maxRows/queryTimeout per statement in JdbcClient
Closes gh-35155
2025-07-04 17:36:18 +02:00
Sam Brannen c9a01051c9 Merge branch '6.2.x' 2025-07-04 17:19:14 +02:00
Sam Brannen cf06efece6 Merge branch '6.2.x' 2025-07-04 11:49:10 +02:00
Sam Brannen 6865380f97 Fix "liver" typo 2025-07-03 18:56:30 +02:00
rstoyanchev ff707d0ccb Add UserWebTestClientConfigurer
Closes gh-35042
2025-07-03 17:11:11 +01:00
rstoyanchev 1b30b469c4 Make SslInfo nullable
This allows autowiring a MockServerSpec in test class and using a different
identity or none at all with each test.

Polishing in MockServerSpecTests.

See gh-35042
2025-07-03 17:11:11 +01:00
Sam Brannen 6091453feb Introduce value alias for cacheNames in @⁠CacheConfig
Prior to this commit @⁠CacheConfig did not have a `value` attribute
alias for `cacheNames`, even though the rest of the cache-related
annotations (such as @⁠Cacheable, @⁠CachePut, etc.) do have a `value` /
`cacheNames` alias pair.

To address that inconsistency, this commit introduces a `value` alias
for `cacheNames` in @⁠CacheConfig as well.

See gh-35096
Closes gh-35152
2025-07-03 17:16:29 +02:00
Sam Brannen c6a8df4a9d Use Duration.ZERO whenever possible 2025-07-03 16:55:09 +02:00
Sam Brannen 58061ae295 Polish contribution
See gh-35109
2025-07-03 16:49:40 +02:00
Mengqi Xu 489ebd2438 Use ExceptionTypeFilter to filter includes & excludes for retry policies
This commit reduces code duplication by reusing the logic already
available in ExceptionTypeFilter.

Closes gh-35109

Signed-off-by: Mengqi Xu <2663479778@qq.com>
2025-07-03 16:49:40 +02:00
Sam Brannen 132836f6ca Add missing "includes mismatch" test in ReactiveRetryInterceptorTests
This commit also overhauls ReactiveRetryInterceptorTests to make the
tests more robust and simultaneously easier to comprehend.
2025-07-03 16:37:57 +02:00
Sam Brannen 27072ccb87 Improve wording 2025-07-03 14:17:43 +02:00
rstoyanchev 26d413c521 Update router function docs for API versioning
Closes gh-35113
2025-07-02 15:09:32 +01:00
Sébastien Deleuze 701e034c0e Improve null-safety documentation related to TYPE_USE
This commit refines the null-safety documentation to document more
explicitly the code style guidelines related to
`@Target(ElementType.TYPE_USE)`.

Closes gh-35098
2025-07-02 15:28:51 +02:00
Sam Brannen 0f495d3b64 Remove obsolete Javadoc reference
See gh-35144
2025-07-02 11:47:12 +02:00
Sam Brannen b58c1c0d63 Assert actual Reactive exception types thrown in ReactiveRetryInterceptorTests 2025-07-02 11:27:50 +02:00
Sam Brannen 191d092952 Polishing 2025-07-02 11:26:34 +02:00
Juergen Hoeller 196b7ec275 Deprecate (Jdbc)DaoSupport classes (including JmsGatewaySupport)
Closes gh-35145
2025-07-02 11:12:57 +02:00
Juergen Hoeller 46654a03fe Replace lenient fallback with assertion for actual annotation present
See gh-35133
2025-07-02 11:09:53 +02:00
Sam Brannen b794abd8cb Polishing 2025-07-02 10:58:50 +02:00
Sam Brannen 5cae769c2d Remove maxDuration/maxElapsedTime support from RetryPolicy
When the core retry functionality was introduced, it had a built-in
MaxRetryDurationPolicy. In #35058, that was migrated to a
withMaxDuration() factory method, and in #35110 that was renamed to
withMaxElapsedTime() (with a corresponding maxElapsedTime() method on
the builder) in order to align with the maxElapsedTime feature of
ExponentialBackOff. The latter also changed the semantics of the
feature in the context of the RetryPolicy.

However, @⁠Retryable does not provide maxElapsedTime support.

In addition, the maxElapsedTime feature is a bit misleading, since it
does not actually track CPU time or wall-clock time but rather only the
sum of individual, accumulated back-off intervals/delays, which is
likely not very useful. Furthermore, the maxElapsedTime will never
apply to a zero-valued delay/interval.

In light of the above, this commit removes the maxElapsedTime support
from the built-in RetryPolicy.

Users can still implement a custom BackOff strategy if they find they
need some form of "max elapsed time" or "max duration".

See gh-34716
See gh-35058
See gh-34529
See gh-35110
Closes gh-35144
2025-07-02 10:18:36 +02:00
Juergen Hoeller b256babad5 Polishing 2025-07-01 18:01:39 +02:00
Juergen Hoeller 95c35e9655 Fix javadoc links to @Retryable
See gh-34529
See gh-35133
2025-07-01 18:00:59 +02:00
Juergen Hoeller 95a6a0ceaf Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/format/datetime/standard/DurationFormatterUtils.java
2025-07-01 17:57:49 +02:00
Sam Brannen cc31bf3c33 Accept zero for RetryPolicy.Builder.delay()
This aligns the programmatic RetryPolicy configuration option with the
delay support in @⁠Retryable.

See gh-35110
2025-07-01 17:40:15 +02:00
Juergen Hoeller c9078bfe14 Introduce @ConcurrencyLimit annotation based on ConcurrencyThrottleInterceptor
Moves @Retryable infrastructure to resilience package in spring-context module.
Includes duration parsing and placeholder resolution for @Retryable attributes.
Provides convenient @EnableResilientMethods for @Retryable + @ConcurrencyLimit.

Closes gh-35133
See gh-34529
2025-07-01 17:27:50 +02:00
rstoyanchev 3ce7613195 Add version deprecation tests for router functions
Given the move of ApiVersionStrategy support to AbstractHandlerMapping,
deprecation should already work. We only need tests to show it.

See gh-35113
2025-07-01 11:37:34 +01:00
rstoyanchev 86f50b20f2 Move ApiVersionStrategy up to AbstractHandlerMapping
Similar to CorProcessor, ApiVersionStrategy is now supported at the
AbstractHandlerMapping level.

See gh-35113
2025-07-01 11:37:34 +01:00
Sam Brannen 93a9c9b8bf Merge branch '6.2.x' 2025-07-01 11:29:45 +02:00
Sébastien Deleuze fb214bb74a Merge branch '6.2.x' 2025-07-01 11:02:54 +02:00
Sébastien Deleuze 9cb9a865c2 Upgrade SDKMAN to Java 24.0.1 2025-07-01 11:02:44 +02:00
NeatGuyCoding 009b880e92 Fix potentially loses precision and jitter is not well capped with unit tests
Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-07-01 10:56:53 +02:00
NeatGuyCoding eeedeb3b10 Remove the duplicated “rss” assertion
Closes gh-35139
Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
2025-07-01 10:21:48 +02:00
Sam Brannen 60b19278c0 Merge branch '6.2.x' 2025-06-30 17:39:17 +02:00
rstoyanchev 1a9f19f87f Update use of preset content-type for streaming
For 7.0 we can favor more explicitly a preset Content-type.

Closes gh-35130
2025-06-30 15:40:33 +01:00
rstoyanchev 817136a0e9 Merge branch '6.2.x' 2025-06-30 15:35:29 +01:00
Stéphane Nicoll 6a3311ba8e Merge branch '6.2.x' 2025-06-30 12:54:07 +02:00
Sébastien Deleuze 0e11dbfcca Use Java 24 instead of Java 23 in the CI Github action
To fix the broken build, and to focus on testing the Java
LTS versions and the latest one.
2025-06-30 12:01:34 +02:00
Sam Brannen 769ba9e23b Merge branch '6.2.x' 2025-06-29 17:42:35 +02:00
Sam Brannen 5513139ef5 Clean up warnings and revise for consistency 2025-06-29 16:47:53 +02:00
Sam Brannen bb7c497bdd Remove obsolete code from internal HibernateTransactionObject
See gh-35111
2025-06-29 16:33:01 +02:00
Sam Brannen b211ac1f4a Resolve warning in CachingMetadataReaderFactoryTests 2025-06-29 16:28:09 +02:00
Sam Brannen ec16b03949 Support navigation to failed tests in @⁠Inject TCK tests
See gh-35126
2025-06-29 15:55:07 +02:00
Sam Brannen ed86daa080 Convert Spring @⁠Inject TCK tests from JUnit 3 to JUnit Jupiter
Closes gh-35126
2025-06-28 19:29:49 +02:00
Sam Brannen ad278cd52e Fix ExponentialBackOffTests 2025-06-28 19:29:49 +02:00
Sam Brannen 4cdfd90882 Polish backoff and retry support
This revises commit 15dd320b95.

See gh-34529
See gh-35110
2025-06-28 19:14:45 +02:00
Juergen Hoeller 96f0399072 Reintroduce FixedBackOff(long) constructor
Effectively removing FixedBackOff(Duration) only.

See gh-35028
See gh-35110
2025-06-28 12:11:02 +02:00
Juergen Hoeller 15dd320b95 Consistent maxAttempts (long) and delay/maxDelay (Duration) declarations
Includes timeUnit attribute in @Retryable (aligned with @Scheduled).

See gh-34529
See gh-35110
2025-06-28 11:40:00 +02:00
Sam Brannen bcdf26d492 Redesign RetryPolicy to directly incorporate BackOff
After experimenting with our newly introduced core retry support
(RetryPolicy, RetryTemplate, etc.) and @⁠Retryable support, it
became apparent that there are overlapping concerns between the current
RetryPolicy and BackOff contracts.

- RetryPolicy and BackOff both have stateful executions: RetryExecution
  and BackOffExecution. However, only one stateful execution is
  necessary.

- FixedBackOff and ExponentialBackOff already incorporate "retry" logic
  in terms of max attempts, max elapsed time, etc. Thus, there is no
  need to duplicate such behavior in a RetryPolicy and its
  RetryExecution.

- RetryTemplate currently accepts both a RetryPolicy and a BackOff in
  order to instrument the retry algorithm. However, users would
  probably rather focus on configuring all "retry" logic via a single
  mechanism.

In light of the above, this commit directly incorporates BackOff
in RetryPolicy as follows.

- Remove the RetryExecution interface and move its shouldRetry() method
  to RetryPolicy, replacing the current RetryExecution start() method.

- Introduce a default getBackOff() method in the RetryPolicy interface.

- Introduce RetryPolicy.withDefaults() factory method.

- Completely overhaul the RetryPolicy.Builder to provide support for
  configuring a BackOff strategy.

- Remove BackOff configuration from RetryTemplate.

- Revise the method signatures of callbacks in RetryListener.

The collective result of these changes can be witnessed in the
reworked implementation of AbstractRetryInterceptor.

RetryPolicy retryPolicy = RetryPolicy.builder()
		.includes(spec.includes())
		.excludes(spec.excludes())
		.predicate(spec.predicate().forMethod(method))
		.maxAttempts(spec.maxAttempts())
		.delay(Duration.ofMillis(spec.delay()))
		.maxDelay(Duration.ofMillis(spec.maxDelay()))
		.jitter(Duration.ofMillis(spec.jitter()))
		.multiplier(spec.multiplier())
		.build();

RetryTemplate retryTemplate = new RetryTemplate(retryPolicy);

See gh-34716
See gh-34529
See gh-35058
Closes gh-35110
2025-06-27 17:28:10 +02:00
rstoyanchev 5a6c019413 Support for functional routing by API version
See gh-35113
2025-06-27 16:22:44 +01:00
rstoyanchev 224f1af08e Prepare to support API versioning for fn
Add default method to resolve, parse, and validate version
Simplify tests
2025-06-27 16:22:44 +01:00
rstoyanchev d045f44693 Polishing in RequestMappingHandlerMapping 2025-06-27 16:22:44 +01:00
Sam Brannen 7cc29d2019 Revise naming and docs for "jitter" and "multiplier" in AOP retry support
See gh-34529
2025-06-27 16:17:40 +02:00
Sam Brannen 98b29b5e37 Consistently implement toString() in BackOff strategies
Closes gh-35120
2025-06-27 16:10:55 +02:00
Sam Brannen d97288a74e Improve Javadoc and tests for BackOff strategies 2025-06-27 16:04:32 +02:00
Brian Clozel 28f9adf88e Simplify media files detection in WebMvcConfigurationSupport
Prior to this commit, `WebMvcConfigurationSupport` would configure file
extensions/media types registrations based on classpath detection.
Since gh-33894, the detection of message converters is located in a
single place, `HttpMessageConverters`.

This commit updates the `WebMvcConfigurationSupport` to use the actual
message converters configured to decide which file extensions should be
set up for content negotiation.

See gh-33894
2025-06-27 15:06:32 +02:00
Juergen Hoeller 02ff681c73 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
#	spring-beans/src/test/java/org/springframework/beans/factory/BeanFactoryUtilsTests.java
2025-06-27 12:31:46 +02:00
Juergen Hoeller 15209dd2a7 Upgrade to Hibernate ORM 7.0.3 and EclipseLink 5.0.0-B08
See gh-33750
2025-06-27 11:26:34 +02:00
Brian Clozel da124a9e89 Make HttpMessageConverters classpath detection static
Prior to this commit, the classpath detection of various
`HttpMessageConverter` types was using an instance `ClassLoader`. The
main goal here was to provide the feature and being able to test it with
filtered classloaders.

It seems this approach fails with GraalVM and we need to ensure that
classpath detection is performed at class loading time for our GraalVM
feature (inlining such static booleans at build time).
As a result, we need to remove the tests for classpath detection.

See gh-33894
2025-06-27 10:10:40 +02:00
Brian Clozel 7e919d2c96 Reorder multipart converter for server converters
Closes gh-33894
2025-06-27 09:30:34 +02:00
Brian Clozel beedf0a76b Use HttpMessageConverters in client and server config
This commit uses the new `HttpMessageConverters` class for the HTTP
client (`RestTemplate` and `RestClient`) and HTTP server support.

This effectively removes the duplication of classpath detection for
message converters in multiple places: clients, server and the multipart
converter itself.
Instead of creating multiple instances of the same converters, this
allows applications to share converter instances as much as possible for
better memory efficiency.

As a result, this change also deprecates configuration methods in the
MVC support that are superseded by the new methods introduced for
`HttpMessageConverters` support.

Closes gh-33894
2025-06-26 17:19:33 +02:00
Brian Clozel 1af25e9cb1 Add HttpMessageConverters
Prior to this commit, Spring Web would configure
`HttpMessageConverter<?>` collections on clients like `RestTemplate` and
on the server infrastructure, in `WebMvcConfigurationSupport`.

This commit introduces a high-level construct for building and
configuring ordered collections of converters.

This includes:
* configuration of well-known converters with classpath detection
* configuration of shared converters, or client/server specific
* configuration of custom converters

See gh-33894
2025-06-26 17:19:33 +02:00
Juergen Hoeller 4b44a34692 Complete treatment of RuntimeBeanReference in BeanDefinitionValueResolver
See gh-35101
2025-06-26 17:15:31 +02:00
Stefano Cordio f7fef93842 Refine nullability of MethodInvoker#setArguments
Closes gh-35089
Signed-off-by: Stefano Cordio <stefano.cordio@gmail.com>
2025-06-26 15:04:49 +02:00
Juergen Hoeller 841d9fb73b Add public method to get bean order on DefaultListableBeanFactory
Closes gh-34712
2025-06-26 14:48:07 +02:00
Juergen Hoeller c5da405314 Consistent type-based bean lookup for RuntimeBeanReference
See gh-35101
2025-06-26 14:47:54 +02:00
Juergen Hoeller 06ef82e9a5 Consistent type-based bean lookup for internal resolution paths
Includes additional tests for List/ObjectProvider dependencies.

See gh-35101
2025-06-26 12:51:55 +02:00
Juergen Hoeller 2e9e45ee55 Restore translation of IllegalArgumentException for JPA
See gh-35111
2025-06-25 22:39:18 +02:00
Juergen Hoeller b3dc75265d Merge branch '6.2.x' 2025-06-25 22:36:44 +02:00
Brian Clozel 6e6280a42c Disallow @org.jetbrains.annotations.Nullable imports
This commit adds a checkstyle rule that rejects
`@org.jetbrains.annotations.Nullable` imports in the source code.

See gh-35114
2025-06-25 20:43:48 +02:00
Tran Ngoc Nhan 1a046f9cec Fix Nullable import in ClassFileAnnotationMetadata
Closes gh-35114

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2025-06-25 20:43:09 +02:00
Brian Clozel 2fa25b50d9 Fix caching operations in CachingMetadataReaderFactory
gh-33616 refactored `CachingMetadataReaderFactory` and broke the
behavior as it bypassed the cache for `getMetadataReader(String
className)` operations.

This commit restores the original behavior.

Fixes gh-35112
2025-06-25 20:32:38 +02:00
Juergen Hoeller b3a5473bc7 Merge branch '6.2.x'
# Conflicts:
#	framework-docs/modules/ROOT/pages/data-access/orm/hibernate.adoc
#	spring-orm/src/main/java/org/springframework/orm/hibernate5/package-info.java
#	spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaDialect.java
#	spring-orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaVendorAdapter.java
2025-06-25 19:08:30 +02:00
Juergen Hoeller 543314fcbb Polishing 2025-06-25 18:07:24 +02:00
Juergen Hoeller d47f1a1749 Migrate orm.hibernate5 to orm.jpa.hibernate package for Hibernate ORM 7.0
Closes gh-35111
2025-06-25 18:07:15 +02:00
Sam Brannen f3f05da39b Refer to Spring Retry project in Javadoc 2025-06-25 16:38:48 +02:00
rstoyanchev e508dea82d Merge branch '6.2.x' 2025-06-25 12:45:04 +01:00
rstoyanchev 40eb9c2c81 Add docs for API version deprecation support
Closes gh-35049
2025-06-25 12:03:35 +01:00
rstoyanchev 482cfb0b18 Add detectSupportedVersions in spring-webmvc
Closes gh-35105
2025-06-25 12:03:35 +01:00
rstoyanchev 3cb8a833e4 Polishing API versioning ref docs 2025-06-25 12:03:35 +01:00
rstoyanchev 785aab8ad5 Rename ApiDeprecationHandler to insert "Version"
The name is a bit long, but it is necessary to indicate it's a handler
for a deprecation version, and the decision is based on the version,
not an individual endpoint.

See gh-35049
2025-06-25 12:03:35 +01:00
Sam Brannen 7606a929c9 Fail build for JUnit discovery issues
JUnit 5.13 introduced support for Discovery Issues which typically
indicate configuration errors in tests that may result in unexpected
behavior.

Furthermore, discovery issues that are currently reported at INFO level
may later be reported at WARNING or ERROR level -- for example, in
JUnit 6.

In order to ensure that our test suite does not suffer from such
potential errors, this commit sets the
junit.platform.discovery.issue.severity.critical JVM system property to
INFO (instead of leaving it with the default ERROR configuration).

Doing so aligns with our build configuration which fails the build for
selected warnings in Java source code and Javadoc.

If we later determine that INFO causes unnecessary issues for us, we
can switch to WARNING.

This commit also removes two "intentionally invalid" test cases from
AutowiredConfigurationErrorsIntegrationTests, since those test cases
are now reported as invalid as of JUnit 5.13.

Closes gh-35107
2025-06-25 11:25:29 +02:00
Sam Brannen ad2b7f4d01 Merge branch '6.2.x' 2025-06-25 10:23:28 +02:00
Juergen Hoeller e828bbbb0a Invert order of suppressed exceptions (for common exception rendering)
See gh-35057
2025-06-24 22:22:45 +02:00
Juergen Hoeller 90c875144a Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/context/aot/BeanFactoryInitializationAotContributions.java
#	spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotGeneratorTests.java
#	spring-orm/src/main/java/org/springframework/orm/hibernate5/HibernateQueryException.java
2025-06-24 22:01:58 +02:00
Juergen Hoeller 04f3975e0f Support for qualified EntityManager/EntityManagerFactory injection (JPA 3.2)
Closes gh-33414
2025-06-24 18:51:18 +02:00
Juergen Hoeller b0eacd22e0 Support for exposing additional object types in SmartFactoryBean
Closes gh-35101
2025-06-24 18:51:04 +02:00
Sam Brannen 3bf9b0de72 Merge branch '6.2.x' 2025-06-24 16:14:19 +02:00
Sébastien Deleuze 839d3a7d44 Refine nullability of PropertyResolver.getProperty(key: String)
Closes gh-35104
2025-06-24 16:06:32 +02:00
Sébastien Deleuze 294406dae9 Remove @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
Fixed in Kotlin 2.2.0 and IntelliJ IDEA IDEA 2024.2 EAP, see
https://youtrack.jetbrains.com/issue/KT-75169 related issue.

See gh-34453
2025-06-24 11:40:23 +02:00
rstoyanchev 3dfb6a7c0b Fix failing test 2025-06-23 18:20:59 +01:00
rstoyanchev ffdf941219 Resolve API version in RequestMappingHandlerMapping
API version resolution and parsing is already applied as long as
an ApiVersionStrategy is configured and irrespective of whether
a given RequestMapping has a version or not.

RequestMappingHandlerMapping also needs to be aware of the API version
in order to apply deprecated version handling. So it is better to
resolve, parse, and validate the version in the beginning of
handler mapping rather than in the first call to any
VersionRequestCondition.

Closes gh-35049
2025-06-23 18:03:56 +01:00
rstoyanchev 492e51f3ba Add handling of deprecated API versions
See gh-35049
2025-06-23 18:03:56 +01:00
rstoyanchev 0eec1dc636 Consistently validate API version
Closes gh-35082
2025-06-23 18:03:56 +01:00
rstoyanchev a0f9872746 Refactor construction of VersionRequestCondition
The single constructor now supports all combinations of having a version
attribute set or not, and ApiVersionStrategy, configured or not.

In effective, ensure the configured ApiVersionStrategy is passed even
when the RequestMapping version attribute is not set.

See gh-35082
2025-06-23 18:03:56 +01:00
rstoyanchev 5d34f9c87e Support API versioning via MediaType parameter
Closes gh-35050
2025-06-23 18:03:55 +01:00
Sébastien Deleuze ba9bef6bbf Upgrade to Kotlin 2.2.0
Kotlin 2.2 is the new baseline for Spring Framework 7.0.

-Xannotation-default-target=param-property is specified to avoid
warnings when compiling tests or documentation snippets. It is
expected to become the default behavior in an upcoming version
of Kotlin, see https://youtrack.jetbrains.com/issue/KT-73255 for
more details.

Closes gh-34453
2025-06-23 18:11:06 +02:00
Sébastien Deleuze fee873d8d2 Update JUnit javadoc link
Otherwise the build is broken by a redirect.
2025-06-23 17:33:17 +02:00
Juergen Hoeller f36fec1651 Upgrade to Hibernate ORM 7.0.2 and Hibernate Validator 9.0.1
Includes missing upgrade for Jetty EE11 support 12.1.0.beta1

See gh-33750
See gh-35084
2025-06-23 11:15:33 +02:00
Sam Brannen 12146c4a1b Clean up warning in Gradle build 2025-06-20 16:43:36 +02:00
Sam Brannen 7ffd4e7cf8 Sync test fixture MockServerHttpRequest implementation with original 2025-06-20 16:33:28 +02:00
Brian Clozel 8448dc90a4 Upgrade to Jetty 12.1.0.beta1
Closes gh-35084
2025-06-20 09:45:53 +02:00
Sam Brannen c17b481939 Fix link in Javadoc
See gh-35042
See gh-35078
2025-06-19 13:58:29 +02:00
Sam Brannen f478f5cdc8 Introduce factory methods in SslInfo and remove MockSslInfo
After further consideration, we have decided to remove the recently
introduced MockSslInfo in favor of introducing the following static
factory methods directly in the SslInfo interface.

- SslInfo.from(String sessionId)

- SslInfo from(String sessionId, X509Certificate... peerCertificates)

See gh-35042
See gh-35078
2025-06-19 13:39:31 +02:00
Sam Brannen 1fb04cb83a Add support for configuring SslInfo in WebTestClient
Prior to this commit, there was no easy way to configure an SslInfo
instance for use with WebTestClient.

To address that, this commit introduces a new sslInfo(SslInfo) method
in WebTestClient.MockServerSpec, which can be used as follows.

var client = WebTestClient.bindToApplicationContext(context)
                          .sslInfo(new MockSslInfo("mock ID"))
                          // ...
                          .build();

Closes gh-35042
2025-06-19 12:48:03 +02:00
Sam Brannen 4375e59a28 Polish WebTestClient ApplicationContext tests
Prerequisite for gh-35042
2025-06-19 11:57:56 +02:00
Sam Brannen 9ca7b623aa Introduce MockSslInfo
Closes gh-35078
2025-06-19 11:54:12 +02:00
rstoyanchev a2b90d9e9a Add HttpExchangeAdapter decoration
Closes gh-35059
2025-06-18 15:32:40 +01:00
Sam Brannen 0e84761871 Return Builder from sslInfo() builder method for MockServerHttpRequest
Prior to this commit, the sslInfo() method in MockServerHttpRequest's
BaseBuilder returned void, which prevented it from being used with the
intended fluent Builder pattern.

This commit changes the return type to the builder (B) for proper method
chaining.

Closes gh-35075
2025-06-18 13:19:43 +02:00
WonYong Hwang 5d0fc72eb2 Document intention of toString() in HandlerMethod
Document that HandlerMethod.toString() is used in log and error messages,
and that the returned description should typically include the method
signature of the underlying handler method for clarity and debugging.

Closes gh-35055

Signed-off-by: WonYong Hwang <111210881+wonyongg@users.noreply.github.com>
Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
2025-06-18 13:00:44 +02:00
Juergen Hoeller a265a135d5 Align package namespace in TaskManagementConfigUtils constants 2025-06-18 12:24:02 +02:00
Juergen Hoeller 6927e39e6b Merge branch '6.2.x' 2025-06-18 12:23:07 +02:00
Brian Clozel 0202d79232 Merge branch '6.2.x' 2025-06-17 17:19:35 +02:00
Sam Brannen c5fd57d92b Polish @⁠Retryable Javadoc and internals 2025-06-17 17:07:15 +02:00
Sébastien Deleuze f601bbb2ac Allow usage of @CheckReturnValue on types and ctors
Closes gh-34910
2025-06-17 16:53:12 +02:00
Sam Brannen 74ee1b991a Apply consistent copyright headers in Kotlin source code
See gh-35070
2025-06-17 16:24:15 +02:00
Spring Builds 16edf9867a Update copyright headers in source files
This commit updates Java, Kotlin, and Groovy source files to use the
"<year>-present" pattern in copyright headers.

Closes gh-35070
2025-06-17 16:23:50 +02:00
Sam Brannen 41f35ef6b3 Update configuration for copyright headers to use "<year>-present" pattern
Historically, we have used `<introduction year>-<modification year>` as
the pattern for copyright headers.

For example: `Copyright 2002-2025 the original author or authors.`

However, we have been encouraged to use `present` as the modification
year.

In light of that, this commit updates the following to enforce the new
pattern.

- The patterns in our SpringHeaderCheck Checkstyle rules
- The `Copyright 2002-${year}` template in org.eclipse.jdt.ui.prefs
- The update_copyright_headers.sh script

See gh-35070
2025-06-17 16:20:46 +02:00
Sam Brannen 485f0f82db Merge branch '6.2.x' 2025-06-17 16:10:46 +02:00
Juergen Hoeller f69df9b767 Introduce retry interceptor and annotation-based retry support
Based on RetryTemplate with ExponentialBackOff.
Includes optional jitter support in ExponentialBackOff.
Supports reactive methods through Reactor's RetryBackoffSpec.

Closes gh-34529
2025-06-17 12:49:29 +02:00
Johnny Lim cd5e4c2264 Fix typo in ProtobufHttpMessageConverterTests.canWrite()
See gh-34645
Closes gh-35062

Signed-off-by: Johnny Lim <izeye@naver.com>
2025-06-16 18:40:32 +02:00
Sam Brannen cc7dc47c4c Simplify suppressed exception assertions
See https://github.com/assertj/assertj/issues/3858
2025-06-16 16:32:24 +02:00
Brian Clozel 764d35c072 Merge branch '6.2.x' 2025-06-16 15:54:43 +02:00
Sam Brannen 6bbfd56dce Remove duplication in RetryTemplateTests 2025-06-16 14:32:33 +02:00
Sam Brannen f41a568b1d Improve Javadoc for RetryPolicy.Builder 2025-06-16 14:31:50 +02:00
Sam Brannen 09372b72ae Add retryWithExceptionExcludes() test 2025-06-16 13:33:10 +02:00
Sam Brannen 97522cfa36 Introduce Builder API and factory methods for RetryPolicy
Prior to this commit, we had three concrete RetryPolicy implementations.

- MaxRetryAttemptsPolicy
- MaxDurationAttemptsPolicy
- PredicateRetryPolicy

However, there was no way to combine the behavior of those policies.
Furthermore, the PredicateRetryPolicy was practically useless as a
standalone policy, since it did not have a way to end an infinite loop
for a Retryable that continually throws an exception which matches the
predicate.

This commit therefore replaces the current built-in RetryPolicy
implementations with a fluent Builder API and dedicated factory methods
for common use cases.

In addition, this commit also introduces built-in support for
specifying include/exclude lists.

Examples:

new MaxRetryAttemptsPolicy(5) -->

    RetryPolicy.withMaxAttempts(5)

new MaxDurationAttemptsPolicy(Duration.ofSeconds(5)) -->

    RetryPolicy.withMaxDuration(Duration.ofSeconds(5))

new PredicateRetryPolicy(IOException.class::isInstance) -->

    RetryPolicy.builder()
        .maxAttempts(3)
        .predicate(IOException.class::isInstance)
        .build();

The following example demonstrates all supported features of the builder.

RetryPolicy.builder()
    .maxAttempts(5)
    .maxDuration(Duration.ofMillis(100))
    .includes(IOException.class)
    .excludes(FileNotFoundException.class)
    .predicate(t -> t.getMessage().contains("Unexpected failure"))
    .build();

Closes gh-35058
2025-06-16 13:15:38 +02:00
Juergen Hoeller 945f3fb5ac Revise RetryTemplate for alignment with Reactor
Exposes last exception as cause in RetryException.
Applies first back-off after the initial exception.
Breaks out of retry loop on BackOffExecution.STOP.
Expects null result in Retryable and RetryListener.

Closes gh-35057
2025-06-16 12:05:25 +02:00
Brian Clozel 2aa0bad432 Merge branch '6.2.x' 2025-06-15 18:50:58 +02:00
Brian Clozel af7758cbc7 Configure CheckStyle rule for empty catch blocks
This commit configures a new CheckStyle rule that fails for empty
"catch" blocks, unless the exception is named "ignored" or "expected".

This also fixes the remaining instances missed by the previous commit.

Closes gh-35047
2025-06-15 16:11:48 +02:00
Vincent Potucek 0d4dfb6c1f Rename exception variables in empty catch blocks
The Spring codebase sometimes ignores exceptions in catch blocks on
purpose. This is often called out by an inline comment.
We should make this more obvious by renaming the exception argument in
the catch block to declare whether the exception is "ignored" or
"expected".

See gh-35047

Signed-off-by: Vincent Potucek <vpotucek@me.com>
[brian.clozel@broadcom.com: rework commit message]
Signed-off-by: Brian Clozel <brian.clozel@broadcom.com>
2025-06-15 16:11:42 +02:00
Sam Brannen cd3ac44fb0 Add test for CompositeRetryListener.addListener() 2025-06-15 15:23:43 +02:00
Sam Brannen 8dc9621ad7 Merge branch '6.2.x' 2025-06-14 15:35:09 +02:00
Brian Clozel 3da645f4b9 Merge branch '6.2.x' 2025-06-13 16:57:26 +02:00
rstoyanchev 00cc48dad4 Support repeatable multipart write
Closes gh-34859
2025-06-13 15:50:22 +01:00
Yanming Zhou d8ac3ff31f Fix typo in WebMvc.fn document
Closes gh-35045

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-06-13 10:03:07 +02:00
Brian Clozel cd80ca0fe0 Merge branch '6.2.x' 2025-06-13 09:57:18 +02:00
Brian Clozel f46a57f4f5 Merge branch '6.2.x' 2025-06-13 09:29:44 +02:00
Brian Clozel 309f850dad Use Java 24 for running Gradle
As of Gradle 8.14, Gradle is now compatible with Java 24 for running
Gradle.
2025-06-13 00:50:11 +02:00
Brian Clozel f111858055 Relax Java 24 toolchain requirements
While we choose our GitHub action to use Bellsoft Liberica, we should
relax that vendor requirement and ensure that contributors can build the
project with any Java 24 distribution.

Closes gh-35043
2025-06-13 00:49:05 +02:00
Stéphane Nicoll 75c4bc8947 Merge pull request #35038 from OlgaMaciaszek
* pr/35038:
  Polish "Add hints to instantiate HttpService group adapters"
  Add hints to instantiate HttpService group adapters

Closes gh-35038
2025-06-12 21:28:09 +02:00
Stéphane Nicoll 8bf9e0cbff Polish "Add hints to instantiate HttpService group adapters"
See gh-35038
2025-06-12 21:24:58 +02:00
Olga Maciaszek-Sharma 8142f80581 Add hints to instantiate HttpService group adapters
See gh-35038

Signed-off-by: Olga Maciaszek-Sharma <olga.maciaszek-sharma@broadcom.com>
2025-06-12 21:23:35 +02:00
Sam Brannen 082eb607ec Overhaul tests for RetryTemplate 2025-06-12 17:34:54 +02:00
Sam Brannen ff167aafa2 Make built-in RetryPolicy implementations final
Closes gh-35040
2025-06-12 17:34:54 +02:00
Sébastien Deleuze fb0fb21b78 Merge branch '6.2.x' 2025-06-12 16:40:36 +02:00
秦利斌 1a5cc87bb1 Remove unused field in ResourceHttpRequestHandler
Closes gh-35037

Signed-off-by: 秦利斌 <68638598+Allan-QLB@users.noreply.github.com>
2025-06-12 14:57:26 +02:00
Brian Clozel 3a1c2f7064 Merge branch '6.2.x' 2025-06-12 11:44:40 +02:00
Patrick Strawderman fd2038c927 Use String.replace in MetadataEncoder
Use String.replace instead of replaceAll in MetadataEncoder; since Java 9, String.replace
no longer uses a regex, while replaceAll does. The use case here of replacing a single
character does not require a regex.

Closes gh-35025

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2025-06-12 09:01:11 +02:00
Brian Clozel f11235ee19 Merge branch '6.2.x' 2025-06-12 08:53:02 +02:00
Sam Brannen bfd3dc2676 Implement toString() in RetryPolicy and RetryExecution implementations
Closes gh-35029
2025-06-11 19:17:03 +02:00
Sam Brannen bc967842f6 Rename and polish ComposedRetryListenerTests 2025-06-11 19:04:48 +02:00
Sam Brannen b6680422db Change signature of RetryOperations.execute() regarding nullability
Due to lacking support in NullAway for the current arrangement, we are
(perhaps temporarily) changing the signature of the execute() method in
RetryOperations (and thus also in RetryTemplate)...

from: <R extends @Nullable Object> R execute(Retryable<R> retryable);

to:   <R> @Nullable R execute(Retryable<? extends @Nullable R> retryable);

Once https://github.com/uber/NullAway/issues/1075 has been resolved, we
will consider switching back to the original signature.

See gh-34716
2025-06-11 17:43:29 +02:00
Brian Clozel a462f5e853 Merge branch '6.2.x' 2025-06-11 17:41:53 +02:00
rstoyanchev 84a4b44cf0 Polishing contribution
Closes gh-34807
2025-06-11 15:50:32 +01:00
hgh1472 9d3de4ff68 Remove duplicated setup
See gh-34807

Signed-off-by: hgh1472 <hgh1472@naver.com>
2025-06-11 15:50:32 +01:00
Sam Brannen 8f3ca49bc4 Rename Retryable.run() to Retryable.execute()
See gh-34716
2025-06-11 13:50:16 +02:00
Sam Brannen d74b863ae7 Polish Javadoc for core retry functionality
See gh-34716
2025-06-11 13:49:00 +02:00
Sam Brannen 8b9e620084 Allow FixedBackOff to be constructed with only a custom interval
This commit introduces two new constructors:

- FixedBackOff(long)

- FixedBackOff(Duration)

Closes gh-35028
2025-06-11 13:26:16 +02:00
Sam Brannen fcdd439ad0 Polish Javadoc for FixedBackOff 2025-06-11 13:06:55 +02:00
Sébastien Deleuze b901132192 Merge branch '6.2.x' 2025-06-11 10:15:36 +02:00
Brian Clozel 68df780c59 Upgrade to Micrometer 1.15.1
Closes gh-35019
2025-06-11 09:25:05 +02:00
Brian Clozel 3d63664ab0 Upgrade to Reactor 2025.0.0-M4
Closes gh-34997
2025-06-11 09:24:30 +02:00
Brian Clozel bdc5fafd0a Merge branch '6.2.x' 2025-06-11 09:23:52 +02:00
Brian Clozel dec0deb7dc Merge branch '6.2.x' 2025-06-11 09:21:38 +02:00
Sam Brannen d42d3f1a6c Fix wording in Javadoc for RetryTemplate
See gh-34716
2025-06-10 18:34:56 +02:00
Sam Brannen 51b6e8cc9f Rename RetryCallback to Retryable
See gh-34716
2025-06-10 18:26:52 +02:00
Sam Brannen f927ff635a Revise @⁠Nullable declarations for contains*() in CollectionUtils
Closes gh-35023
2025-06-10 17:50:37 +02:00
Sam Brannen 2c0f01e8ed Merge branch '6.2.x' 2025-06-10 11:52:37 +02:00
Sébastien Deleuze be02d961fc Merge branch '6.2.x' 2025-06-09 16:55:33 +02:00
Sam Brannen 077146d636 Merge branch '6.2.x' 2025-06-09 14:12:45 +02:00
Sébastien Deleuze b6a121ed44 Merge branch '6.2.x' 2025-06-09 11:03:47 +02:00
Sébastien Deleuze ef2495874d Upgrade to Kotlin 2.2.0-RC2
See gh-34946
2025-06-09 10:42:52 +02:00
Sam Brannen de7d50d39f Redeclare @⁠TestMethodOrder on @⁠Nested test class
Thanks to the new Discovery Issue Reporting mechanism introduced in JUnit 5.13, I became
aware of the fact that the @⁠Order annotations in NestedAfterTestClassSqlScriptsTests
were being silently ignored.

To address that, this commit redeclares @⁠TestMethodOrder on @⁠Nested test class.
2025-06-07 15:22:57 +02:00
Sam Brannen 5752585bb2 Clean up warnings in build 2025-06-07 12:37:27 +02:00
Sam Brannen 0b4f7f2f9d Remove obsolete code
The hasNullableAnnotation() method was made obsolete in commit
b5d153febf.

See gh-34952
See gh-34261
2025-06-07 12:23:56 +02:00
Sam Brannen 799a37602d Merge branch '6.2.x' 2025-06-07 12:15:02 +02:00
Sam Brannen 315bbf3abe Consistently declare nullability @⁠Contract for core utilities
Closes gh-34934
2025-06-07 11:41:38 +02:00
Sébastien Deleuze 9505e768ae Merge branch '6.2.x' 2025-06-06 18:21:24 +02:00
Sam Brannen 7a6f9bd3c3 Use @⁠TempDir in FileSystemUtilsTests 2025-06-06 16:34:56 +02:00
rstoyanchev 6c27dbc095 Merge branch '6.2.x' 2025-06-06 15:28:43 +01:00
Sam Brannen 583612fd40 Merge branch '6.2.x' 2025-06-06 15:13:42 +02:00
Sam Brannen 87c0655e12 Polishing 2025-06-06 15:01:44 +02:00
Sam Brannen ad2931b51f Migrate away from AssertJ's catchThrowable()
Closes gh-35003
2025-06-06 15:01:26 +02:00
Sam Brannen 3aa3b81e1c Update copyright headers 2025-06-06 13:49:23 +02:00
Johnny Lim 7f6a7b806e Replace AssertionsForClassTypes with Assertions
Closes gh-34821

Signed-off-by: Johnny Lim <izeye@naver.com>
2025-06-06 13:49:23 +02:00
Sébastien Deleuze 977792009d Introduce hints in RestClient API
This commit introduces hints in RestClient API for
SmartHttpMessageConverters supporting them.

Closes gh-34924
2025-06-06 13:10:12 +02:00
Brian Clozel 72601b6948 Merge branch '6.2.x' 2025-06-06 12:06:08 +02:00
Juergen Hoeller 8d17afc28b Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-06-06 09:25:25 +02:00
Juergen Hoeller 167350d408 Merge branch '6.2.x'
# Conflicts:
#	spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJExpressionPointcut.java
#	spring-aop/src/main/java/org/springframework/aop/aspectj/ShadowMatchUtils.java
2025-06-05 20:39:20 +02:00
Sébastien Deleuze 826041d2f7 Add Kotlin body advices
This commit introduces KotlinRequestBodyAdvice and
KotlinResponseBodyAdvice in order to set a KType hint when relevant.

Closes gh-34923
2025-06-05 18:53:31 +02:00
rstoyanchev 9f7a321c44 Support streaming with HTTP interfaces + RestClient
Closes gh-32358
2025-06-05 17:07:01 +01:00
Sam Brannen 02af9e5cee Revise core retry support
This commit constitutes a first pass over the new core retry support.

- Fix code and Javadoc formatting

- Polish/fix Javadoc

- Fix default FixedBackOff configuration in RetryTemplate

- Consistent logging in RetryTemplate

- Fix listener handling in CompositeRetryListener, allowing addListener()
  to work

- Polish tests

- Ensure RetryTemplateTests do not take over 30 seconds to execute

See gh-34716
2025-06-05 14:56:25 +02:00
Mahmoud Ben Hassine 3fb4a75ae4 Introduce minimal retry functionality as a core framework feature
This commit introduces a minimal core retry feature. It is inspired
by Spring Retry, but redesigned and trimmed to the bare minimum to
cover most cases.

Closes gh-34716
2025-06-05 14:56:25 +02:00
Violeta Georgieva aefdda3490 Upgrade to Netty v4.2.2.Final and Reactor Netty 2025.0.0-SNAPSHOT
Closes gh-34996
See gh-34997

Signed-off-by: Violeta Georgieva <696661+violetagg@users.noreply.github.com>
2025-06-05 14:14:06 +02:00
Sébastien Deleuze 93ba10fa1a Merge branch '6.2.x' 2025-06-05 14:08:36 +02:00
Sébastien Deleuze b89c48e714 Merge branch '6.2.x' 2025-06-05 12:12:23 +02:00
Brian Clozel 2d5d988ad4 Polishing contribution
Closes gh-34645
2025-06-05 11:34:34 +02:00
Kamil Doroszkiewicz c1839938ea Add support for "application/*+x-protobuf" media type
See gh-34645

Signed-off-by: Kamil Doroszkiewicz <kamil.doroszkiewicz@gmail.com>
2025-06-05 11:34:34 +02:00
Brian Clozel 79a793e44c Merge branch '6.2.x' 2025-06-05 10:58:57 +02:00
Brian Clozel 5fbb81de10 Fix missing "since" attributes for Deprecated code
See gh-34989
2025-06-05 09:25:10 +02:00
Brian Clozel 1e9179a87c Enable SpringDeprecatedCheck Checkstyle rule
This rules checks that `@Deprecated` annotations have a "since"
attribute.

Closes gh-34989
2025-06-05 09:25:03 +02:00
Brian Clozel fa6e32940c Merge branch '6.2.x' 2025-06-04 20:23:39 +02:00
Sam Brannen 7e035f5c50 Polish ImportTests 2025-06-04 17:00:10 +02:00
Sam Brannen 4581324038 Polish support for @⁠Import on interfaces
- Update @⁠Import Javadoc

- Move tests from ImportSelectorTests to ImportTests

See gh-34820
2025-06-04 16:59:46 +02:00
Daeho Kwon a4d5800a6c Support @⁠Import on interfaces
See gh-34805
Closes gh-34820

Signed-off-by: Daeho Kwon <trewq231@naver.com>
2025-06-04 16:47:50 +02:00
Sam Brannen 686705140e Polish Javadoc for @⁠Import 2025-06-04 16:47:50 +02:00
Sam Brannen af4fc0118c Update copyright header 2025-06-04 14:53:31 +02:00
ChanHyeongLee 4f5e2eefe9 Remove thenReturn that fetches unused values
Closes gh-34883

Signed-off-by: ChanHyeongLee <cksgud410@gmail.com>
2025-06-04 13:46:22 +01:00
rstoyanchev 263af04508 Polishing contribution
Closes gh-34877
2025-06-04 13:46:22 +01:00
kssumin 8b9ae2b11c Update Jetty on WebFlux bootstrap in reference docs
Replace deprecated JettyHttpHandlerAdapter with JettyCoreHttpHandlerAdapter
Update example to work with Jetty 12+
Add note about the deprecation

See gh-34877

Signed-off-by: kssumin <201566@jnu.ac.kr>
2025-06-04 13:46:22 +01:00
rstoyanchev 230540b6da Polishing contribution
Closes gh-34942
2025-06-04 13:46:22 +01:00
Yanming Zhou f9fa7cc93b Add missing "since" in @Deprecated
See gh-34942

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-06-04 13:46:22 +01:00
Sam Brannen b7dfd68d89 Merge branch '6.2.x' 2025-06-04 14:11:07 +02:00
rstoyanchev b699b65b40 Merge branch '6.2.x' 2025-06-03 19:11:52 +01:00
rstoyanchev 72b42bbd55 Polishing in RestClientAdapterTests 2025-06-03 18:51:57 +01:00
Patrick Strawderman 9501bff1f0 Use HexFormat in CharacterEditor
Use HexFormat to perform conversion for unicode-prefixed Strings in CharacterEditor.

Closes gh-34798

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2025-06-03 18:20:19 +02:00
Patrick Strawderman 542eb6f305 Use HexFormat in ContentDisposition
Closes gh-34797

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2025-06-03 18:19:47 +02:00
Brian Clozel 7c82a62bfb Merge branch '6.2.x' 2025-06-03 18:07:22 +02:00
Sam Brannen 941b791669 Polish null-safety documentation 2025-06-03 13:44:35 +02:00
Sam Brannen 9782dfb620 Fix nullability @⁠Contract for SupplierUtils.resolve(Supplier)
Closes gh-34987
2025-06-03 13:15:58 +02:00
Sam Brannen b0a06b8607 Merge branch '6.2.x' 2025-06-03 13:07:56 +02:00
Sébastien Deleuze c41147aa35 Introduce JacksonJsonMessageConverter#getObjectMapper
In order to give access to the underlying ObjectMapper to
classes extending JacksonJsonMessageConverter.

Closes gh-34963
2025-06-03 09:58:02 +02:00
Sébastien Deleuze ebf8d4fb1c Use Gradle nullability plugin 0.0.1
This commit replaces manual Gradle configuration of Error Prone
and NullAway by
https://github.com/spring-gradle-plugins/nullability-plugin.

Closes gh-34983
2025-06-03 09:42:29 +02:00
Sébastien Deleuze 0b14d676cc Refine null-safety documentation terms
Closes gh-34982
2025-06-02 23:42:33 +02:00
Sam Brannen 45ba4ace39 Merge branch '6.2.x' 2025-06-02 17:00:50 +02:00
Sam Brannen 0d39bb828a Merge branch '6.2.x' 2025-06-02 16:30:57 +02:00
Brian Clozel d75f20f65f Merge branch '6.2.x' 2025-06-02 15:48:19 +02:00
rstoyanchev a16cdd2c41 Fix typo in reference docs 2025-06-02 12:38:19 +01:00
rstoyanchev d1e279f060 Add reference docs for HTTP Service config
Closes gh-34912
2025-06-02 10:40:09 +01:00
rstoyanchev 81626b0734 Polishing reference docs for HTTP Service clients
See gh-34912
2025-06-02 10:40:09 +01:00
Sam Brannen 05d59271d2 Merge branch '6.2.x' 2025-06-02 10:48:28 +02:00
Sam Brannen a6b06a889d Merge branch '6.2.x' 2025-06-02 10:12:36 +02:00
Sam Brannen 5e9f90f9bf Merge branch '6.2.x' 2025-05-31 12:17:47 +02:00
Sam Brannen c5566c947c Merge branch '6.2.x' 2025-05-30 14:55:22 +02:00
Sam Brannen 24facbc002 Document that JUnit 4 is officially in maintenance mode (as of today) 2025-05-30 14:37:58 +02:00
Sam Brannen 0f9870b603 Stop referring to JUnit 5 in documentation
Closes gh-34970
2025-05-30 14:37:05 +02:00
Sam Brannen 1f1c24cb2a Merge branch '6.2.x' 2025-05-30 14:00:27 +02:00
Scott Frederick 8c967bf76d Fix typos in API versioning
Closes gh-34961

Signed-off-by: Scott Frederick <scottyfred@gmail.com>
2025-05-28 17:06:24 +02:00
Sam Brannen 21f235c093 Merge branch '6.2.x' 2025-05-28 16:41:58 +02:00
rstoyanchev 22c672a469 Revise names of callbacks in HttpServiceGroupConfigurer
Closes gh-34926
2025-05-28 14:54:27 +01:00
Johnny Lim ec49435a4d Polish HttpRequestValues
Signed-off-by: Johnny Lim <izeye@naver.com>
2025-05-28 14:54:07 +01:00
Sébastien Deleuze 3290592f58 Remove Kotlin field handling in DependencyDescriptor
The KotlinDelegate#isNullable invocation is unnecessary since this check
is already done by the Nullness#forField one introduced by
b5d153febf.

See gh-34952
See gh-34261
2025-05-28 14:39:44 +02:00
rstoyanchev 26ee30ed8f Merge branch '6.2.x' 2025-05-28 11:10:06 +01:00
Sébastien Deleuze 20ddd9f864 Polish KotlinReflectionParameterNameDiscoverer 2025-05-28 11:16:09 +02:00
Sébastien Deleuze a638828157 Merge branch '6.2.x' 2025-05-28 10:31:34 +02:00
Juergen Hoeller 106e5c7554 Upgrade to Hibernate ORM 7.0.0.Final and Hibernate Validator 9.0.0.Final
See gh-33750
2025-05-27 16:05:27 +02:00
Sam Brannen eb59d911cd Merge branch '6.2.x' 2025-05-27 11:32:25 +02:00
Sam Brannen e03117c9d2 Merge branch '6.2.x' 2025-05-27 11:28:48 +02:00
Juergen Hoeller b5d153febf Enforce consistent null check on injection points for pre-existing singleton beans
Includes consistent JSpecify nullness check on fields as optional injection points

Closes gh-34952
See gh-34261
2025-05-27 10:25:50 +02:00
Juergen Hoeller cdfe0895f9 Merge branch '6.2.x' 2025-05-27 09:57:01 +02:00
Sébastien Deleuze 59299b9e15 Fix a typo in null-safety.adoc 2025-05-27 09:36:21 +02:00
Sam Brannen 5d166f4932 Merge branch '6.2.x' 2025-05-26 18:19:29 +02:00
Sam Brannen 62f1814d7c Remove [set|with]Property(String, String) variants from MockEnvironment
Since setProperty(String, Object) and withProperty(String, Object)
methods were introduced in MockEnvironment in 6.2.8, this commit removes
the obsolete variants with (String, String) signatures.

See gh-34947
Closes gh-34948
2025-05-26 17:45:51 +02:00
Sam Brannen 6f6e0d45a9 Merge branch '6.2.x' 2025-05-26 17:37:08 +02:00
Sébastien Deleuze 3049e6d0ee Upgrade to Kotlin 2.2.0-RC
Closes gh-34946
2025-05-26 16:56:38 +02:00
Sébastien Deleuze eb65df027e Upgrade to Jackson 3.0.0-rc5
Closes gh-34945
2025-05-26 16:56:38 +02:00
Sébastien Deleuze 13be54a1d2 Make ProblemDetailJacksonXmlMixin compatible with Jackson 3
Closes gh-34925
2025-05-26 16:56:28 +02:00
Sébastien Deleuze eed0a3ff59 Allow access to env from SupplierContextDsl
Closes gh-34943
2025-05-26 11:55:34 +02:00
Sébastien Deleuze a8ac54120d Fix the build with Java 24 2025-05-26 10:43:20 +02:00
Sébastien Deleuze 2da1f8031d Merge branch '6.2.x' 2025-05-26 10:25:56 +02:00
Sam Brannen 3be3e4d28c Merge branch '6.2.x' 2025-05-23 17:39:21 +02:00
Sam Brannen 6653cd86ea Merge branch '6.2.x' 2025-05-22 17:44:03 +02:00
Sam Brannen e5a3c43fbc Merge branch '6.2.x' 2025-05-22 17:26:11 +02:00
Sam Brannen efea28953d Improve Javadoc for getFilename() & getFilenameExtension() in StringUtils
Closes gh-34932
2025-05-22 17:03:09 +02:00
Brian Clozel 612dc573d1 Upgrade to Jetty 12.1.0.beta0
Closes gh-34930
2025-05-21 18:16:58 +02:00
Stéphane Nicoll 9d3779db49 Declare @⁠Contract for quote() & getFilename() in StringUtils
This commit declares nullability @⁠Contract annotations for quote() and
getFilename() in StringUtils.

Closes gh-34896


Signed-off-by: Stéphane Nicoll <stephane.nicoll@broadcom.com>
2025-05-21 17:43:23 +02:00
Sam Brannen 88ce11abc8 Merge branch '6.2.x' 2025-05-21 15:40:34 +02:00
rstoyanchev 2e086bd727 Refine HttpServiceGroupConfigurer API
Closes gh-34926
2025-05-19 18:08:53 +01:00
Brian Clozel 1ea8a91b85 Merge branch '6.2.x' 2025-05-19 17:10:49 +02:00
Sébastien Deleuze e02e67b39f Polish BeanRegistrarDsl Javadoc 2025-05-19 13:09:14 +02:00
Sébastien Deleuze aa9ab8e545 Add support for callable references to BeanRegistrarDsl
BeanDefinitionDsl is allowing to create a bean from a callable
reference with its parameters autowired by type,
BeanRegistrarDsl should allow that too. For example:

class SampleBeanRegistrar : BeanRegistrarDsl({
    registerBean<MyRepository>()
    registerBean(::myRouter)
})

fun myRouter(myRepository: MyRepository) = router {
    ...
}

Closes gh-34922
2025-05-19 13:09:04 +02:00
Brian Clozel 81ea754ac2 Merge branch '6.2.x' 2025-05-19 12:11:32 +02:00
rstoyanchev 094e653746 Versioning support in WebTestClient controller setup
See gh-34919
2025-05-19 09:36:51 +01:00
rstoyanchev 3095219479 Support API versioning in MockMvc
See gh-34919
2025-05-19 09:36:51 +01:00
rstoyanchev a024e5985a Add defaultApiVersion to WebTestClient
See gh-34919
2025-05-19 09:36:51 +01:00
rstoyanchev 5b19f6249e Refactoring in ApiVersionInserter
Refine naming of static factory methods, and update them to be
shortcuts for instance creation.

See gh-34919
2025-05-19 09:36:51 +01:00
Sam Brannen f4f0e52003 Stop declaring parameters as final in JdbcTemplate
The affected parameters are "effectively final" and are therefore no
longer required to be declared as "final" on modern JDKs.
2025-05-16 14:46:40 +02:00
Sam Brannen d0bf8faf48 Implement PreparedStatementCallback as lambda expression 2025-05-16 14:45:52 +02:00
Brian Clozel bd83fb7021 Merge branch '6.2.x' 2025-05-15 11:07:53 +02:00
rstoyanchev e41fe16d37 Merge branch '6.2.x' 2025-05-15 08:26:08 +01:00
Juergen Hoeller 1187bc2016 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
2025-05-15 01:48:01 +02:00
Sam Brannen 01fea5e7ed Polish Jackson 3 support
- Improve Javadoc.

- Suppress warnings for "removal".

- Update copyright headers.

- Migrate several tests from:
  - MappingJackson2MessageConverter to JacksonJsonMessageConverter
  - Jackson2JsonEncoder to JacksonJsonEncoder
  - Jackson2JsonDecoder to JacksonJsonDecoder
  - Jackson2SmileEncoder to JacksonSmileEncoder
  - Jackson2ObjectMapperBuilder to JsonMapper and XmlMapper
  - MappingJackson2JsonView to JacksonJsonView
  - MappingJackson2HttpMessageConverter to JacksonJsonHttpMessageConverter
  - MappingJackson2XmlHttpMessageConverter to JacksonXmlHttpMessageConverter
2025-05-14 16:55:27 +02:00
rstoyanchev ea340fbe69 Merge branch '6.2.x' 2025-05-14 15:16:12 +01:00
rstoyanchev 807cf5e254 Add Consumer methods to HttpRequestValues.Builder
Closes: gh-34870
2025-05-14 15:16:05 +01:00
Dmitry Sulman 3b5acc270f Upgrade to Kotlin 2.1.21
Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
2025-05-14 16:34:45 +03:00
Juergen Hoeller 88c92ab067 Upgrade to Reactor 2025.0.0-M3
Closes gh-34897
2025-05-14 15:22:19 +02:00
Juergen Hoeller 4956cb7b82 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-05-14 15:07:05 +02:00
rstoyanchev e04de95ef2 Update API versioning ref docs for client side
Closes: gh-34569
2025-05-14 13:01:30 +01:00
rstoyanchev 5cb3ea228e Polishing in RestClient reference docs 2025-05-14 13:01:30 +01:00
rstoyanchev cce2771639 Add API versioning reference documentation
See gh-34569
2025-05-14 13:01:30 +01:00
Brian Clozel bf78980925 Merge branch '6.2.x' 2025-05-14 09:58:54 +02:00
Sébastien Deleuze 2a29e16456 Deprecate for removal Jackson 2 support
This commit deprecate for removal (likely in a future 7.x release) the
Jackson 2 support in favor of the Jackson 3 one.

Closes gh-33798
2025-05-13 18:02:33 +02:00
Sébastien Deleuze 6ae89ea397 Introduce Jackson 3 support to MessageBrokerBeanDefinitionParser
See gh-33798
2025-05-13 17:53:29 +02:00
Sébastien Deleuze 7acd4aec38 Introduce Jackson 3 support to AnnotationDrivenBeanDefinitionParser
See gh-33798
2025-05-13 17:53:29 +02:00
Sébastien Deleuze 0ad4fcaeaf Update spring-test tests to use Jackson 3
See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze ac3c1b8762 Introduce Jackson 3 support for spring-websocket
This commit introduces a JacksonJsonSockJsMessageCodec Jackson 3 variant
of Jackson2SockJsMessageCodec.

See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze a0ed3f052e Introduce Jackson 3 support for spring-jms
This commit introduces a JacksonJsonMessageConverter Jackson 3 variant
of MappingJackson2MessageConverter.

See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze 3a0a755144 Introduce Jackson 3 support for spring-messaging
This commit introduces a JacksonJsonMessageConverter Jackson 3 variant
of MappingJackson2MessageConverter.

See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze d0cd7af7e6 Introduce hints support in advices
This commit introduces RequestBodyAdvice#determineReadHints and
ResponseBodyAdvice#determineWriteHints in order to be able to support
SmartHttpMessageConverter hints, as well as related `@JsonView`
support.

See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze 71987a8713 Introduce Jackson 3 support for views
This commit introduces Jackson 3 based variants of the following
Jackson 2 classes (and related dependent classes).

MappingJackson2JsonView -> JacksonJsonView
MappingJackson2XmlView-> JacksonXmlView

See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze d4e4a9ae06 Introduce Jackson 3 support for converters
This commit introduces Jackson 3 SmartHttpMessageConverter based
variants of the following Jackson 2 classes (and related dependent classes).

org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter ->
org.springframework.http.converter.AbstractJacksonHttpMessageConverter

MappingJackson2HttpMessageConverter -> JacksonJsonHttpMessageConverter
MappingJackson2SmileHttpMessageConverter -> JacksonSmileHttpMessageConverter
MappingJackson2CborHttpMessageConverter -> JacksonCborHttpMessageConverter
MappingJackson2XmlHttpMessageConverter -> JacksonXmlHttpMessageConverter
MappingJackson2YamlHttpMessageConverter -> JacksonYamlHttpMessageConverter

They use hints instead of MappingJacksonValue and MappingJacksonInputMessage
to support `@JsonView` and FilterProvider.

Jackson 3 support is configured if found in the classpath otherwise
fallback to Jackson 2.

JacksonHandlerInstantiator needs to be enabled explicitly if needed.

See gh-33798
2025-05-13 17:53:28 +02:00
Sébastien Deleuze 7a8db31dc3 Introduce Jackson 3 support for HandlerInstantiator
This commit introduces a
org.springframework.http.support.JacksonHandlerInstantiator Jackson 3
variant of org.springframework.http.converter.json.SpringHandlerInstantiator
Jackson 2 class.

See gh-33798
2025-05-13 17:51:04 +02:00
Sébastien Deleuze 5cb2f870d0 Introduce Jackson 3 support for codecs
This commit introduces Jackson 3 variants of the following Jackson 2
classes (and related dependent classes).

org.springframework.http.codec.json.Jackson2CodecSupport ->
org.springframework.http.codec.JacksonCodecSupport

org.springframework.http.codec.json.Jackson2Tokenizer ->
org.springframework.http.codec.JacksonTokenizer

org.springframework.http.codec.json.Jackson2SmileDecoder ->
org.springframework.http.codec.smile.JacksonSmileDecoder

org.springframework.http.codec.json.Jackson2SmileEncoder ->
org.springframework.http.codec.smile.JacksonSmileEncoder

Jackson2CborDecoder -> JacksonCborDecoder
Jackson2CborEncoder -> JacksonCborEncoder
Jackson2JsonDecoder -> JacksonJsonDecoder
Jackson2JsonEncoder -> JacksonJsonEncoder

Jackson 3 support is configured if found in the classpath otherwise
fallback to Jackson 2.

See gh-33798
2025-05-13 17:51:04 +02:00
Sébastien Deleuze 746679f7a7 Introduce Jackson 3 support in the Gradle build
This commit adds Jackson 3 BOM to Spring Framework platform dependencies
and related Javadoc link.

See gh-33798
2025-05-13 17:51:04 +02:00
Juergen Hoeller 46e6783593 Polishing 2025-05-13 16:42:57 +02:00
Juergen Hoeller 0f2fbd1983 Upgrade to Micrometer 1.15.0
Includes Tomcat 11.0.7

Closes gh-34888
2025-05-13 16:32:22 +02:00
Juergen Hoeller 254a55d217 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-05-13 16:31:05 +02:00
Brian Clozel 0df75ff75e Fix StringIndexOutOfBoundsException with Class-File metadata
Closes gh-34882
2025-05-13 16:15:00 +02:00
Martin Mois 261862076c Use system properties in ReactorClientHttpRequestFactory
Closes gh-34850

Signed-off-by: Martin Mois <martin.mois@gmail.com>
2025-05-13 15:18:03 +02:00
Sam Brannen 680094d74e Merge branch '6.2.x' 2025-05-13 13:45:37 +02:00
Brian Clozel 233eb7f0aa Fix StringIndexOutOfBoundsException with Class-File metadata
Prior to this commit, the new `ClassFileAnnotationMetadata` would fail
when reading `Class<T>` annotation attributes when values are primitive
types.

This commit uses `java.lang.constant.ClassDesc` to better parse type
descriptors from the bytecode.

Fixes gh-24882
2025-05-12 18:14:33 +02:00
Sam Brannen 18756c0701 Merge branch '6.2.x' 2025-05-12 17:27:38 +02:00
Sam Brannen 33aeb6ee9c Deprecate [Property|Preferences]PlaceholderConfigurer for removal
PropertyPlaceholderConfigurer and PreferencesPlaceholderConfigurer have
been officially deprecated since Spring Framework 5.2.

Since we no longer expect applications to depend on these outdated
mechanisms, this commit deprecates these classes "for removal" in
Spring Framework 8.0.

Closes gh-34880
2025-05-11 17:03:42 +02:00
Sam Brannen c7787b8383 Merge branch '6.2.x' 2025-05-11 16:41:55 +02:00
Sam Brannen dde69c96b0 Merge branch '6.2.x' 2025-05-11 15:55:07 +02:00
Sam Brannen 74f4a07eac Merge branch '6.2.x' 2025-05-11 15:37:07 +02:00
Sam Brannen c28b22b465 Merge branch '6.2.x' 2025-05-11 14:11:53 +02:00
Sam Brannen 958dab7c84 Merge branch '6.2.x' 2025-05-11 13:53:40 +02:00
Sam Brannen 6878587a33 Merge branch '6.2.x' 2025-05-10 15:44:23 +02:00
Sam Brannen 32e2c453b0 Merge branch '6.2.x' 2025-05-10 15:21:39 +02:00
Sam Brannen 2018d933ac Merge branch '6.2.x' 2025-05-10 15:11:44 +02:00
Sam Brannen 3fb9c2b507 Merge branch '6.2.x' 2025-05-10 14:21:41 +02:00
Sam Brannen 5fbfdbc91c Merge branch '6.2.x' 2025-05-09 16:44:21 +02:00
Sam Brannen 4f38c5bdfa Merge branch '6.2.x' 2025-05-09 14:32:13 +02:00
Phillip Webb 13b09e6f3c Ensure only immediate member classes are only included
Update `ClassFileClassMetadata` so that member classes only include
immediate children. This aligns with the other `ClassMetadata`
implementations.

Closes gh-34869
2025-05-09 09:43:58 +02:00
Phillip Webb ead80ce2f5 Return null for getSuperClassName() with package-info classes
Update `ClassFileClassMetadata` to align the behavior of
`getSuperClassName()` with other readers in that it returns
`null` for `package-info` classes.

See gh-34869
2025-05-09 09:43:48 +02:00
Sam Brannen dbaba3d88a Merge branch '6.2.x' 2025-05-08 10:50:14 +02:00
rstoyanchev 97d5f7f07d Fix filtering in HttpServiceProxyRegistryFactoryBean
Closes gh-34867
2025-05-07 22:53:33 +01:00
Sam Brannen 733e695e18 Merge branch '6.2.x' 2025-05-07 17:37:41 +02:00
Sam Brannen e673345102 Merge branch '6.2.x' 2025-05-07 16:15:15 +02:00
Sam Brannen 6c4651925e Merge branch '6.2.x' 2025-05-07 14:29:35 +02:00
rstoyanchev d8b506e09a Fix failing test 2025-05-06 21:43:12 +01:00
rstoyanchev e5d4d7c13c Refactor DefaultApiVersionInserter 2025-05-06 20:36:56 +01:00
rstoyanchev 22e7f24731 Add defaultApiVersion to RestClient and WebClient
Closes gh-34857
2025-05-06 19:07:58 +01:00
Sam Brannen fef969145d Merge branch '6.2.x' 2025-05-06 18:51:10 +02:00
Sam Brannen 964d67474c Merge branch '6.2.x' 2025-05-06 16:08:20 +02:00
Brian Clozel 4a99fa8846 Merge branch '6.2.x' 2025-05-05 14:51:34 +02:00
rstoyanchev ecdb63371e Merge branch '6.2.x' 2025-05-02 15:59:10 +01:00
Sam Brannen f8e7bf7825 Merge branch '6.2.x' 2025-05-02 11:39:09 +02:00
rstoyanchev 67f3ff574f Polishing in HTTP service registry 2025-05-01 11:00:32 +01:00
Phillip Webb 42e854e5ff Polish AbstractHttpServiceRegistrar.DefaultGroupSpec
Remove `DefaultGroupRegistry` since it's not really needed and polish
`DefaultGroupSpec` a little.
2025-05-01 11:00:32 +01:00
Phillip Webb d2246162c3 Polish GroupsMetadata.Registration
Unify `Registration` and `DefualtRegistration` into a single
class since they are both package-private and the interface
isn't really needed.
2025-05-01 11:00:32 +01:00
Phillip Webb abbee1a050 Use bean class loader when creating interface clients
Update interface client code to replace `GroupsMetadata.loadClass` calls
with `ClassUtils.resolveClassName` passing in the bean class loader.

Since the bean class loader in injected after construction, some minor
refactoring has been applied to `HttpServiceProxyRegistryFactoryBean`.
The class now stores `GroupsMetadata` and only loads the types in
in `afterPropertiesSet`.

The `HttpServiceProxyFactory` class has also been updated to ensure
that the proxy is created using the class loader of the service
type, rather than the thread context class loader.

Fixes gh-34846
2025-05-01 11:00:32 +01:00
Sam Brannen 13f9fed4bc Merge branch '6.2.x' 2025-05-01 10:52:26 +02:00
Juergen Hoeller d0a1ba5092 Merge branch '6.2.x' 2025-04-30 17:56:36 +02:00
Juergen Hoeller b98ef1309b Upgrade to Hibernate ORM 7.0.0.CR1
See gh-33750
2025-04-29 18:30:57 +02:00
Juergen Hoeller 4d15c136b1 Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/test/java/org/springframework/context/aot/ContextAotProcessorTests.java
2025-04-29 11:51:24 +02:00
Juergen Hoeller bb513de224 Merge branch '6.2.x' 2025-04-28 16:14:34 +02:00
rstoyanchev 86b5679516 Add remaining change from merge 2025-04-28 14:40:52 +01:00
rstoyanchev 8375962813 Merge branch '6.2.x' 2025-04-28 14:29:58 +01:00
rstoyanchev 6d6f657858 Add option to not use detected versions
Closes gh-34775
2025-04-28 13:35:01 +01:00
Sam Brannen 0c6a26a381 Merge branch '6.2.x' 2025-04-27 17:59:50 +02:00
Sam Brannen d0af5146e0 Add note regarding aggregated Javadoc toolchain configuration
In commit 49ef150c5d, I stated that the common javadoc task used by all
spring-* modules would be addressed in a separate commit. However,
after further investigation I determined that the spring-test Javadoc
JAR was published successfully, including links to JUnit 5 Javadoc
(which was not previously the case).

https://repo1.maven.org/maven2/org/springframework/spring-test/7.0.0-M4/spring-test-7.0.0-M4-javadoc.jar

This commit therefore only adds a note in JavaConventions to remind us
that the aggregated Javadoc toolchain configuration needs to stay in
sync with the configuration in JavaConventions.

See gh-27497
Closes gh-34774
2025-04-27 17:41:42 +02:00
Sam Brannen 5d3170448a Import junit-bom in buildSrc 2025-04-27 17:22:03 +02:00
Sam Brannen d8c7c250e3 Upgrade to JUnit Jupiter 5.12.2 in buildSrc 2025-04-27 17:03:01 +02:00
Sam Brannen 5bdec756b9 Merge branch '6.2.x' 2025-04-27 16:55:39 +02:00
Sam Brannen 1234d29d78 Merge branch '6.2.x' 2025-04-27 16:30:08 +02:00
Sam Brannen c74fc7ec90 Deprecate JUnit 4 support in the TestContext framework
Closes gh-34794
2025-04-26 10:06:18 +02:00
Sam Brannen 2db1a63a92 Merge branch '6.2.x' 2025-04-26 09:41:09 +02:00
Sam Brannen 4bf8e2f366 Merge branch '6.2.x' 2025-04-26 07:55:00 +02:00
rstoyanchev d8503daa1f Revise how bodyType is set for 7.0 codebase
See gh-34793
2025-04-25 21:41:11 +01:00
rstoyanchev fed6e9b3c3 Merge branch '6.2.x' 2025-04-25 21:33:03 +01:00
Sam Brannen 98cdae6444 Merge branch '6.2.x' 2025-04-25 13:45:10 +02:00
Sam Brannen cdee5c5b79 Merge branch '6.2.x' 2025-04-25 12:13:37 +02:00
Sam Brannen 52265a5c65 Merge branch '6.2.x' 2025-04-24 16:30:45 +02:00
Sébastien Deleuze ead76b6317 Merge branch '6.2.x' 2025-04-24 10:39:39 +02:00
rstoyanchev 838b4d67a5 Fix Nullable declaration in PatternMatchUtils 2025-04-23 12:20:32 +01:00
rstoyanchev 2a3e7ea3f9 Merge branch '6.2.x' 2025-04-23 12:11:28 +01:00
Juergen Hoeller 014a395aed Merge branch '6.2.x' 2025-04-23 10:21:52 +02:00
Juergen Hoeller ffb32f4238 Merge branch '6.2.x' 2025-04-22 23:20:09 +02:00
Sam Brannen 61a517ea3b Merge branch '6.2.x' 2025-04-22 12:46:52 +02:00
Juergen Hoeller f2dd7b01cd Consistent final @Nullable declarations 2025-04-22 12:25:01 +02:00
Juergen Hoeller 78f901649e Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
2025-04-22 12:18:44 +02:00
Seonghun Jeong d3a5aefdff Improve handling of mainThreadPrefix and remove redundant null check (#34746) 2025-04-22 12:16:34 +02:00
Sam Brannen fc516cb39e Merge branch '6.2.x' 2025-04-22 11:55:39 +02:00
Sam Brannen e7402bc365 Remove obsolete RmiInvocationWrapperRTD.xml file
Closes gh-34779
2025-04-18 16:59:37 +02:00
Sam Brannen 49ef150c5d Configure JDK 24 toolchain for aggregated Javadoc
Changes made in conjunction with #27497 now require that we generate
Javadoc with JDK 18 or higher in order to make use of the
"--link-modularity-mismatch" flag for the javadoc executable.

This commit sets the toolchain for the javadoc task in the
framework-api module to use JDK 24 for generating Javadoc.

The common javadoc task used by all spring-* modules will be addressed
in a separate commit.

See gh-27497
See gh-34774
2025-04-17 18:12:06 +02:00
Sam Brannen c5e865494e Merge branch '6.2.x' 2025-04-17 15:48:48 +02:00
Brian Clozel a185f15352 Upgrade to Gson 2.13.0
Closes gh-34772
2025-04-17 10:28:16 +02:00
Brian Clozel 7a4bf1dcb2 Upgrade to Reactor 2025.0.0-M2
Closes gh-34770
2025-04-17 10:10:32 +02:00
Brian Clozel 16bb91e2e1 Upgrade to Micrometer 1.15.0-RC1
Closes gh-34771
2025-04-17 10:08:58 +02:00
Brian Clozel cb76ebcf9d Merge branch '6.2.x' 2025-04-17 09:50:40 +02:00
Sam Brannen 39e263fe5d Switch javadoc link-modularity-mismatch flag to info
We now invoke the javadoc tool with "--link-modularity-mismatch info"
in order not to fail the build when encountering warnings such as the
following.

> The code being documented uses packages in the unnamed module, but the
> packages defined in https://junit.org/junit5/docs/5.12.2/api/ are in
> named modules.

Closes gh-27497
2025-04-16 14:16:59 +02:00
Sam Brannen 3057de7746 Merge branch '6.2.x' 2025-04-16 14:04:38 +02:00
rstoyanchev d8b05c7eba Merge branch '6.2.x' 2025-04-16 11:59:28 +01:00
Olga Maciaszek-Sharma b24f4edbec HttpServiceGroupConfigurer extends Ordered
Closes gh-34739

Signed-off-by: Olga Maciaszek-Sharma <olga.maciaszek-sharma@broadcom.com>
2025-04-15 17:33:34 +01:00
rstoyanchev 4599ad4168 HttpServiceProxyRegistry Javadoc updates
See gh-33992
2025-04-15 17:27:48 +01:00
rstoyanchev 40853825dc Add HttpRequestValues.Processor
Closes gh-34699
2025-04-15 17:25:34 +01:00
Stéphane Nicoll 88e773ae24 Add AOT support for Registry of HTTP Interface Proxies
This commit adds AOT support for restoring the state of the
HttpServiceProxyRegistry. This generates code for the groupsMetadata
as well as for the creation of the client proxies.

Closes gh-34750
2025-04-15 17:29:43 +02:00
Stéphane Nicoll e3e99ac8a0 Add a convenience method to create a ValueCodeGenerator
This commit makes BeanDefinitionPropertyValueCodeGeneratorDelegates
public and offer a convenience method to create a ValueCodeGenerator
that works will all core delegates.

Closes gh-34761
2025-04-15 17:17:45 +02:00
Sam Brannen 5fb37e3133 Polishing 2025-04-15 15:19:34 +02:00
Stéphane Nicoll aad742ded0 Merge branch '6.2.x' 2025-04-15 10:05:53 +02:00
rstoyanchev 76ba02ec3e Update HttpServiceProxyRegistry
See gh-33992
2025-04-14 17:45:49 +01:00
rstoyanchev fb94109c09 WebTestClient support for API versioning
Closes gh-34568
2025-04-14 17:45:49 +01:00
Stéphane Nicoll c55bebab21 Add dependency management for 'org.jboss.logging:jboss-logging'
This commit updates framework-platform to manage the dependency of JBoss
Logging. This leads to problem previously as Hibernate Validator
requires a recent version of JBoss Logging that other dependencies
haven't upgraded to yet.

Closes gh-34749
2025-04-14 16:38:02 +02:00
Sam Brannen af461fc0a6 Merge branch '6.2.x' 2025-04-14 14:27:27 +02:00
Sam Brannen d5baab2aed Merge branch '6.2.x' 2025-04-14 14:16:31 +02:00
Sam Brannen 7dfe0cc3bd Upgrade to AspectJ 1.9.24
This commit upgrades the build to use AspectJ 1.9.24 which provides
support for JDK 24.

Closes gh-34752
2025-04-14 13:57:12 +02:00
Sam Brannen 23aea5c402 Merge branch '6.2.x' 2025-04-14 11:32:48 +02:00
Juergen Hoeller 6ade8c5a41 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
2025-04-12 06:02:42 +02:00
Sam Brannen 6ab4cf49a8 Merge branch '6.2.x' 2025-04-11 16:59:35 +02:00
Juergen Hoeller 75ed4be446 Align JSpecify @Nullable annotation 2025-04-10 18:42:27 +02:00
Juergen Hoeller 7bb7456686 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
#	spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java
2025-04-10 18:37:07 +02:00
Sam Brannen e35db3311f Merge branch '6.2.x' 2025-04-10 17:07:18 +02:00
Sam Brannen df4868bf83 Merge branch '6.2.x' 2025-04-10 16:49:43 +02:00
Sam Brannen 1795b234e4 Merge branch '6.2.x' 2025-04-10 14:52:22 +02:00
Juergen Hoeller 24c44019a0 Merge branch '6.2.x' 2025-04-07 23:55:00 +02:00
Juergen Hoeller 8bc99fa662 Merge branch '6.2.x' 2025-04-07 22:42:52 +02:00
Juergen Hoeller 4283a34fa4 Merge branch '6.2.x' 2025-04-07 17:09:36 +02:00
Sam Brannen 65cdbf7c07 Merge branch '6.2.x' 2025-04-07 15:57:41 +02:00
Sam Brannen 024f421170 Switch to JSpecify @⁠Nullable annotation on main
See gh-34726
2025-04-07 14:19:51 +02:00
Sam Brannen 48df362dfc Merge branch '6.2.x' 2025-04-07 14:11:38 +02:00
Sam Brannen 63daa7a0e4 Merge branch '6.2.x' 2025-04-06 18:18:39 +02:00
Sam Brannen 343f613f7c Indent with tabs instead of spaces in Gradle build scripts 2025-04-06 17:41:32 +02:00
Sam Brannen cfb7888044 Merge branch '6.2.x' 2025-04-06 17:40:51 +02:00
Sam Brannen 555d17df14 Merge branch '6.2.x' 2025-04-06 17:34:44 +02:00
Juergen Hoeller 8d48a1e34b Merge branch '6.2.x' 2025-04-05 16:14:06 +02:00
Sébastien Deleuze eee45c3583 Refine CORS preflight requests handling with no configuration
This commit makes CORS preflight requests handling more flexible
by just skipping setting CORS response headers when no
configuration is defined instead of rejecting them.

That will have the same effect on user agent side (the preflight
request will be considered as not authorized and the actual
request not performed) but is more flexible and more efficient.

Closes gh-31839
2025-04-04 21:32:38 +02:00
Sam Brannen 76d335aa41 Remove default value for @⁠ManagedOperationParameters container 2025-04-04 18:17:43 +02:00
Sam Brannen 5b4511fbf7 Merge branch '6.2.x' 2025-04-04 15:54:29 +02:00
Juergen Hoeller 907c1db7a6 Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
2025-04-04 00:28:50 +02:00
Sébastien Deleuze 98de16bc50 Turn CDS documentation into a JVM AOT cache one
This commit evolves the CDS documentation to a JVM AOT cache
one for Java 24+, while still documenting how to use CDS for
Java 17 to Java 23.

Closes gh-34700
2025-04-03 17:55:42 +02:00
Sam Brannen d6e35cf1f0 Introduce queryParamCount() in MockRestRequestMatchers
Closes gh-34703
2025-04-03 14:50:58 +02:00
Juergen Hoeller 18989123ac Merge branch '6.2.x' 2025-04-03 12:04:38 +02:00
Sam Brannen a9cab2a3f1 Polishing 2025-04-03 11:19:53 +02:00
Sam Brannen d10d8e98c2 Remove default value for Container annotation 2025-04-03 10:59:33 +02:00
Sam Brannen 6576c52ed3 Remove unused code 2025-04-03 10:58:51 +02:00
Sam Brannen 71b6dcfa7e Merge branch '6.2.x' 2025-04-03 10:48:28 +02:00
Juergen Hoeller 5b1c55252e Merge branch '6.2.x' 2025-04-02 23:43:06 +02:00
Sébastien Deleuze e9c4665a80 Merge branch '6.2.x' 2025-04-02 18:05:04 +02:00
Sébastien Deleuze b94ab90eb2 Merge branch '6.2.x' 2025-04-02 17:10:56 +02:00
Sébastien Deleuze dd888ed813 Refine StringUtils#uriDecode and update documentation
This commit adds another optimization mainly for the use case where
there is no encoded sequence, and updates the Javadoc of both
StringUtils#uriDecode and UriUtils#decode to match the implementation.

Closes gh-34673
2025-04-02 14:46:10 +02:00
Patrick Strawderman 7f1bc20688 Refine StringUtils#uriDecode
Refine the StringUtils#uriDecode method in the following ways:

- Use a StringBuilder instead of ByteArrayOutputStream, and only decode
  %-encoded sequences.
- Use HexFormat.fromHexDigits to decode hex sequences.
- Decode to a byte array that is only allocated if encoded sequences are
  encountered.

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
See gh-34673
2025-04-02 14:33:51 +02:00
Brian Clozel 0b92a51650 Reinstate failing tests after Tomcat upgrade
Closes gh-33917
2025-04-02 11:05:56 +02:00
rstoyanchev c35aac0c52 Merge branch '6.2.x' 2025-04-02 09:06:06 +01:00
Brian Clozel a787088df2 Merge branch '6.2.x' 2025-04-02 09:40:05 +02:00
Juergen Hoeller 533283a23e Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-04-01 23:44:04 +02:00
Juergen Hoeller 7970046f17 Upgrade to Commons Logging 1.3.5, Tomcat 11.0.5, Jetty 12.1.0.alpha2, Hibernate ORM 7.0.0.Beta5 2025-04-01 22:54:51 +02:00
Juergen Hoeller d06b47818b Align JSpecify @Nullable annotation 2025-04-01 22:23:46 +02:00
Juergen Hoeller 5e2c16c30c Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java
2025-04-01 22:21:56 +02:00
rstoyanchev 7bf628c827 Client support for API versioning
Closes gh-34567
2025-04-01 17:04:15 +01:00
rstoyanchev 483abd96a4 Polishing in client adapter tests 2025-04-01 17:02:48 +01:00
Sébastien Deleuze 5c93bb38c4 Merge branch '6.2.x' 2025-04-01 09:53:42 +02:00
rstoyanchev 10e32c92e6 Make container annotation for ImportHttpServices nested
See gh-33992
2025-03-31 18:29:24 +01:00
Juergen Hoeller a122dda596 Merge branch '6.2.x' 2025-03-31 16:42:29 +02:00
rstoyanchev ebdebbbd06 Rename HttpServiceGroups to ImportHttpServiceGroups
See gh-33992
2025-03-31 15:21:00 +01:00
rstoyanchev 779f1b080e Merge branch '6.2.x' 2025-03-31 11:36:44 +01:00
Sam Brannen b2af1af50f Merge branch '6.2.x' 2025-03-31 12:19:43 +02:00
Sam Brannen 18645022e9 Merge branch '6.2.x' 2025-03-31 12:13:23 +02:00
rstoyanchev 87fa9a5acb Polishing in GroupsMetadata
See gh-33992
2025-03-31 10:23:57 +01:00
Sébastien Deleuze 85bc6350ce Merge branch '6.2.x' 2025-03-31 11:16:01 +02:00
Sébastien Deleuze d771d02119 Add a requiredExchange extension to RestClient
Closes gh-34692
2025-03-31 11:15:40 +02:00
rstoyanchev 302f04ecf3 Replace Map argument with GroupsMetadata
In preparation for HTTP Service registry AOT support.

See gh-33992
2025-03-31 10:11:42 +01:00
rstoyanchev 1c0bcba587 Add HTTP Service registrar tests
Closes gh-33992
2025-03-31 10:11:42 +01:00
rstoyanchev 42409e21fa Lazy loading of HTTP Service classes
To help with AOT support, update AbstractHttpServiceRegistrar to store
HTTP Service types by name, and avoid loading classes during the bean
definition registration phase.

See gh-33992
2025-03-31 10:11:42 +01:00
rstoyanchev 49e24b7dfa Add author tags to HTTP Service registry
See gh-33992
2025-03-31 10:11:42 +01:00
rstoyanchev 9721cbad5c Further simplify GroupAdapter initialization
See gh-33992
2025-03-31 10:11:42 +01:00
Phillip Webb 39c4cc537d Apply HTTP Service group configurers in order
See gh-33992
2025-03-31 10:11:42 +01:00
Phillip Webb 7c3618de7c Fixup checkstyle violations
See gh-33992
2025-03-31 10:11:42 +01:00
rstoyanchev 92b0eb7f8b Add HTTP Service registry support
See gh-33992
2025-03-31 10:11:42 +01:00
Tobias Hänel a63c5ad305 Fix typo in Bean Validation section of reference manual
This commit fixes a minor typo in  the "Java Bean Validation - Customizing
Validation Errors" section of the reference manual.

Closes gh-34686

Signed-off-by: Tobias Hänel <contact@tobias-haenel.de>
2025-03-30 20:28:12 +02:00
Sam Brannen 551f6c0c66 Polishing 2025-03-29 13:27:32 +01:00
Sam Brannen 9956cc11bb Merge branch '6.2.x' 2025-03-29 12:57:49 +01:00
Sam Brannen 8379ac772a Introduce OptionalToObjectConverter
We have had an ObjectToOptionalConverter since Spring Framework 4.1;
however, prior to this commit we did not have a standard Converter for
the inverse (Optional to Object).

To address that, this commit introduces an OptionalToObjectConverter
that unwraps an Optional, using the ConversionService to convert the
object contained in the Optional (potentially null) to the target type.

This allows for conversions such as the following.

- Optional.empty()                             -> null
- Optional.of(42) with Integer target          -> 42
- Optional.of(42) with String target           -> "42"
- Optional.of(42) with Optional<String> target -> Optional.of("42")

The OptionalToObjectConverter is also registered by default in
DefaultConversionService, alongside the existing
ObjectToOptionalConverter.

See gh-20433
Closes gh-34544
2025-03-29 12:15:46 +01:00
Sam Brannen b8c2780bfe Simplify SpEL ExpressionWithConversionTests 2025-03-29 12:15:46 +01:00
Juergen Hoeller ac7c7ff5b2 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
2025-03-28 20:47:57 +01:00
Sam Brannen 51c084ffb6 Polishing 2025-03-28 14:54:43 +01:00
Yanming Zhou 5be83e9223 Stop calling deprecated JdbcOperations methods
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-03-28 14:40:51 +01:00
Sam Brannen e41487492d Merge branch '6.2.x' 2025-03-27 16:06:11 +01:00
Sam Brannen 8edda5c768 Remove java24 classpath entries in Eclipse for the time being 2025-03-27 16:03:39 +01:00
Sam Brannen 2fa7b30831 Merge branch '6.2.x' 2025-03-27 15:32:42 +01:00
Stéphane Nicoll 7ab108a321 Merge branch '6.2.x' 2025-03-27 12:12:54 +01:00
Juergen Hoeller f55ca3058b Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
2025-03-26 23:49:54 +01:00
Sébastien Deleuze 7e9c33f50e Polishing
See gh-34555
2025-03-26 10:56:34 +01:00
Dmitry Sulman 00b88ec76f Propagate CoroutineContext to WebClient filter
This commit introduces a new ResponseSpec.awaitEntityOrNull() extension
function to replace ResponseSpec.toEntity(...).awaitFirstOrNull() and
pass the CoroutineContext to the CoExchangeFilterFunction.

CoroutineContext propagation is implemented via ReactorContext and
ClientRequest attribute.

Closes gh-34555
Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
2025-03-26 10:54:53 +01:00
Juergen Hoeller 3872c1a762 Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
#	spring-jms/src/main/java/org/springframework/jms/config/AbstractJmsListenerContainerFactory.java
#	spring-jms/src/main/java/org/springframework/jms/listener/AbstractMessageListenerContainer.java
2025-03-25 17:13:02 +01:00
Brian Clozel fb423d66e3 Add ClassFile variant for class metadata reading
Prior to this commit, Spring Framework would use its own ASM fork to
read class/method/annotation metadata from bytecode. This is typically
used in configuration class parsing to build bean definitions without
actually loading classes at runtime at that step.

This commit adds support for a new metadata reading implementation that
uses the ClassFile API available as of Java 24. For now, this is turned
on by default for Java 24+.

Closes gh-33616
2025-03-25 15:33:53 +01:00
Brian Clozel 20b35f068a Add visibility and return type to SimpleMethodMetadata toString
Closes gh-34649
2025-03-25 15:32:42 +01:00
Juergen Hoeller 7d0cc6c83a Merge branch '6.2.x' 2025-03-25 00:11:30 +01:00
Sam Brannen d1a1364231 Reinstate links to JUnit 5 Javadoc APIs
Now that we are using JDK 18+ (currently JDK 24 -- see JavaConventions
in buildSrc for details), we can reinstate links to JUnit 5 Javadoc APIs.

Closes gh-27497
2025-03-24 16:58:53 +01:00
Sam Brannen 02c7719eef Update Javadoc regarding convention-based annotation attribute overrides
This commit updates the Javadoc in various places to reflect the fact
that support for convention-based annotation attribute overrides has
been removed.

See gh-28761
2025-03-24 14:13:45 +01:00
Sam Brannen d5bfd7ff8b Polishing 2025-03-24 14:13:45 +01:00
Sam Brannen 065692237c Document that @⁠AliasFor(attribute) is optional in override use cases
This commit documents that `attribute` is optional in @⁠AliasFor for
meta-annotation attribute overrides with the same name.

Closes gh-34641
2025-03-24 14:13:31 +01:00
Brian Clozel 603e559397 Update Java runtime in SDKMan! env file
See gh-34639
2025-03-24 10:17:08 +01:00
Brian Clozel b8b279d3e0 Use Java 24 to build Spring Framework
This commit also adapts tests for a Java 24 runtime.

Closes gh-34639
2025-03-24 09:51:19 +01:00
Sam Brannen 274a689a10 Revise RepeatableContainers API to better guide developers
Historically, the Spring Framework first had support for repeatable
annotations based on convention and later added explicit support for
Java 8's @⁠Repeatable facility. Consequently, the support for both
types of repeatable annotations has grown a bit intertwined over the
years. However, modern Java applications typically make use of
@⁠Repeatable, and convention-based repeatable annotations have become
more of a niche.

The RepeatableContainers API supports both types of repeatable
annotations with @⁠Repeatable support being the default. However,
RepeatableContainers.of() makes it very easy to enable support for
convention-based repeatable annotations while accidentally disabling
support for @⁠Repeatable, which can lead to subtle bugs – for example,
if convention-based annotations are combined with @⁠Repeatable
annotations. In addition, it is not readily clear how to combine
@⁠Repeatable support with convention-based repeatable annotations.

In light of the above, this commit revises the RepeatableContainers API
to better guide developers to use @⁠Repeatable support for almost all
use cases while still supporting convention-based repeatable
annotations for special use cases.

Specifically:

- RepeatableContainers.of() is now deprecated in favor of the new
  RepeatableContainers.explicitRepeatable() method.

- RepeatableContainers.and() is now deprecated in favor of the new
  RepeatableContainers.plus() method which declares the repeatable and
  container arguments in the same order as the rest of Spring
  Framework's repeated annotation APIs.

For example, instead of the following confusing mixture of
repeatable/container and container/repeatable:

RepeatableContainers.of(A.class, A.Container.class)
    .and(B.Container.class, B.class)

Developers are now be able to use:

RepeatableContainers.explicitRepeatable(A.class, A.Container.class)
    .plus(B.class, B.Container.class)

This commit also overhauls the Javadoc for RepeatableContainers and
explicitly points out that the following is the recommended approach to
support convention-based repeatable annotations while retaining support
for @⁠Repeatable.

RepeatableContainers.standardRepeatables()
    .plus(MyRepeatable1.class, MyContainer1.class)
    .plus(MyRepeatable2.class, MyContainer2.class)

See gh-20279
Closes gh-34637
2025-03-23 18:38:45 +01:00
Juergen Hoeller 7d5b3892c4 Add since 7.0 tags for stream methods
See gh-34623
2025-03-21 18:44:57 +01:00
Yanming Zhou 8819c749ce Introduce Stream variant methods for SqlQuery
Closes GH-34474

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-03-21 18:38:28 +01:00
Sam Brannen b7a9bee020 Polishing 2025-03-21 17:43:26 +01:00
Juergen Hoeller 58246ec5ec Merge branch '6.2.x' 2025-03-21 15:54:43 +01:00
Sébastien Deleuze 07ae1853ff Upgrade to Kotlin 2.1.20
Closes gh-34632
2025-03-21 15:01:17 +01:00
Sébastien Deleuze 5ce64f47b2 Add support for ImportAware in BeanRegistrar
Closes gh-34627
2025-03-21 11:49:15 +01:00
Sam Brannen 3e788e4ca1 Consistent parameter declaration order 2025-03-21 11:31:43 +01:00
Juergen Hoeller 66c94bb4a2 Merge branch '6.2.x' 2025-03-21 11:06:59 +01:00
Juergen Hoeller 0e1422820f JdbcClient holds ConversionService for queries with mapped classes
Closes gh-33467
2025-03-21 10:43:37 +01:00
rstoyanchev a145f6205e Merge branch '6.2.x' 2025-03-21 09:05:58 +00:00
Juergen Hoeller d710f73c47 Log public final method at warn level for non-interface case as well
Closes gh-33939
2025-03-21 09:40:52 +01:00
Sam Brannen 6505c4b839 Refine use of isArray() and componentType() 2025-03-20 17:28:37 +01:00
Sam Brannen cc9b39b53f Extract AnnotatedElementAdapter to public type
This commit extracts AnnotatedElementAdapter from TypeDescriptor and
introduces it as a public, top-level type in the
org.springframework.core.annotation package, and
AnnotatedElementUtils.forAnnotations() now returns an instance of
AnnotatedElementAdapter instead of AnnotatedElementForAnnotations which
has been removed.

In addition, this commit adds missing Javadoc for
AnnotatedElementAdapter and refines some of the implementation.

Closes gh-34628
2025-03-20 16:20:47 +01:00
Sam Brannen a376ef36e4 Merge branch '6.2.x' 2025-03-20 10:24:39 +01:00
Brian Clozel cacc63da20 Merge branch '6.2.x' 2025-03-19 18:19:12 +01:00
Sam Brannen 92ee20c896 Adhere to new Checkstyle rule 2025-03-19 16:29:03 +01:00
Sam Brannen 8db1340263 Merge branch '6.2.x' 2025-03-19 16:24:18 +01:00
Sébastien Deleuze 2f8c5a580a Polishing 2025-03-19 15:11:43 +01:00
Sébastien Deleuze 2bc213d703 Allow registering aliases with BeanRegistry
Closes gh-34599
2025-03-19 15:11:32 +01:00
rstoyanchev 087d239148 Merge branch '6.2.x' 2025-03-19 12:34:58 +00:00
Juergen Hoeller 73c4b46ed7 Merge branch '6.2.x' 2025-03-19 11:00:39 +01:00
Sébastien Deleuze 6ab87477ea Merge branch '6.2.x' 2025-03-18 17:58:38 +01:00
Sam Brannen 84ba6b4b26 Add package to Javadoc link 2025-03-18 16:52:12 +01:00
Sam Brannen e05d4f2f18 Merge branch '6.2.x' 2025-03-18 16:42:37 +01:00
Juergen Hoeller 69ed984a81 Merge branch '6.2.x' 2025-03-18 16:11:38 +01:00
Sam Brannen ce815006d2 Generate compiled SpEL expressions using Java 17 byte code level
Closes gh-34602
2025-03-18 12:44:01 +01:00
Sam Brannen d6a7aefd1d Add comments regarding Java 1.8 byte code level for CGLIB
Unfortunately, it is not possible to raise the byte code level beyond
Java 1.8 for classes generated using CGLIB due to the fact that CGLIB
generates STATICHOOK methods which set static final fields outside the
initializer method <clinit> (i.e., a static initialization block).

Attempting to raise the level to Java 17 (or even Java 9) results in
exceptions like the following.

Caused by: java.lang.IllegalAccessError: Update to static final field
  org.example.MyBean$$SpringCGLIB$$0.CGLIB$THREAD_CALLBACKS attempted from
  a different method (CGLIB$STATICHOOK1) than the initializer method <clinit>
    at org.example.MyBean$$SpringCGLIB$$0.CGLIB$STATICHOOK1(<generated>)
    at org.example.MyBean$$SpringCGLIB$$0.<clinit>(<generated>)

This commit therefore introduces inline comments pointing out why we
stay with Java 1.8 byte code level with CGLIB.

See gh-34602
2025-03-18 12:40:28 +01:00
Juergen Hoeller a0763d13c5 Merge branch '6.2.x' 2025-03-17 19:24:30 +01:00
Sam Brannen 30a7f7be28 Merge branch '6.2.x' 2025-03-17 18:13:04 +01:00
ChanHyeongLee 8ee09e5766 Separate commonly used DepositionTypeCheck into methods
Closes gh-34573

Signed-off-by: ChanHyeongLee <cksgud410@gmail.com>
[brian.clozel@broadcom.com: apply code conventions]
Signed-off-by: Brian Clozel <brian.clozel@broadcom.com>
2025-03-17 11:52:18 +01:00
Sébastien Deleuze de75b6e1a2 Merge branch '6.2.x' 2025-03-17 11:42:06 +01:00
Sam Brannen b660d8c553 Merge branch '6.2.x' 2025-03-16 16:15:24 +01:00
Sam Brannen 892a5cdca6 Upgrade to AspectJ 1.9.23
This commit upgrades the build to use AspectJ 1.9.23 which provides
support for JDK 23.

Closes gh-34598
2025-03-15 17:13:02 +01:00
Sam Brannen 37a135447c Rely on standard @Repeatable support in AnnotationJmxAttributeSource
This commit removes the use of RepeatableContainers.of() in
AnnotationJmxAttributeSource since that is unnecessary when using the
MergedAnnotations API with @⁠Repeatable annotations such as
@⁠ManagedOperationParameter and @⁠ManagedNotification.

Closes gh-34606
2025-03-15 16:56:56 +01:00
Sam Brannen 13efc2205b Test status quo for @⁠Repeatable annotation support in AnnotationJmxAttributeSource 2025-03-15 16:42:40 +01:00
Sam Brannen 6e1706a8a4 Polish [Annotation]JmxAttributeSource 2025-03-15 15:15:45 +01:00
Sam Brannen f678af4626 Merge branch '6.2.x' 2025-03-15 13:51:56 +01:00
Tran Ngoc Nhan 666e2df0f3 Fix formatting and update links to scripting libraries and HDIV
Closes gh-34603

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
2025-03-15 13:49:32 +01:00
Sam Brannen ae13eac86b Merge branch '6.2.x' 2025-03-14 18:06:14 +01:00
Juergen Hoeller d2a8b56742 Merge branch '6.2.x' 2025-03-13 18:49:30 +01:00
Brian Clozel 4724020174 Merge branch '6.2.x' 2025-03-13 15:26:47 +01:00
Sébastien Deleuze 90e32cadeb Merge branch '6.2.x' 2025-03-13 12:58:04 +01:00
Brian Clozel d9bd168d54 Merge branch '6.2.x' 2025-03-13 09:50:21 +01:00
Sam Brannen 68fce29ae9 Support Optional with null-safe and Elvis operators in SpEL expressions
This commit introduces null-safe support for java.util.Optional in the
following SpEL operators:

- PropertyOrFieldReference
- MethodReference
- Indexer
- Projection
- Selection
- Elvis

Specifically, when a null-safe operator is applied to an empty
`Optional`, it will be treated as if the `Optional` were `null`, and
the subsequent operation will evaluate to `null`. However, if a
null-safe operator is applied to a non-empty `Optional`, the subsequent
operation will be applied to the object contained in the `Optional`,
thereby effectively unwrapping the `Optional`.

For example, if `user` is of type `Optional<User>`, the expression
`user?.name` will evaluate to `null` if `user` is either `null` or an
empty `Optional` and will otherwise evaluate to the `name` of the
`user`, effectively `user.get().getName()` for property access.

Note, however, that invocations of methods defined in the `Optional`
API are still supported on an empty `Optional`. For example, if `name`
is of type `Optional<String>`, the expression `name?.orElse('Unknown')`
will evaluate to "Unknown" if `name` is an empty `Optional` and will
otherwise evaluate to the `String` contained in the `Optional` if
`name` is a non-empty `Optional`, effectively `name.get()`.

Closes gh-20433
2025-03-12 14:53:06 +01:00
Sam Brannen 1780e30a43 Polish documentation for SpEL Elvis operator 2025-03-12 14:52:57 +01:00
Sam Brannen c7b0550e43 Test status quo for Optional support in SpEL expressions
This is a prerequisite for null-safe Optional support.

See gh-20433
2025-03-12 14:02:17 +01:00
Sam Brannen 71716e848d Cache capitalized name in SpEL's ReflectivePropertyAccessor 2025-03-12 14:01:19 +01:00
Sam Brannen 2c05e991b5 Revise SpEL internals and documentation
This is a prerequisite for null-safe Optional support.

See gh-20433
2025-03-12 13:59:26 +01:00
Sam Brannen d3d951e44b Improve documentation for SpEL Elvis operator 2025-03-12 13:35:41 +01:00
rstoyanchev f8a82b46c1 Fix WebSocketHandlerMapping match for "/*"
Closes gh-34503
2025-03-12 12:29:35 +00:00
Juergen Hoeller 057742f27a Remove Netty 5 support
See gh-34345
2025-03-12 12:55:31 +01:00
Juergen Hoeller ea551cd9b3 Merge branch '6.2.x'
# Conflicts:
#	build.gradle
#	framework-platform/framework-platform.gradle
2025-03-12 12:52:34 +01:00
Sébastien Deleuze 1eec0382d7 Polishing
See gh-34557
2025-03-12 12:35:30 +01:00
Sébastien Deleuze 762831e742 Add BeanRegistrarDsl.register
See gh-34557
2025-03-12 12:34:04 +01:00
Juergen Hoeller 641b809d4b Upgrade to Reactor 2025.0.0-M1
Closes gh-34577
2025-03-12 12:21:00 +01:00
Juergen Hoeller 0d3f07fdd6 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-03-12 11:54:31 +01:00
Sam Brannen eb7b26db24 Merge branch '6.2.x' 2025-03-12 11:20:05 +01:00
Juergen Hoeller 86b21d9b5c Add support for BeanRegistrar registration on GenericApplicationContext
Closes gh-34574
2025-03-11 21:18:20 +01:00
Juergen Hoeller beb3a91847 Upgrade to Hibernate ORM 7.0.0.Beta4
Includes Hamcrest 3.0

See gh-33750
2025-03-11 19:17:00 +01:00
rstoyanchev 4d955f9ed8 Merge branch '6.2.x' 2025-03-10 20:59:55 +00:00
rstoyanchev f8f712dff8 Merge branch '6.2.x' 2025-03-10 18:18:05 +00:00
rstoyanchev bb2174c260 Merge branch '6.2.x' 2025-03-10 18:12:57 +00:00
rstoyanchev e73dc37513 API versioning support for Spring WebFlux
Closes gh-34566
2025-03-10 13:53:12 +00:00
rstoyanchev 51d34fff64 API versioning support for Spring MVC
See gh-34566
2025-03-10 13:53:12 +00:00
Sébastien Deleuze e9701a9ce3 Remove support for Aware interfaces in BeanRegistrar
Closes gh-34562
2025-03-10 12:14:11 +01:00
Juergen Hoeller 15b251dcd6 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-03-10 11:04:14 +01:00
Sébastien Deleuze 91d0ebe327 Refine BeanRegistryAdapterTests
Closes gh-34557
2025-03-10 10:39:21 +01:00
Phillip Webb 789791e186 Allow chained BeanRegistry registration
Add a `register(BeanRegistry registry)` method to `BeanRegistry`
to allow registration chaining.

See gh-34557
2025-03-10 10:38:50 +01:00
Sébastien Deleuze a0e2d3a221 Add support for target type to BeanRegistry
Closes gh-34560
2025-03-10 10:14:28 +01:00
Juergen Hoeller c74f897fac Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java
2025-03-08 12:23:43 +01:00
Yanming Zhou 639af7befa Add tests to ensure bean definition flag "fallback" take precedence over "defaultCandidate"
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-03-08 12:21:31 +01:00
Sam Brannen 86d81632c8 Consistently invoke isNullSafe() 2025-03-07 16:58:59 +01:00
Sam Brannen 80df88bd4f Clean up warnings in Gradle build 2025-03-07 16:58:52 +01:00
Sam Brannen 15a71f94fb Merge branch '6.2.x' 2025-03-07 13:38:50 +01:00
Sébastien Deleuze 5bd03494d4 Merge branch '6.2.x' 2025-03-07 09:30:28 +01:00
Sébastien Deleuze fda9b9a696 Polishing
See gh-18353
2025-03-07 09:00:06 +01:00
Sébastien Deleuze bedc235bab Document programmatic bean registration
This commit adds the reference documentation for the new programmatic
bean registration capabilities for both Java and Kotlin.

Closes gh-18353
2025-03-06 19:15:56 +01:00
Sébastien Deleuze 682e2d6d84 Introduce BeanRegistrarDsl
This commit introduces a new BeanRegistrarDsl that supersedes
BeanDefinitionDsl which is now deprecated.

See BeanRegistrarDslConfigurationTests for a concrete example.

See gh-18353
2025-03-06 19:15:56 +01:00
Sébastien Deleuze 496be9ca98 Introduce first-class support for programmatic bean registration
This commit introduces a new BeanRegistrar interface that can be
implemented to register beans programmatically in a concise and
flexible way.

Those bean registrar implementations are typically imported with
an `@Import` annotation on `@Configuration` classes.

See BeanRegistrarConfigurationTests for a concrete example.

See gh-18353
2025-03-06 19:14:03 +01:00
Sam Brannen aeaf52ee96 Merge branch '6.2.x' 2025-03-06 17:32:49 +01:00
Sam Brannen e09cdcd920 Remove convention-based annotation attribute override support
This commit completely removes all support for convention-based
annotation attribute overrides in Spring's annotation utilities and the
MergedAnnotations infrastructure.

Composed annotations must now use @⁠AliasFor to declare explicit
overrides for attributes in meta-annotations.

See gh-28760
Closes gh-28761
2025-03-06 16:28:21 +01:00
Sam Brannen d722b9434e Merge branch '6.2.x' 2025-03-06 16:27:48 +01:00
Juergen Hoeller 2a98b3137d Merge branch '6.2.x' 2025-03-06 15:45:18 +01:00
Sam Brannen 52e01bbb62 Merge branch '6.2.x' 2025-03-06 13:31:46 +01:00
Sam Brannen cd4e73a4a3 Fix typos in CloseStatus comments
Closes gh-34548
2025-03-06 10:26:07 +01:00
Juergen Hoeller a605f07100 Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/convert/support/GenericConversionService.java
2025-03-05 22:47:24 +01:00
Sam Brannen 5a0848b579 Merge branch '6.2.x' 2025-03-05 14:10:41 +01:00
Juergen Hoeller 2fbd54078b Merge branch '6.2.x'
# Conflicts:
#	spring-webflux/src/main/java/org/springframework/web/reactive/resource/ResourceHandlerUtils.java
#	spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHandlerUtils.java
2025-03-04 18:46:39 +01:00
Sam Brannen ca7ebd60ed Stop using deprecated ReflectionHintsPredicates.onMethod() on main 2025-03-04 11:21:37 +01:00
Sam Brannen 702c63a7e8 Merge branch '6.2.x' 2025-03-03 17:40:39 +01:00
Sam Brannen 955cc2039b Merge branch '6.2.x' 2025-03-03 15:05:11 +01:00
Sam Brannen 5ffd88cd89 Remove deprecated rowsExpected property of SqlQuery
Closes gh-34530

Co-authored-by: Yanming Zhou <zhouyanming@gmail.com>
2025-03-03 14:45:22 +01:00
Sam Brannen e9345f16dc Merge branch '6.2.x' 2025-03-03 14:34:06 +01:00
Juergen Hoeller 3632c09348 Merge branch '6.2.x' 2025-03-03 13:34:14 +01:00
Brian Clozel 84a57861d1 Merge branch '6.2.x' 2025-03-03 11:24:09 +01:00
Sébastien Deleuze 7bc712e304 Upgrade NullAway to 0.12.4
This commit also slightly refines nullness but without
significant user-side impact expected.

Closes gh-34525
2025-03-03 08:45:54 +01:00
Sébastien Deleuze f7db4bf4f0 Fix a compilation warning in spring-webflux 2025-03-02 19:15:26 +01:00
Juergen Hoeller 533ecf0244 Merge branch '6.2.x' 2025-03-01 22:21:39 +01:00
Sam Brannen 99d5e90b5e Merge branch '6.2.x' 2025-03-01 13:39:14 +01:00
rstoyanchev 788b66feac Remove UrlPathHelper in ServletWebSocketHandlerRegistry
See gh-34508
2025-02-28 16:20:38 +00:00
rstoyanchev 6a9783bb1a Merge branch '6.2.x' 2025-02-28 14:41:47 +00:00
Juergen Hoeller b610711235 Merge branch '6.2.x' 2025-02-28 14:15:36 +01:00
Sébastien Deleuze fec0bfe6b3 Merge branch '6.2.x' 2025-02-28 12:06:30 +01:00
Juergen Hoeller 03cce13937 Merge branch '6.2.x' 2025-02-27 22:54:07 +01:00
Yanming Zhou 7f020118eb Polish JdbcTemplate to use getter instead of field
1. align with others in the same source file
2. allow subclass to override

Closes: gh-34501
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2025-02-27 19:11:14 +01:00
Brian Clozel 72afd4b9bd Merge branch '6.2.x' 2025-02-27 18:58:16 +01:00
rstoyanchev 33fef8df84 Merge branch '6.2.x' 2025-02-27 14:36:24 +00:00
Brian Clozel 8a7d20f844 Upgrade Develocity and Foojay Gradle plugins 2025-02-27 15:02:07 +01:00
Brian Clozel f55fe79805 Remove Link to Jackson javadoc
The javadoc is not published by the team anymore and we should not link
to an outdated version.
2025-02-27 14:52:18 +01:00
Brian Clozel 68e9460e9b Revisit compiler configuration in project build
This commit revisit the build configuration to enforce the following:

* A single Java toolchain is used consistently with a recent Java
  version (here, Java 23) and language level
* the main source is compiled with the Java 17 "-release" target
* Multi-Release classes are compiled with their respective "-release"
  target. For now, only "spring-core" ships Java 21 variants.

Closes gh-34507
2025-02-27 14:39:43 +01:00
Sam Brannen 382caac37c Merge branch '6.2.x' 2025-02-26 15:45:09 +01:00
Sam Brannen 5f98db6ffe Use new features introduced in JUnit Jupiter 5.11 and 5.12
See gh-34416
2025-02-26 15:18:16 +01:00
Juergen Hoeller fb77fcd922 Merge branch '6.2.x' 2025-02-26 10:33:19 +01:00
Brian Clozel a1410d98de Merge branch '6.2.x' 2025-02-25 17:19:01 +01:00
Juergen Hoeller dc580740c0 Merge branch '6.2.x' 2025-02-25 16:21:09 +01:00
Brian Clozel 466ac6b703 Improve SimpleKey hashing function
Prior to this commit, `SimpleKey` would be used in Spring Framework's
caching support and its `hashCode` value would be used to efficiently
store this key in data structures.

While the current hashcode strategy works, the resulting values don't
spread well enough when input keys are sequential (which is often the
case). This can have negative performance impacts, depending on the
data structures used by the cache implementation.

This commit improves the `hashCode` function with a mixer to better
spread the hash values. This is using the mixer function from the
MurMur3 hash algorithm.

Closes gh-34483
2025-02-25 16:09:01 +01:00
Brian Clozel 8b14bf86ef Merge branch '6.2.x' 2025-02-25 10:48:09 +01:00
Brian Clozel 75329e6d9d Revisit MockHttpServletResponse for Servlet 6.1
This commit revisits the behavior of our `MockHttpServletResponse`
implementation with the javadoc clarifications applied in Servlet 6.1.

Prior to this change, adding or setting an HTTP response header with a
`null` name or value would not have the expected behavior:

* a `null` name should have no effect instead of throwing exceptions
* a `null` value when setting a header effectively removes the entry
  from the response headers

Also, this commit ensures that `IllegalStateException` are thrown if
`getWriter` is called after a previous `getOutputStream` (and vice
versa).

Closes gh-34467
2025-02-24 14:02:20 +01:00
Sam Brannen 34129f3f89 Upgrade to JUnit 5.12
Closes gh-34416
2025-02-23 17:38:04 +01:00
Juergen Hoeller 7c4594c014 Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/aot/hint/ResourceHints.java
#	spring-core/src/main/java/org/springframework/aot/hint/support/FilePatternResourceHintsRegistrar.java
2025-02-23 15:29:38 +01:00
Juergen Hoeller 1aea698088 Merge branch '6.2.x' 2025-02-23 14:04:31 +01:00
Brian Clozel db5505d55a Merge branch '6.2.x' 2025-02-21 14:42:47 +01:00
Sébastien Deleuze a08be368a2 Merge branch '6.2.x' 2025-02-21 11:33:15 +01:00
Brian Clozel a4d3977692 Remove unnecessary since tag in tests 2025-02-20 15:24:35 +01:00
Sébastien Deleuze 4ffbc4ea18 Merge branch '6.2.x' 2025-02-20 09:07:50 +01:00
Sébastien Deleuze 5dc7425a8f Merge branch '6.2.x' 2025-02-19 16:41:13 +01:00
Sébastien Deleuze e34899c06f Merge branch '6.2.x' 2025-02-19 13:58:47 +01:00
Sébastien Deleuze 24cafbb0f5 Merge branch '6.2.x' 2025-02-19 13:45:35 +01:00
Vincent Potucek 67d2635947 Sync checkstyle on buildSrc
Closes gh-34434
Signed-off-by: Vincent Potucek <vincent.potucek@sap.com>
2025-02-18 21:29:31 +01:00
Juergen Hoeller 63f6c33db6 Merge branch '6.2.x' 2025-02-18 20:45:34 +01:00
Juergen Hoeller 48aa94be46 Merge branch '6.2.x' 2025-02-18 15:18:01 +01:00
Juergen Hoeller 2e4fbd1ff3 Merge branch '6.2.x' 2025-02-18 13:14:38 +01:00
Sébastien Deleuze bc82077350 Merge branch '6.2.x' 2025-02-18 11:57:15 +01:00
Sébastien Deleuze 63ee6e6fe2 Merge branch '6.2.x' 2025-02-18 11:41:47 +01:00
Sébastien Deleuze 4dd83c814c Merge branch '6.2.x' 2025-02-18 11:28:35 +01:00
Sébastien Deleuze b8d9dee7be Refine Kotlin serialization converters/codecs conditions
This commit is a follow-up of 34410 to refine the activation conditions
of Kotlin serialization converters/codecs.

Closes gh-34438
2025-02-17 18:40:05 +01:00
Sébastien Deleuze eae09637a1 Refine Kotlin serialization reference documentation
Closes gh-34437
2025-02-17 18:40:05 +01:00
Sébastien Deleuze 6bdb9bb950 Support open polymorphism with Kotlin Serialization
This commit introduces open polymorphism support with Kotlin
Serialization in HTTP converters and codecs as a follow-up of gh-34410
which considers Kotlin Serialization as a Jackson/Gson/Jsonb equivalent
(it is not anymore configured before Jackson).

Closes gh-34433
2025-02-17 18:40:05 +01:00
rstoyanchev d9100917d1 Refine onError handling WebAsyncManager
In addition to the wrapping of errors recognized as client disconnected
errors with AsyncRequestNotUsableException, we now wrap any IOException
in the onError callback. The Servlet container would only be aware of
such an exception if it relates to the response.

Closes gh-33832
2025-02-17 12:19:36 +00:00
Sébastien Deleuze 21604d1a25 Merge branch '6.2.x' 2025-02-16 12:10:59 +01:00
Sam Brannen fe41cd6d20 Merge branch '6.2.x' 2025-02-13 16:39:21 +01:00
Stéphane Nicoll e64243d8a1 Merge branch '6.2.x' 2025-02-13 14:19:17 +01:00
Sam Brannen 6868ff7dbe Merge branch '6.2.x' 2025-02-13 13:10:37 +01:00
Juergen Hoeller 9bc7229a1c Merge branch '6.2.x' 2025-02-12 23:07:37 +01:00
Juergen Hoeller 4d6947d14f Merge branch '6.2.x' 2025-02-12 19:20:01 +01:00
Sam Brannen 8df21109f2 Merge branch '6.2.x' 2025-02-12 17:50:22 +01:00
Sam Brannen f42e886f03 Polishing 2025-02-12 17:10:22 +01:00
Sam Brannen de4db3812a Merge branch '6.2.x' 2025-02-12 16:46:58 +01:00
Sam Brannen 9eae0b6f6f Merge branch '6.2.x' 2025-02-12 16:32:05 +01:00
Sam Brannen 8a53525209 Merge branch '6.2.x' 2025-02-12 15:55:33 +01:00
rstoyanchev 1fd6ded7a0 Polishing
Closes gh-34081
2025-02-12 11:48:27 +00:00
rstoyanchev 667004e5fa Update contribution
See gh-34081
2025-02-12 11:48:27 +00:00
m4tt30c91 ba74de997a Allow to set custom cookie parsers
Provides a way to be compliant with RFC 6265 section 4.1.1.

See gh-34081
2025-02-12 11:48:27 +00:00
rstoyanchev 011e398355 UriComponents formats Collection query param URI var
Closes gh-34311
2025-02-12 11:48:27 +00:00
Mengqi Xu 295a9565a3 Format Collection query param in UriComponentsBuilder
See gh-34311

Signed-off-by: Mengqi Xu <2663479778@qq.com>
2025-02-12 11:48:27 +00:00
Juergen Hoeller b07ff1c2d4 Merge branch '6.2.x' 2025-02-12 12:17:54 +01:00
Sébastien Deleuze bb33a3efa3 Upgrade to Kotlin 2.1.10 2025-02-12 11:34:37 +01:00
Sébastien Deleuze 3956a36837 Merge branch '6.2.x' 2025-02-12 11:34:22 +01:00
Brian Clozel 5c09435816 Fix warnings
See gh-34409
2025-02-12 08:48:04 +01:00
Brian Clozel 7271358ea4 Merge branch '6.2.x' 2025-02-11 22:34:49 +01:00
Juergen Hoeller 39bd530461 Consistently use @Nullable annotation from JSpecify 2025-02-11 22:16:13 +01:00
Juergen Hoeller dce3f71b7d Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-02-11 22:11:45 +01:00
Brian Clozel 7077809561 Configure Kotlin JSON converters as Jackson alternative
Prior to this commit, Spring MVC and WebFlux would consider the
"kotlinx.serialization" JSON codecs and converters in addition to other
JSON alternatives like Jackson, Gson and Jsonb.

This would cause issues because while in most cases this library is only
involved if the type is annotated with "@Serializable", this is not true
for Java enums. In this particular case, the codec shadows Jackson and
causes issues.

This commit now considers kotlinx.serialization JSON support as an
alternative to Jackson. Just like Jsonb and GSON, this is only
auto-detected if Jackson is not present.
We received consistent feedback that kotlinx.serialization is popular in
Kotlin libraries and is often a transitive dependency. As a result, we
cannot consider its presence on the classpath as a strong enough signal
to configure it by default.

Closes gh-34410
2025-02-11 20:05:53 +01:00
Sam Brannen 6ded25ba28 Merge branch '6.2.x' 2025-02-11 16:31:12 +01:00
Sam Brannen e78e802647 Use JSpecify's @⁠Nullable on main 2025-02-11 16:17:32 +01:00
Sam Brannen 18e31fcfba Merge branch '6.2.x' 2025-02-11 16:12:32 +01:00
Stéphane Nicoll 722701a451 Merge branch '6.2.x' 2025-02-11 16:01:09 +01:00
rstoyanchev e9d16da633 Remove Netty 5 support
Closes gh-34345
2025-02-11 12:27:33 +00:00
rstoyanchev bae12e739d Merge branch '6.2.x' 2025-02-11 11:18:23 +00:00
Sam Brannen 85855ec793 Merge branch '6.2.x' 2025-02-11 11:57:48 +01:00
Stéphane Nicoll 2f6d142ad7 Merge branch '6.2.x' 2025-02-11 11:41:02 +01:00
Sam Brannen 7557967f9e Stop using explicitly aliased value attribute as @⁠Component name
Prior to this commit, if a custom stereotype annotation was
meta-annotated with @⁠Component and declared a local String `value`
attribute that was explicitly configured (via @⁠AliasFor) as an
override for an attribute other than @⁠Component.value, the local
`value` attribute was still used as a convention-based override for
@⁠Component.value.

Consequently, a local `value` attribute was used as a custom
@⁠Component name, even when that is clearly not the intent.

To address that, this commit revises the logic in
AnnotationBeanNameGenerator so that a `value` attribute which is
explicitly aliased to something other than @⁠Component.value is no
longer used as an explicit @⁠Component name.

See gh-34317
Closes gh-34346
2025-02-10 18:21:29 +01:00
Juergen Hoeller 4ba14ca58c Merge branch '6.2.x' 2025-02-10 15:55:26 +01:00
Sam Brannen b78d371746 Merge branch '6.2.x' 2025-02-10 13:30:30 +01:00
rstoyanchev b0a1a11612 Merge branch '6.2.x' 2025-02-10 11:15:08 +00:00
Sébastien Deleuze e49d2da443 Upgrade to Error Prone 2.36.0
Closes gh-34396
2025-02-10 12:09:19 +01:00
Sam Brannen e6f2f86f9f Merge branch '6.2.x' 2025-02-10 11:49:50 +01:00
Sam Brannen 1a29fbda48 Restore @⁠Nullable on AnnotatedElementUtils.getAllAnnotationAttributes(...)
Closes gh-34394
2025-02-10 10:52:32 +01:00
Brian Clozel 6d63abd4e9 Merge branch '6.2.x' 2025-02-10 09:24:44 +01:00
Sam Brannen e81fcc34de Merge branch '6.2.x' 2025-02-09 11:40:02 +01:00
Brian Clozel 11a1858e79 Merge branch '6.2.x' 2025-02-08 16:20:38 +01:00
Sam Brannen 68fcf81c4d Merge branch '6.2.x' 2025-02-08 13:33:39 +01:00
Juergen Hoeller 3fff3b8a6d Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java
#	spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
2025-02-07 19:03:37 +01:00
Sam Brannen bd9ae6bd2a Merge branch '6.2.x' 2025-02-07 18:34:07 +01:00
Sam Brannen a09f454dfc Merge branch '6.2.x' 2025-02-07 18:27:34 +01:00
Sam Brannen cf1d274baa Merge branch '6.2.x' 2025-02-07 18:11:01 +01:00
rstoyanchev 55a090602b Merge branch '6.2.x' 2025-02-07 13:23:14 +00:00
Brian Clozel 0c739016d4 Merge branch '6.2.x' 2025-02-06 18:33:42 +01:00
Sébastien Deleuze 262ce16bb4 Upgrade to Kotlin Serialization 1.8
Closes gh-34378
2025-02-06 17:42:19 +01:00
Sébastien Deleuze 66b3a94376 Upgrade to Kotlin Coroutines 1.10
Closes gh-34376
2025-02-06 17:41:44 +01:00
Brian Clozel e8f71ab5ef Simplify HttpHeaders constructor
As of gh-33913, `HttpHeaders` does not implement the `MultiValueMap`
contract anymore, so we can take this opportunity to simplify one of the
constructors to not consider that the argument could be an `HttpHeaders`
instance. This case is already covered by the other constructor.

See gh-33913
2025-02-06 14:37:16 +01:00
Bryce J. Fisher 2a846c9594 Add HttpHeaders.copyOf factory method
Prior to this commit, the `HttpHeaders` class would provide constructor
variants where the instances are are backed by the existing headers
collection given as a parameter.

While such constructors are clearly documented and meant for internal
usage, there are cases where developers would like to copy the data from
an existing headers instance without being backed by the same collection
instance and thus, being mutated from some place else.

This commit introduces new factory methods `HttpHeaders.copyOf` for this
purpose. While this name aligns with some of the Java collections
factory methods, in this case the returned instance is not immutable, on
purpose. `HttpHeaders` does not extends `MultiValueMap` anymore and
shouldn't be seen as such.

Closes: gh-34341

Signed-off-by: Bryce J. Fisher <bryce.fisher@gmail.com>
[brian.clozel@broadcom.com: reduce scope and update javadoc]
Signed-off-by: Brian Clozel <brian.clozel@broadcom.com>
2025-02-06 14:24:41 +01:00
Sébastien Deleuze 7695be0079 Merge branch '6.2.x' 2025-02-06 09:19:42 +01:00
Sébastien Deleuze e44a3eb39a Merge branch '6.2.x' 2025-02-05 17:47:58 +01:00
rstoyanchev 03984bacf4 Merge branch '6.2.x' 2025-02-05 14:34:11 +00:00
Stéphane Nicoll 49bd8333e8 Merge branch '6.2.x' 2025-02-05 14:42:42 +01:00
Sam Brannen e997e16cd1 Merge branch '6.2.x' 2025-02-05 13:43:46 +01:00
Stéphane Nicoll fce0389e23 Merge branch '6.2.x' 2025-02-05 11:53:30 +01:00
Stéphane Nicoll 3c4d535723 Merge branch '6.2.x' 2025-02-04 16:01:45 +01:00
Stéphane Nicoll 0db2c7d40c Merge pull request #33729 from dssievewright
* pr/33729:
  Polish "Prevent further configuration once SqlCall is compiled"
  Prevent further configuration once SqlCall is compiled

Closes gh-33729
2025-02-04 15:46:48 +01:00
Stéphane Nicoll 35dea59ce4 Polish "Prevent further configuration once SqlCall is compiled"
See gh-33729
2025-02-04 15:45:18 +01:00
Dan Sievewright 8810913f30 Prevent further configuration once SqlCall is compiled
This commit prevents AbstractJdbcCall to be further configured once it
is compiled.

See gh-33729
2025-02-04 15:43:01 +01:00
Juergen Hoeller 83ab71725f Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/PropertyEditorRegistrySupport.java
2025-02-04 13:31:37 +01:00
Stéphane Nicoll dfe6dc1ee5 Merge branch '6.2.x' 2025-02-04 09:30:02 +01:00
rstoyanchev ecf75f2f40 Merge branch '6.2.x' 2025-02-03 15:31:32 +00:00
Juergen Hoeller 088d53adb4 Merge branch '6.2.x' 2025-02-03 15:24:59 +01:00
Juergen Hoeller ecc7ddd96b Merge branch '6.2.x' 2025-01-31 22:28:50 +01:00
Juergen Hoeller 121be15004 Merge branch '6.2.x' 2025-01-31 15:17:44 +01:00
Juergen Hoeller 7405e20690 Merge branch '6.2.x'
# Conflicts:
#	spring-core/src/main/java/org/springframework/core/ResolvableType.java
2025-01-30 15:38:09 +01:00
Sébastien Deleuze 4620d864dd Refine GenericApplicationContext#registerBean nullness
Closes gh-34343
2025-01-30 12:26:31 +01:00
Johnny Lim 042b78f609 Fix Javadoc @code tags
Signed-off-by: Johnny Lim <izeye@naver.com>
2025-01-30 13:33:42 +09:00
Brian Clozel d4030a87e2 Merge branch '6.2.x' 2025-01-29 18:28:52 +01:00
Sam Brannen 7a98e210da Remove obsolete code
See gh-34331
2025-01-29 18:06:28 +01:00
Sam Brannen 38bdf0cd27 Merge branch '6.2.x' 2025-01-29 17:52:42 +01:00
Sam Brannen c9f12aa804 Merge branch '6.2.x' 2025-01-29 17:40:49 +01:00
Brian Clozel a853e94810 Merge branch '6.2.x' 2025-01-29 16:15:16 +01:00
rstoyanchev f5b5f9a639 Fix forwarded host formatting
Follow-up to recent commit
75e2e2c3c7

Closes gh-34253
2025-01-28 15:53:14 +00:00
rstoyanchev 83cdd58ac8 Update localAddress handling in StandardWebSocketClient
Closes gh-34331
2025-01-28 15:49:58 +00:00
rstoyanchev 52c187bf64 Merge branch '6.2.x' 2025-01-28 15:37:38 +00:00
Sébastien Deleuze db3c2b39b1 Remove HttpHeaders#asMultiValueMap usages from Kotlin tests
Closes gh-34327
2025-01-27 15:57:54 +01:00
Sam Brannen 36cd069c6e Exclude spring-jcl from nohttp check on main branch
The spring-jcl module no longer exists on main, but it still exists on
the 6.2.x branch and previous branches and can cause build failures when
switching between branches.
2025-01-27 15:33:43 +01:00
Sam Brannen 5574f45cb1 Merge branch '6.2.x' 2025-01-27 15:22:10 +01:00
Sébastien Deleuze 1167b30b3f Merge branch '6.2.x' 2025-01-27 15:07:59 +01:00
Sam Brannen 86b04b7b69 Merge branch '6.2.x' 2025-01-24 15:34:10 +01:00
Sébastien Deleuze 673e2b0dd2 Refine null-safety in DestinationPatternsMessageCondition
See gh-28797
2025-01-23 14:16:45 +01:00
Sam Brannen 35fede1382 Polish Nullness 2025-01-23 11:16:00 +01:00
Sam Brannen 564eb77a52 Merge branch '6.2.x' 2025-01-23 11:00:51 +01:00
Stéphane Nicoll fc075d110e Polish 2025-01-23 10:35:27 +01:00
Sébastien Deleuze 8a89248b16 Refine Nullness Javadoc
See gh-34261
2025-01-22 13:21:17 +01:00
Sébastien Deleuze 7f21443a1b Refine null-safety based on IDEA warnings
See gh-28797
2025-01-22 13:20:11 +01:00
Brian Clozel 4189f8b477 Update GA release pipeline
Push milestones versions to Maven Central.
2025-01-21 20:32:10 +01:00
Brian Clozel f85752a956 Fix hints and predicates for Field reflective access
This commit revisits the arrangement for Field hints after changes made
in gh-34239.

Closes gh-34294
2025-01-21 20:05:12 +01:00
Juergen Hoeller 3302bc46f8 Merge branch '6.2.x' 2025-01-21 19:16:08 +01:00
Brian Clozel 4763877259 Merge branch '6.2.x' 2025-01-21 17:27:54 +01:00
Sam Brannen d888432dca Merge branch '6.2.x' 2025-01-21 17:23:28 +01:00
Sébastien Deleuze 1115be581a Add primitive type support to Nullness
See gh-34261
2025-01-21 16:32:52 +01:00
Sébastien Deleuze d83be7c33a Mention the Nullness API in the null safety refdoc
See gh-34261
2025-01-21 15:47:10 +01:00
Sébastien Deleuze b3e888279e Introduce Nullness API
This commit introduces a Nullness enum with related utility methods
in order to detect if a type usage, a field, a method return type or a
parameter is unspecified, nullable or not null.

JSpecify annotations are fully supported, as well as Kotlin null safety
and `@Nullable` annotations regardless of their package (from Spring,
JSR-305 or Jakarta set of annotations for example).

Closes gh-34261
2025-01-21 14:59:32 +01:00
rstoyanchev 92472a6b62 Merge branch '6.2.x' 2025-01-21 12:23:05 +00:00
Sam Brannen a257697775 Merge branch '6.2.x' 2025-01-21 11:32:11 +01:00
Juergen Hoeller 001ccca5e6 Merge branch '6.2.x' 2025-01-20 18:18:48 +01:00
Sam Brannen 62405560af Polishing 2025-01-20 17:18:44 +01:00
Sam Brannen a8de8ac0da Merge branch '6.2.x'
Closes gh-34286
2025-01-20 17:11:12 +01:00
Sam Brannen 7fedb9c1d4 Remove binary array name handling in ClassUtils.forName()
In ClassUtils.forName(), we originally delegated to
ClassLoader.loadClass(), which does not support loading classes from
binary names for arrays (such as "[[I" for "int[][]" or
"[Ljava.lang.String;" for "String[]"); whereas, Class.forName() does
support binary names for arrays.

However, in Spring Framework 5.1.1 we switched from using
ClassLoader.loadClass() to Class.forName() in ClassUtils.forName() (see
gh-21867), which makes our custom handling of binary names for arrays
in ClassUtils.forName() obsolete.

In light of that, this commit removes our custom binary array name
handling support from ClassUtils.forName().

Closes gh-34291
2025-01-20 16:16:05 +01:00
Stéphane Nicoll eda7af764b Merge branch '6.2.x' 2025-01-20 15:13:42 +01:00
Sébastien Deleuze 1763334180 Refine KotlinDetector usages and implementation
This commit refines KotlinDetector usages and implementation in order
to remove preliminary KotlinDetector#isKotlinReflectPresent invocations
and to ensure that KotlinDetector methods are implemented safely and
efficiently for such use case.

Closes gh-34275
2025-01-20 12:34:28 +01:00
Brian Clozel ffd7b93dde Merge branch '6.2.x' 2025-01-20 08:03:12 +01:00
Brian Clozel 4a95b804e9 Merge branch '6.2.x' 2025-01-20 07:58:13 +01:00
Sam Brannen 113c101bed Merge branch '6.2.x' 2025-01-18 17:03:31 +01:00
Sam Brannen ef05b82920 Revise @⁠Nullable declarations for consistency with usage in 7.0 2025-01-18 15:07:46 +01:00
Sam Brannen 863ccd81d5 Merge branch '6.2.x' 2025-01-18 15:06:35 +01:00
Sam Brannen f6602c2f68 Merge branch '6.2.x' 2025-01-18 14:05:19 +01:00
Brian Clozel 309f5bebdb Fixing Kotlin annotations architecture rule
See gh-34276
2025-01-17 17:57:25 +01:00
Brian Clozel 1bd9848d42 Add ArchUnit architecture checks
This commit adds a new custom build Plugin, the `ArchitecturePlugin`.
This plugin is using ArchUnit to enforce several rules in the main
sources of the project:

* All "package-info" should be `@NullMarked`
* Classes should not import forbidden types (like "reactor.core.support.Assert"
* Java Classes should not import "org.jetbrains.annotations.*" annotations
* Classes should not call "toLowerCase"/"toUpperCase" without a Locale
* There should not be any package tangle

Duplicate rules were removed from checkstyle as a result.
Note, these checks only consider the "main" source sets, so test
fixtures and tests are not considered. Repackaged sources like JavaPoet,
CGLib and ASM are also excluded from the analysis.

Closes gh-34276
2025-01-17 17:21:10 +01:00
Sam Brannen 1ab3d89f10 Merge branch '6.2.x' 2025-01-17 11:48:13 +01:00
rstoyanchev 31578c4170 Remove deprecated web APIs in spring-test
See gh-33809
2025-01-16 15:47:52 +00:00
rstoyanchev 2ed281f6a8 Remove deprecated WebFlux APIs
See gh-33809
2025-01-16 15:47:52 +00:00
rstoyanchev eb15b26abe Add since and forRemoval to @Deprecated 2025-01-16 15:47:52 +00:00
rstoyanchev 5f6df35ec4 Remove deprecated LastModified APIs
See gh-33809
2025-01-16 15:47:45 +00:00
Brian Clozel 65df3097e0 Upgrade to JSONAssert 2.0-rc1
Closes gh-33799
2025-01-16 14:10:13 +01:00
Stéphane Nicoll c6b060a2eb Merge branch '6.2.x' 2025-01-16 10:06:31 +01:00
Sébastien Deleuze 94e3b54581 Fix the build
This commit add missing compileOnly jsr305 dependencies.
2025-01-16 08:11:49 +01:00
Johnny Lim 80a84945ef Fix depth for NullAway subsections in reference docs
Closes gh-34267
Signed-off-by: Johnny Lim <izeye@naver.com>
2025-01-16 07:48:11 +01:00
rstoyanchev 6873427aa7 Merge branch '6.2.x' 2025-01-15 19:04:57 +00:00
rstoyanchev 3b1d14a64d Fix checkstyle warning
See gh-34253
2025-01-15 18:13:42 +00:00
rstoyanchev 75e2e2c3c7 Consistent formatting of forward for host
Closes gh-34253
2025-01-15 17:53:30 +00:00
Juergen Hoeller c4fe18ca79 Fix merge result 2025-01-15 18:31:16 +01:00
Juergen Hoeller 38a41b6d01 Merge branch '6.2.x'
# Conflicts:
#	framework-platform/framework-platform.gradle
2025-01-15 18:29:30 +01:00
rstoyanchev b8c51a2767 Additional theme removal updates
See gh-33809
2025-01-15 17:17:38 +00:00
Sam Brannen 9cfece0d54 Fix compilation error in ResolvableTypeTests 2025-01-15 17:29:01 +01:00
rstoyanchev 4920086225 Remove deprecated web APIs
See gh-33809
2025-01-15 16:26:16 +00:00
rstoyanchev 83c020eea5 Remove deprecated HttpStatus codes
See gh-33809
2025-01-15 16:26:16 +00:00
rstoyanchev 9f77d5ff1f Remove deprecated ThemeResolver support
See gh-33809
2025-01-15 16:26:16 +00:00
rstoyanchev 9ddbf800b9 Remove deprecated APIs in spring-web
See gh-33809
2025-01-15 16:26:16 +00:00
Sam Brannen 00ee0ab99c Fix compilation error in ResolvableTypeTests 2025-01-15 17:20:19 +01:00
Sam Brannen 6a81de95ab Merge branch '6.2.x' 2025-01-15 17:16:51 +01:00
Stéphane Nicoll 2c749ebdb7 Merge branch '6.2.x' 2025-01-15 17:08:09 +01:00
Juergen Hoeller 7e71001896 Merge branch '6.2.x' 2025-01-15 15:03:38 +01:00
Simon Baslé caf84ffe7d Revisit HttpHeadersAssert after HttpHeaders API changes
- add various assertions to HttpHeadersAssert
 - improve assertion test coverage
 - remove niche size assertions

Closes gh-34168

Co-authored-by: Stephane Nicoll <stephane.nicoll@broadcom.com>
2025-01-15 11:42:59 +01:00
Stéphane Nicoll 448d6c6ebf Merge branch '6.2.x' 2025-01-15 11:22:23 +01:00
Stéphane Nicoll 05d8604012 Merge branch '6.2.x' 2025-01-14 17:36:58 +01:00
Stéphane Nicoll 46327d6e9b Merge branch '6.2.x' 2025-01-14 16:41:19 +01:00
Sébastien Deleuze 19f647ab8c Set -Xjdk-release=17 for Kotlin build
Needed due to https://youtrack.jetbrains.com/issue/KT-49746.

See gh-34220
2025-01-14 12:35:54 +01:00
Sébastien Deleuze c71bfc7aed Update null-safety documentation
Closes gh-34140
2025-01-14 12:35:53 +01:00
Sébastien Deleuze 2f59701148 Specify generic type nullness in spring-webmvc
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 69bfb64dfd Specify generic type nullness in spring-webflux
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 380c9e318c Specify generic type nullness in spring-web
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze e2216ddc32 Specify generic type nullness in spring-test
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 5be36ce8ce Specify generic type nullness in spring-r2dbc
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 2f8ff7eb41 Specify generic type nullness in spring-orm
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 8b64e2735e Specify generic type nullness in spring-messaging
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 8299a617b9 Specify generic type nullness in spring-jdbc
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 4c988146bc Specify generic type nullness in spring-expression
See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 9d9383aaeb Specify generic type nullness in spring-core
Also in spring-core-test.

See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 435cb0c7d6 Specify generic type nullness in spring-context
Also in spring-context-support.

See gh-34140
2025-01-14 12:35:02 +01:00
Sébastien Deleuze 928a3c7184 Specify generic type nullness in spring-beans
See gh-34140
2025-01-14 12:35:01 +01:00
Sébastien Deleuze f52f83349c Specify generic type nullness in spring-aop
See gh-34140
2025-01-14 12:35:01 +01:00
Sébastien Deleuze c0039fb624 Enable NullAway JSpecify mode
See gh-34140
2025-01-14 12:26:20 +01:00
Sam Brannen b9c1aec62f Merge branch '6.2.x' 2025-01-14 11:38:45 +01:00
Brian Clozel c02251672e Polishing RuntimeHintsPredicates deprecations
This commit also deprecates the types returned by deprecated methods as
they will be removed as well in the future.

See gh-34239
2025-01-14 10:28:39 +01:00
Brian Clozel 9b17928143 Merge branch '6.2.x' 2025-01-13 20:21:40 +01:00
Juergen Hoeller ae9abc8545 Merge branch '6.2.x' 2025-01-13 17:49:25 +01:00
Brian Clozel d28c0396c9 Update runtime hints predicates after GraalVM changes
As of gh-33847, method and field introspection is included by default
when a type is registered for reflection.
Many methods in ReflectionHintsPredicates are now mostly useless as their
default behavior checks for introspection.

This commit deprecates those methods and promotes instead invocation
variants. During the upgrade, developers should replace it for an
`onType` check if only reflection is required. If they were checking for
invocation, they should use the new 'onXInvocation` method.

Closes gh-34239
2025-01-13 15:34:34 +01:00
Stéphane Nicoll 6be811119e Merge branch '6.2.x' 2025-01-13 13:58:16 +01:00
Juergen Hoeller 87da67165a Merge branch '6.2.x'
# Conflicts:
#	spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
2025-01-13 13:06:14 +01:00
Stéphane Nicoll 6888137cb6 Merge branch '6.2.x' 2025-01-13 09:12:32 +01:00
Juergen Hoeller b8c3f03ec0 Merge branch '6.2.x' 2025-01-12 18:13:04 +01:00
Stéphane Nicoll 92ede84ea3 Merge branch '6.2.x' 2025-01-11 12:36:54 +01:00
rstoyanchev 8c03d55905 Deprecate HandlerMappingIntrospector
Closes gh-34019
2025-01-10 18:50:47 +00:00
Mengqi Xu dc98a7960a Remove the catch of NPE because this issue had resolved at Jetty 12.0.2.
Closes gh-34235
Signed-off-by: Mengqi Xu <2663479778@qq.com>
2025-01-10 18:12:51 +01:00
Stéphane Nicoll 4d0f1729cb Restore deprecated constructor for binary compatibility support
Code that compiles against the non-deprecated version does not see the
new constructor that has been introduced. As such, there is no way for
them to migrate to it without resorting to reflection.

This commit restores the deprecated constructor so that people can try
the latest version more easily.

Closes gh-34238
2025-01-10 18:07:53 +01:00
Brian Clozel c85e56aac9 Polishing
See gh-34237
2025-01-10 18:06:46 +01:00
Brian Clozel f2a18e5920 Upgrade to Jetty 12.1.0.alpha0
Closes gh-34237
2025-01-10 18:03:10 +01:00
rstoyanchev 2561a60968 Update MockRestServiceServer bufferContent
Connect the existing bufferContent option to the new RestClient and
RestTemplate equivalent feature.

See gh-33785
2025-01-10 14:39:24 +00:00
rstoyanchev 39bb751546 Polishing 2025-01-10 14:39:24 +00:00
rstoyanchev be5542a7a7 Add buffering predicate to RestTemplate
See gh-33785
2025-01-10 14:39:24 +00:00
Sébastien Deleuze ec48c47886 Make URI template variables nullable
Closes gh-34221
2025-01-10 11:39:21 +01:00
Brian Clozel bce7d87151 Merge branch '6.2.x' 2025-01-10 11:22:38 +01:00
Sébastien Deleuze 87f1961c3e Polishing 2025-01-09 17:53:28 +01:00
Sébastien Deleuze 52f325db82 Fix javadoc Gradle task
This commit refines the javadoc options and removes aspectj broken link.

See gh-34220
2025-01-09 17:28:09 +01:00
Sébastien Deleuze 262a3130d4 Upgrade SDK env to Java 23.0.1
See gh-34220
2025-01-09 16:08:44 +01:00
Sébastien Deleuze df1ed0a4dc Refine dependencies to fix compilation with Java 23
Closes gh-34220
2025-01-09 16:01:39 +01:00
Sébastien Deleuze 483985b173 Suppress serialization warnings
This commit suppresses serialization warnings triggered by the upgrade
of javac from 17 to 23.

See gh-34220
2025-01-09 16:01:30 +01:00
Sébastien Deleuze b85a76f983 Configure the Gradle toolchain to use Java 23
In order to be able to fix gh-34140 which requires using at least a
Java 22 compiler, this commit intends to change the configuration of
the Gradle toolchain to use Java 23, while setting the Java release to
Java 17 (or other versions when using MRJARs) when relevant in order to
keep the current Java 17 baseline.

See gh-34220
2025-01-09 15:59:34 +01:00
Stéphane Nicoll 63770ba516 Remove Java samples from Kotlin samples compilation 2025-01-09 11:36:48 +01:00
Sébastien Deleuze f55c234eb4 Provide guidelines for NullAway
Closes gh-34202
2025-01-08 17:34:24 +01:00
Sébastien Deleuze a73a819c82 Refine @SuppressWarnings("NullAway")
See gh-28797
2025-01-08 17:34:24 +01:00
rstoyanchev 82941caa00 Polishing in DefaultRestClientBuilder
Align order of fields with order of methods on Builder.
2025-01-08 15:52:40 +00:00
rstoyanchev 4b9be5aaf8 Add setBody with byte[] to StreamingHttpOutputMessage
Sometimes the content to write is already buffered, but requires boilerplate
to write through a Body callback.

See gh-33785
2025-01-08 15:52:40 +00:00
rstoyanchev 819a13f22d Apply predicate to BufferingClientHttpRequestFactory
The bufferingPredicate configured in RestClient.Builder can and should also
be used in the (existing) shouldBuffer protected method in
BufferingClientHttpRequestFactory since the factory is no longer intended
for direct use, and in any case the setting should apply in all cases
including when there are no interceptors.

See gh-33785
2025-01-08 15:52:40 +00:00
Brian Clozel 808d1b6413 Merge branch '6.2.x' 2025-01-08 16:34:46 +01:00
rstoyanchev 27c4f0e29d Built-in buffering support in RestClient
Closes gh-33785
2025-01-08 13:46:15 +00:00
rstoyanchev 6a0c5ddf68 Refactoring in AbstractBufferingClientHttpRequest
Extract a protected method for subclasses to use to perform the
actual (end-of-chain) request execution.

See gh-33785
2025-01-08 13:46:15 +00:00
rstoyanchev b9efa91ecc Polishing in client tests 2025-01-08 13:46:15 +00:00
rstoyanchev 3f7d3cbbd3 Add chaining methods to ClientHttpRequestInterceptor
See gh-34169
2025-01-08 13:46:15 +00:00
Brian Clozel c970a6052a Merge branch '6.2.x' 2025-01-08 14:40:41 +01:00
Brian Clozel 396f04a3b9 Remove outdated TODO task 2025-01-08 13:49:16 +01:00
Brian Clozel 7a71d7c3a8 Merge branch '6.2.x' 2025-01-08 11:19:49 +01:00
Brian Clozel 774231db1e Merge branch '6.2.x' 2025-01-07 22:15:16 +01:00
Sam Brannen e8788c7e3e Merge branch '6.2.x' 2025-01-07 17:32:42 +02:00
Brian Clozel 1b7ccbce2a Deprecate PathResource variant
This commit deprecates the `PathResource` implementation variant in
favor of `FileSystemResource`. This was already pointing to
`FileSystemResource` as of Spring Framework 5.1 and we now consider this
variant as deprecated.

Closes gh-34206
2025-01-07 16:09:37 +01:00
Sébastien Deleuze e184860ca4 Use "nullness" instead of "nullability"
This commit updates the null-safety documentation to use "nullness"
instead of "nullability" in order to be consistent with the JSpecify
documentation.

See gh-28797
2025-01-07 15:03:05 +01:00
Sam Brannen a3594e7207 Merge branch '6.2.x' 2025-01-07 11:53:04 +02:00
Sébastien Deleuze 96f7d50abf Remove unneeded NullAway warning suppressions
This commit removes warning suppressions related to uber/NullAway#1113
which is now fixed.

See gh-28797
2025-01-07 09:57:56 +01:00
Sébastien Deleuze 2697aea15f Upgrade NullAway to 0.12.3
This commit also leverages the new OnlyNullMarked flag.

See gh-28797
2025-01-07 09:57:56 +01:00
Brian Clozel 284f6057cc Merge branch '6.2.x' 2025-01-07 09:56:26 +01:00
Brian Clozel 68833e43aa Skip DCO sign-off for organization members
See https://github.com/dcoapp/app
2025-01-07 09:22:08 +01:00
Brian Clozel 2cdc406e71 Merge branch '6.2.x' 2025-01-07 09:04:05 +01:00
Brian Clozel e8e722fb59 Allow multiple executions of ClientHttpRequestInterceptors
Prior to this commit, an `ClientHttpRequestInterceptor` implementation
could delegate HTTP calls to the next `ClientHttpRequestExecution` only
once. Calling the execution would advance to the next interceptor in the
chain in a mutable fashion for the entire lifetime of the current
exchange.

This commit changes the implementation of `InterceptingClientHttpRequest`
so that a `ClientHttpRequestInterceptor` implementation can call
`ClientHttpRequestExecution#execute` multiple times.

This is especially useful for interceptors in case they want to issue
other HTTP requests without needing another `RestTemplate` or
`RestClient` instance provided out of band.

Closes gh-34169
2025-01-06 19:29:09 +01:00
Sébastien Deleuze 292a3a4895 Refine spring-aop arguments nullness
See gh-28797
2025-01-06 16:52:34 +01:00
Sébastien Deleuze 5e9b07b56d Use JSpecify annotations in org.aopalliance.*
See gh-28797
2025-01-06 16:52:34 +01:00
rstoyanchev e2ea87fe4f Merge branch '6.2.x' 2025-01-06 12:13:56 +00:00
Sam Brannen 8bba4f641f Update copyright headers to 2025 2025-01-05 17:02:14 +02:00
Sam Brannen bc499df6ce Merge branch '6.2.x' 2025-01-05 17:01:12 +02:00
Sam Brannen 2eede7ad1c Update Eclipse code template to use "@⁠since 7.0" 2025-01-05 16:57:02 +02:00
Sam Brannen 4345acd7b9 Merge branch '6.2.x' 2025-01-05 12:29:50 +02:00
Sam Brannen 7b1cdb5efb Merge branch '6.2.x' 2025-01-05 12:18:52 +02:00
Sam Brannen 69ef885b68 Merge branch '6.2.x' 2025-01-04 15:59:47 +02:00
Sébastien Deleuze 57c0d95007 Fix detection of JSpecify annotations on parameters
See gh-28797
2025-01-03 17:29:49 +01:00
Stéphane Nicoll f136e27ccf Merge branch '6.2.x' 2025-01-03 16:54:32 +01:00
Sam Brannen 99bcd3a845 Remove unused code 2025-01-03 17:43:17 +02:00
Sam Brannen e26c161ae9 Clean up warnings 2025-01-03 17:42:57 +02:00
Sam Brannen 087641c508 Merge branch '6.2.x' 2025-01-03 17:29:14 +02:00
Sam Brannen bab8a8300b Merge branch '6.2.x' 2025-01-03 16:44:26 +02:00
Brian Clozel b6de2b0611 Merge branch '6.2.x' 2025-01-02 20:12:14 +01:00
Stéphane Nicoll 69b7624629 Merge branch '6.2.x' 2025-01-01 10:08:45 +01:00
Stéphane Nicoll 333dfd1577 Fix build failure 2024-12-31 10:02:00 +01:00
Stéphane Nicoll 067bbce1d3 Merge branch '6.2.x' 2024-12-31 09:49:53 +01:00
rstoyanchev 48308aee26 Merge branch '6.2.x' 2024-12-30 14:48:04 +00:00
Sébastien Deleuze e0521fc1a1 Merge branch '6.2.x' 2024-12-30 12:15:46 +01:00
Sébastien Deleuze 08d7a38546 Merge branch '6.2.x' 2024-12-30 09:06:24 +01:00
Simon Baslé a2bc1ded73 Polishing, fix checkstyle errors 2024-12-27 14:00:38 +01:00
Simon Baslé eb9ee9fafa Polishing
`@since` missing tags in some methods related to the HttpHeaders change
2024-12-27 12:14:23 +01:00
Simon Baslé f025d60b92 Merge branch '6.2.x' 2024-12-27 11:00:10 +01:00
Stéphane Nicoll 5aab947b6e Merge branch '6.2.x' 2024-12-27 09:33:18 +01:00
Sébastien Deleuze 6c86914709 Refine null-safety in the spring-webmvc module
Closes gh-34164
2024-12-26 19:23:33 +01:00
Sébastien Deleuze b332920b17 Refine null-safety in the spring-webflux module
Closes gh-34163
2024-12-26 19:14:04 +01:00
Sébastien Deleuze 5fba926ab6 Refine null-safety in the spring-web module
Closes gh-34162
2024-12-26 18:50:17 +01:00
Sébastien Deleuze a442c180f1 Refine null-safety in the spring-test module
Closes gh-34161
2024-12-26 17:49:17 +01:00
Sébastien Deleuze 7417bd0ac1 Refine null-safety in the spring-r2dbc module
Closes gh-34160
2024-12-26 16:29:27 +01:00
Sébastien Deleuze 73b24b6f7b Refine null-safety in the spring-orm module
Closes gh-34159
2024-12-26 16:21:17 +01:00
Sébastien Deleuze abccba22f1 Refine null-safety in the spring-messaging module
Closes gh-34158
2024-12-26 16:00:24 +01:00
Sébastien Deleuze 4fa33dfece Refine null-safety in the spring-aop module
See gh-34154
2024-12-26 15:30:59 +01:00
Sébastien Deleuze 9516d9b822 Refine null-safety in the spring-jms module
Closes gh-34157
2024-12-26 15:18:27 +01:00
Sébastien Deleuze be11e73d2c Refine null-safety in the spring-expression module
Closes gh-34156
2024-12-26 14:59:50 +01:00
Sébastien Deleuze 4747ab67e6 Refine null-safety in the spring-core module
See gh-34150
2024-12-26 14:56:34 +01:00
Sébastien Deleuze c245e20e3f Refine null-safety in the spring-beans module
See gh-34152
2024-12-26 14:18:48 +01:00
Sébastien Deleuze 185537d469 Refine jsr305 dependency management
See gh-28797
2024-12-26 14:13:17 +01:00
Sébastien Deleuze 92f1f55957 Refine null-safety in the spring-aop module
Closes gh-34154
2024-12-26 13:53:25 +01:00
Sébastien Deleuze b4a2cdf028 Merge branch '6.2.x' 2024-12-26 13:18:16 +01:00
Sébastien Deleuze 8b741f3a46 Refine null-safety in the spring-beans module
Closes gh-34152
2024-12-26 11:24:05 +01:00
Sébastien Deleuze 1c37e7092e Use @SuppressWarnings("NullAway.Init")`
This commit uses `@SuppressWarnings("NullAway.Init")` when
relevant.

See gh-34147
See gh-34151
2024-12-26 10:47:10 +01:00
Simon Baslé f24f9a4ba4 Polishing
Javadoc links to `HttpHeaders#remove` now use the new String-based
signature.

See gh-33913
2024-12-26 10:30:46 +01:00
Stéphane Nicoll cf49a33ea4 Merge branch '6.2.x' 2024-12-25 09:30:08 +01:00
Sébastien Deleuze f368147f9d Refine null-safety in the spring-context module
Closes gh-34151
2024-12-24 18:27:13 +01:00
Sébastien Deleuze cf90beec0a Refine null-safety in the spring-core module
Closes gh-34150
2024-12-24 16:46:00 +01:00
Sébastien Deleuze fbc759077c Refine null-safety in the spring-jdbc module
Closes gh-34147
2024-12-24 16:17:24 +01:00
Simon Baslé 0c6f5d7d29 HttpHeaders are no longer a MultiValueMap
This change removes the `MultiValueMap` nature of `HttpHeaders`, since
it inherits APIs that do not align well with underlying server
implementations. Notably, methods that allows to iterate over the whole
collection of headers are susceptible to artificially introduced
duplicates when multiple casings are used for a given header, depending
on the underlying implementation.

This change includes a dedicated key set implementation to support
iterator-based removal, and either keeps map method implementations that
are relevant or introduces header-focused methods that have a similar
responsibility (like `hasHeaderValues(String, List)` and
`containsHeaderValue(String, String)`).

In order to nudge users away from using an HttpHeaders as a Map, the
`asSingleValueMap` view is deprecated. In order to offer an escape
hatch to users that do make use of the `MultiValueMap` API, a similar
`asMultiValueMap` view is introduced but is immediately marked as
deprecated.

This change also adds map-like but header-focused assertions to
`HttpHeadersAssert`, since it cannot extend `AbstractMapAssert` anymore.

Closes gh-33913
2024-12-24 14:43:51 +01:00
Sébastien Deleuze 1e0ef99b0c Leverage @NullMarked instead of package configuration
This commit replaces NullAway package configuration by package-level
`@NullMarked` detection by configuring `NullAway:AnnotatedPackages` to
an empty string.

NullAway configuration should be refined to use a proper flag instead
once uber/NullAway#574 is fixed.

See gh-28797
2024-12-23 17:14:29 +01:00
Sébastien Deleuze 528578d138 Merge branch '6.2.x' 2024-12-23 15:34:57 +01:00
Stéphane Nicoll 950d0b5164 Merge branch '6.2.x' 2024-12-23 12:31:31 +01:00
Sébastien Deleuze bccd9e9f11 Merge branch '6.2.x' 2024-12-23 11:15:08 +01:00
Sam Brannen bf06d74879 Merge branch '6.2.x' 2024-12-21 16:03:43 +01:00
Sam Brannen 5b8e436c98 Merge branch '6.2.x' 2024-12-21 15:31:29 +01:00
rstoyanchev 373763723e Deprecate use of PathMatcher and UrlPathHelper in web
Closes gh-34018
2024-12-19 15:59:41 +00:00
rstoyanchev 41a9db376d Deprecate pathExtension routing predicates
Closes gh-34103
2024-12-19 15:59:18 +00:00
Sam Brannen 62d9600cdd Clean up warnings in Gradle build 2024-12-19 14:48:33 +01:00
Sébastien Deleuze ef06bf4e74 Refine null-safety migration documentation
See gh-28797
2024-12-19 11:38:26 +01:00
Sébastien Deleuze 6d2d10cffe Update null-safety documentation
This commit documents using JSpecify instead of the now deprecated
Spring null-safety annotations.

Closes gh-28797
2024-12-19 11:07:33 +01:00
Sébastien Deleuze b3586560c1 Add support for AnnotatedType in MethodParameter.hasNullableAnnotation
This commit adds support for detecting annotated types.

See gh-28797
2024-12-19 11:07:33 +01:00
Sébastien Deleuze 61545fabfc Deprecate Spring nullability annotations
JSpecify annotations should be used instead.

See gh-28797
2024-12-19 11:07:33 +01:00
Sébastien Deleuze 0e85d950b3 Remove unneeded @NonNull annotations
See gh-28797
2024-12-19 11:07:33 +01:00
Sébastien Deleuze bc5d771a06 Switch to JSpecify annotations
This commit updates the whole Spring Framework codebase to use JSpecify
annotations instead of Spring null-safety annotations with JSR 305
semantics.

JSpecify provides signficant enhancements such as properly defined
specifications, a canonical dependency with no split-package issue,
better tooling, better Kotlin integration and the capability to specify
generic type, array and varargs element null-safety. Generic type
null-safety is not defined by this commit yet and will be specified
later.

A key difference is that Spring null-safety annotations, following
JSR 305 semantics, apply to fields, parameters and return values,
while JSpecify annotations apply to type usages. That's why this
commit moves nullability annotations closer to the type for fields
and return values.

See gh-28797
2024-12-19 11:07:23 +01:00
Sam Brannen fcb8aed03f Merge branch '6.2.x' 2024-12-18 18:04:19 +01:00
rstoyanchev 4b9f1732f1 Remove remaining Spring MVC trailing slash matching
Closes gh-34036
2024-12-17 11:14:00 +00:00
rstoyanchev 2e6046a655 Remove trailing slash matching in PathPatternParser
See gh-34036
2024-12-17 11:14:00 +00:00
rstoyanchev 32db1a1680 Remove WebFlux trailing slash match
See gh-34036
2024-12-17 11:14:00 +00:00
Brian Clozel 4fd368b1af Deprecate mvc XML configuration namespace
This commit deprecates the `<mvc:*` XML configuration namespace for
configuring Spring MVC applications. This configuration model is lagging
behind in the 6.x generation already and we don't intend to invest in
this space to close that gap.

As of 7.0, using this XML namespace will result in a WARN log message.
This commit also states our intent in the reference documentation.

Closes gh-34063
2024-12-17 11:55:08 +01:00
Sébastien Deleuze f094c46172 Merge branch '6.2.x' 2024-12-17 11:40:53 +01:00
rstoyanchev 7f4da52cc5 Remove Spring MVC path extension content negotiation
See gh-34036
2024-12-17 09:49:07 +00:00
rstoyanchev e9946937e7 Remove Spring MVC suffixPattern and trailingSlash matching
See gh-34036
2024-12-17 09:49:04 +00:00
Brian Clozel ca909483f1 Merge branch '6.2.x' 2024-12-17 10:20:19 +01:00
Sam Brannen c75887c20d Merge branch '6.2.x' 2024-12-16 15:01:21 +01:00
Sam Brannen dd094b5a17 Complete removal of local variable support in SpEL
See gh-33809
2024-12-15 15:55:38 +01:00
Sam Brannen af83a152dc Polishing 2024-12-15 15:55:03 +01:00
Sam Brannen aa7793a593 Removed unused code from ContentDisposition
See gh-33809
2024-12-15 15:54:23 +01:00
Sam Brannen bf80485cc3 Clean up after deprecation of AsyncResult
See gh-33809
2024-12-15 15:53:33 +01:00
Sam Brannen 8a8df90a46 Restore TomcatHeadersAdapter.clear() behavior
This commit restores the original behavior of the clear() method in
TomcatHeadersAdapter by delegating to
org.apache.tomcat.util.http.MimeHeaders.recycle(), which aligns with
the memory efficiency goals documented in the class-level Javadoc for
MimeHeaders.

See gh-33916
Closes gh-34092
2024-12-15 15:34:49 +01:00
Johnny Lim c8009dc67d Fix TomcatHeadersAdapter.clear()
This commit fixes a regression introduced in TomcatHeadersAdapter in
conjunction with gh-33916.

Closes gh-34092
2024-12-15 15:24:37 +01:00
Juergen Hoeller 5cbb5d4d70 Upgrade to Hibernate ORM 7.0.0.Beta3 and Validator 9.0.0.CR1
Using relocated Maven coordinates.

See gh-33750
2024-12-15 14:37:54 +01:00
Sam Brannen 30d249c3a7 Merge branch '6.2.x' 2024-12-14 17:14:47 +01:00
Sam Brannen 34f74026f7 Merge branch '6.2.x' 2024-12-14 16:41:25 +01:00
Sébastien Deleuze 65553f55d7 Fix a Kotlin compilation warning 2024-12-13 15:25:06 +01:00
Juergen Hoeller 43ff6d9711 Deprecate use of several bean factory methods for the same bean
See gh-31073
2024-12-12 22:16:24 +01:00
Juergen Hoeller 4773ffc72c Merge branch '6.2.x' 2024-12-12 19:56:04 +01:00
Juergen Hoeller 2dbad8de41 Avoid unnecessary logger serialization
See gh-32459
2024-12-12 19:34:55 +01:00
Juergen Hoeller 5e549da75f Use Log4j 3.0.0 beta 3 for testing
See gh-32459
2024-12-12 19:15:27 +01:00
Juergen Hoeller 3db1b94465 Replace spring-jcl with regular Apache Commons Logging 1.3
Closes gh-32459
2024-12-12 17:37:11 +01:00
Stéphane Nicoll c5eefaa5f3 Merge branch '6.2.x' 2024-12-12 17:35:59 +01:00
Stéphane Nicoll 7a6ba43402 Merge branch '6.2.x' 2024-12-12 17:32:50 +01:00
Sam Brannen 01a15cf0e7 Merge branch '6.2.x' 2024-12-12 14:41:51 +01:00
Brian Clozel 0ebbe024f2 Merge branch '6.2.x' 2024-12-12 10:54:05 +01:00
Juergen Hoeller 429833cae6 Merge branch '6.2.x'
# Conflicts:
#	spring-web/src/main/java/org/springframework/http/client/SimpleClientHttpRequestFactory.java
2024-12-11 17:55:36 +01:00
rstoyanchev 2d5943352f Merge branch '6.2.x' 2024-12-11 16:22:47 +00:00
Juergen Hoeller 9fe69e2cc4 Merge branch '6.2.x' 2024-12-11 16:59:31 +01:00
Juergen Hoeller cb633832a9 Remove unused HibernateCallback interface
See gh-33750
2024-12-11 16:48:12 +01:00
Brian Clozel 88a5b4efd3 Merge branch '6.2.x' 2024-12-11 16:12:01 +01:00
Sam Brannen 1ef7e70950 Merge branch '6.2.x' 2024-12-11 15:04:43 +01:00
rstoyanchev d45e6ec197 Support Flux<ServerSentEvent<Fragment>> in WebFlux
Closes gh-33975
2024-12-11 12:22:56 +00:00
rstoyanchev c4b100ac0c Minor refactoring in ServerSentEvent
Extract re-usable method to serialize SSE fields.

See gh-33975
2024-12-11 12:22:56 +00:00
rstoyanchev fd8823819f MapMethodProcessor supportsParameter is more specific
Closes gh-33160
2024-12-11 12:22:56 +00:00
Sam Brannen 3256bf436a Merge branch '6.2.x' 2024-12-11 12:12:57 +01:00
Brian Clozel 11db31a8ee Merge branch '6.2.x' 2024-12-10 22:36:01 +01:00
Juergen Hoeller 41f8ac6b59 Merge branch '6.2.x' 2024-12-10 22:16:46 +01:00
Juergen Hoeller 3d19d78461 Merge branch '6.2.x' 2024-12-10 16:26:56 +01:00
Stéphane Nicoll 1c435c0f47 Merge branch '6.2.x' 2024-12-10 14:09:18 +01:00
Sam Brannen 2d4baec2b1 Merge branch '6.2.x' 2024-12-10 12:52:32 +01:00
Sébastien Deleuze 83517d05d0 Merge branch '6.2.x' 2024-12-10 11:51:19 +01:00
Stéphane Nicoll 2546f63824 Merge branch '6.2.x' 2024-12-10 07:48:01 +01:00
Sam Brannen cd25a64ac0 Merge branch '6.2.x' 2024-12-09 16:01:07 +01:00
Brian Clozel 78f28fda54 Merge branch '6.2.x' 2024-12-09 11:18:28 +01:00
Brian Clozel 810da11bb5 Remove deprecated web APIs
This commit also marks for removal APIs that were deprecated a long time
ago but were not marked for removal.

See gh-33809
2024-12-08 22:50:54 +01:00
Brian Clozel 5044b70a40 Remove deprecated MediaType entries
See gh-33809
2024-12-08 21:01:11 +01:00
Brian Clozel ff28d2d47a Polishing MediaType Javadoc
Closes gh-34047
2024-12-08 20:44:57 +01:00
Brian Clozel 3edb256298 Update websocket reference docs
See gh-33744
2024-12-08 20:12:57 +01:00
Sam Brannen 2015a93823 Merge branch '6.2.x' 2024-12-08 18:41:37 +01:00
Stéphane Nicoll b904753a25 Merge branch '6.2.x' 2024-12-08 10:53:16 +01:00
Sam Brannen 0e50fe4f6a Merge branch '6.2.x' 2024-12-07 16:56:23 +01:00
Stéphane Nicoll f8fd6da10b Merge branch '6.2.x' 2024-12-06 15:42:15 +01:00
Stéphane Nicoll 6d28ac6b2c Merge branch '6.2.x' 2024-12-06 09:44:05 +01:00
Juergen Hoeller 5e62ae19a9 Merge branch '6.2.x' 2024-12-05 17:42:45 +01:00
Stéphane Nicoll b8cdef6d29 Merge branch '6.2.x' 2024-12-05 17:01:50 +01:00
Sébastien Deleuze c2822a6b23 Add .kotlin directory to .gitignore
See gh-33629
2024-12-05 16:02:23 +01:00
Stéphane Nicoll 086d7081f8 Merge branch '6.2.x' 2024-12-05 15:57:57 +01:00
Sébastien Deleuze db196321a6 Merge branch '6.2.x' 2024-12-05 15:44:43 +01:00
Sébastien Deleuze 75e57475ca Upgrade to Kotlin 2.1.0
Spring Framework 7.0 will use a Kotlin 2 baseline, using the latest 2.x
release at the time of the release.

This commit upgrades Kotlin to 2.1.0, and Kotlin Serialization and
Coroutines accordingly.

Closes gh-33629
2024-12-05 11:42:00 +01:00
Sébastien Deleuze 58020ff0eb Stop using Java code snippets in Kotlin ones
As a preparation to using a Kotlin 2 baseline, this commit stops using
Java code snippets in Kotlin ones in order to avoid redeclaration
errors.

See gh-33629
2024-12-05 11:41:48 +01:00
Sébastien Deleuze edce3029a2 Remove tests for Kotlin Script Templates
Closes gh-34030
2024-12-05 11:19:42 +01:00
Sébastien Deleuze 3eb5b8263b Remove documentation for Kotlin Script Templates
Closes gh-34029
2024-12-05 11:19:42 +01:00
Juergen Hoeller 5e939ccb4b Merge branch '6.2.x' 2024-12-04 21:10:30 +01:00
Juergen Hoeller da75840712 Drop server-specific TomcatRequestUpgradeStrategy for WebFlux
StandardWebSocketUpgradeStrategy is the common replacement on Tomcat.

See gh-33744
2024-12-04 16:50:16 +01:00
Juergen Hoeller 162e533393 Merge branch '6.2.x'
# Conflicts:
#	spring-context/src/test/java/org/springframework/scheduling/concurrent/AbstractSchedulingTaskExecutorTests.java
#	spring-web/src/main/java/org/springframework/http/MediaType.java
#	spring-websocket/spring-websocket.gradle
#	spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java
#	spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/DefaultTransportRequest.java
2024-12-04 16:45:54 +01:00
Juergen Hoeller 2b9010c2a2 Remove APIs marked as deprecated for removal
Closes gh-33809
2024-12-04 13:19:39 +01:00
Sam Brannen 078d683f47 Merge branch '6.2.x' 2024-12-04 12:04:37 +01:00
Juergen Hoeller 3f3341bb1d Drop server-specific RequestUpgradeStrategy implementations
StandardWebSocketUpgradeStrategy is the common replacement on Tomcat, Undertow and all EE servers. JettyRequestUpgradeStrategy remains the preferred choice on Jetty.

Closes gh-33744
2024-12-03 19:08:22 +01:00
Brian Clozel 342369355d Polishing 2024-12-03 15:59:12 +01:00
Brian Clozel 5de03f6bb1 Merge branch '6.2.x' 2024-12-03 15:39:16 +01:00
Sam Brannen d41d674c4f Update code due to upgrade to Jakarta EE 11 APIs 2024-12-03 15:10:32 +01:00
Sam Brannen 5ac0b8e22e Remove obsolete code 2024-12-03 15:08:57 +01:00
Juergen Hoeller 949432ce8b General upgrade to Jakarta EE 11 APIs
Includes removal of ManagedBean and javax.annotation legacy support.
Includes AbstractJson(Http)MessageConverter revision for Yasson 3.0.
Includes initial Hibernate ORM 7.0 upgrade.

Closes gh-34011
Closes gh-33750
2024-12-03 13:30:25 +01:00
rstoyanchev 15c6d3449b Merge branch '6.2.x' 2024-12-02 17:52:56 +00:00
Sam Brannen f243abbce3 Merge branch '6.2.x' 2024-12-01 16:39:10 +01:00
Brian Clozel ba312f6c7c Update AOT support after RuntimeHints changes
This commit adapts AOT support in various modules after the RuntimeHints
and related deprecation changes.

`MemberCategory.INTROSPECT_*` hints are now removed and
`MemberCategory.*_FIELDS` are  replaced with
`MemberCategory.INVOKE*_FIELDS` when invocation is needed.

Usage of `RuntimeHintsAgent` are also deprecated.

Closes gh-33847
2024-11-29 14:44:05 +01:00
Brian Clozel 0759129c14 Deprecate RuntimeHintsAgent Java agent
This Java agent has been designed to instrument specific JDK calls for
reflective introspection and invocations. This is useful for testing
runtime hints in integration tests.

As of GraalVM 23, there is a new VM option that does this in a much more
efficient and precise fashion. Developers can use the
`-XX:MissingRegistrationReportingMode` with the "Warn" or "Exit" value.
The option will look for reachability metadata and emit logs in "Warn"
mode or immediately exit the application with in "Exit" mode.

This commit deprecates the `RuntimeHintsAgent` in favor of this new,
more reliable option.

See gh-33847
2024-11-29 14:44:02 +01:00
Brian Clozel 71362c953c Revisit RuntimeHints API
The `RuntimeHints` API mainly reflects what is needed to write GraalVM
reachability metadata. The latest GraalVM version simplified its
format. This commit applies relevant simplifications as parts of it are
not needed anymore.

The new metadata format implies methods, constructors and fields
introspection as soon as a reflection hint is registered for a type. As
a result, `ExecutableMode.INTROSPECT`, and all `MemberCategory` values
except `MemberCategory.INVOKE_*` are being deprecated.
They have no replacement, as registering a type hint is enough.
In practice, it is enough to replace this:

```
hints.reflection().registerType(MyType.class, MemberCategory.DECLARED_FIELDS);
```

By this:
```
hints.reflection().registerType(MyType.class);
```

As for `MemberCategory.PUBLIC_FIELDS` and `MemberCategory.DECLARED_FIELDS`,
values were replaced by `INVOKE_PUBLIC_FIELDS` and
`INVOKE_DECLARED_FIELDS` to make their original intent clearer and align
with the rest of the API. Note, if you were using those values for
reflection only, you can safely remove those hints in favor of a simple
type hint.

See gh-33847
2024-11-29 14:43:59 +01:00
Brian Clozel fec2ed5540 Implement new GraalVM reachability metadata format
As of GraalVM 23, a new and simplified reachability metadata format is
available. Metadata now consists of a single
"reachability-metadata.json" file that contains all the information
previously spread in multiple files. The new format does not include
some introspection flags, as they're now automatically included when a
hint is registered against a type.
Also, "typeReachable" has been renamed as "typeReached" to highlight the
fact that the event considered is the static initialization of the type,
not when the static analysis performed during native compilation is
reaching the type.

This new format ships with a JSON schema, which this commit is tested
against.

See gh-33847
2024-11-29 14:43:55 +01:00
Brian Clozel 989eb37fb7 Update AOT resource hints with new GraalVM behavior
Prior to this commit, the resource hints for AOT applications would
generate JSON metadata with `java.util.regex.Pattern`, like:

```
{
  "resources": {
    "includes": [
      {
        "pattern": "\\Qbanner.txt\\E"
      }
    ]
  }
}
```

This regexp feature, as well as "includes" and "excludes" are not supported
anymore with the new metadata format. This commit removes the pattern
format which is now replaced by a "glob" format.
"globs" should only contain "*" (zero or more characters in a path
segment)  or "**" (zero or more path segments).
Some instances of resource hint registration should be migrated as a
result.
For example, "/files/*.ext" matched both "/files/a.ext" and
"/files/folder/b.txt" in the past. The new behavior matches only the
former, unless the "/files/**/*.ext" glob pattern is used.

This commit also removes the "excludes" support, which was not widely
used and very often could lead to subtle behavior.

Closes gh-31340
2024-11-29 14:43:52 +01:00
Sam Brannen bd81abe58d Merge branch '6.2.x' 2024-11-29 11:32:53 +01:00
rstoyanchev fa01e9c566 Use response decorator to check if error handled
Closes gh-33980
2024-11-29 10:30:29 +00:00
Brian Clozel 431d726dc6 Use Jakarta 11 javadoc link
See gh-33918
2024-11-29 09:44:27 +01:00
rstoyanchev 89b2a6500e DefaultResponseErrorHandler updates
Deprecate handleError(response), and ensure it continues to be invoked
if overridden.

Closes gh-33980
2024-11-28 17:57:32 +00:00
rstoyanchev a0cc6419f4 Polishing in DefaultResponseErrorHandler
See gh-33980
2024-11-28 17:18:48 +00:00
Brian Clozel 5fa9460bf6 Temporarily revert changes for gh-33616
See gh-33616
2024-11-28 18:07:23 +01:00
Brian Clozel 5d492689b7 Create MetadataReaderFactory instances with factory methods
Prior to this commit, Spring would create directly
`SimpleMetadataReaderFactory` instances or would manually create
`CachingMetadataReaderFactory` which extend
`SimpleMetadataReaderFactory`. This would prevent usage of the new
`ClassFileMetadataReaderFactory` in our internal codebase.

This commit replaces manual instantiations with calls to
`MetadataReaderFactory` factory methods and makes
`CachingMetadataReaderFactory` delegate to another factory created with
the same factory methods.

This allows internal usage of `ClassFileMetadataReaderFactory`
internally.

Closes gh-33616
2024-11-28 16:30:16 +01:00
Brian Clozel 4f260a4511 Add ClassFile implementation for class metadata
Prior to this commit, Spring Framework would allow two ways of getting
class metadata:
* `StandardClassMetadata`, using the Java reflection API
* `SimpleMetadataReaderFactory`, using ASM to read the class bytecode

This commit adds a new implementation for this feature, this time using
the new `ClassFile` API which is taken out of preview in Java 24.

See gh-33616
2024-11-28 16:29:50 +01:00
Brian Clozel 28273b9309 Add build DSL extension to enable Java preview features
This commit adds a DSL Gradle extension for optionally enabling Java
preview features in a specific project module. The "--enable-preview"
JVM flag will be configured automatically for compile and test tasks
where this is applied:

```
springFramework {
	enableJavaPreviewFeatures = true
}
```

See gh-33616
2024-11-28 16:29:47 +01:00
Brian Clozel c213724a47 Document Servlet PushBuilder API deprecation
See gh-33918
2024-11-28 15:55:53 +01:00
Sébastien Deleuze b6e6b015e8 Merge branch '6.2.x' 2024-11-28 15:17:06 +01:00
Sébastien Deleuze ab33d715a2 Merge branch '6.2.x' 2024-11-27 16:40:05 +01:00
Sam Brannen 80f63d89d1 Merge branch '6.2.x' 2024-11-27 12:55:57 +01:00
rstoyanchev 81ea35c726 Update method names in FragmentsRendering
Closes gh-33974
2024-11-27 11:21:51 +00:00
Stéphane Nicoll 186f909c96 Merge branch '6.2.x' 2024-11-26 20:04:56 +01:00
rstoyanchev 1fd0b8730b Improve Javadoc of FragmentsRendering 2024-11-26 18:27:16 +00:00
rstoyanchev 1164ac3079 ContentCachingRequestWrapper requires cacheLimit
Closes gh-33914
2024-11-26 18:27:16 +00:00
Sébastien Deleuze b027cf110d Merge branch '6.2.x' 2024-11-26 16:10:03 +01:00
Sam Brannen 98676746f3 Merge branch '6.2.x' 2024-11-26 11:58:44 +01:00
Sam Brannen 64f93d5755 Merge branch '6.2.x' 2024-11-24 14:28:25 +01:00
Sam Brannen 102cc72fd3 Merge branch '6.2.x' 2024-11-24 14:15:13 +01:00
Brian Clozel 5e08a88219 Upgrade Servlet mock classes to Servlet 6.1
This commit upgrades our Mock Servlet classes for Servlet 6.1 support:

* the read/write `ByteBuffer` variants for `ServletInputStream` and
  `ServletOutputStream` were not added as the default implementation
  matches well the testing use case.
* Implement the session accessor with a simple lambda. Our mocks do not
  simulate the scheduling of request/response processing on different
  threads.
* Ensure that the response content length can only be written before the
  response is committed. Calling those methods after commit is a no-op,
  per specification.

Closes gh-33749
2024-11-22 17:07:44 +01:00
Brian Clozel 3b65506c13 Use ByteBuffer support in ServletHttpHandlerAdapter
As of Servlet 6.1, the `ServletInputStream` and `ServletOutputStream`
offer read and write variants based on `ByteBuffer` instead of byte
arrays. This can improve performance and avoid memory copy for I/O
calls.

This was already partially supported for some servers like Tomcat
through specific adapters. This commit moves this support to the
standard `ServletHttpHandlerAdapter` and makes it available for all
Servlet 6.1+ containers.

Closes gh-33748
2024-11-22 15:08:02 +01:00
Brian Clozel f5ff84ab7b Merge branch '6.2.x' 2024-11-21 14:35:52 +01:00
Brian Clozel 50061dae35 Merge branch '6.2.x' 2024-11-21 14:25:41 +01:00
Sam Brannen 74c48d8132 Merge branch '6.2.x' 2024-11-21 11:34:55 +01:00
Sam Brannen ff5529bbae Merge branch '6.2.x' 2024-11-21 09:53:46 +01:00
Sam Brannen 082a8cfae3 Merge branch '6.2.x' 2024-11-20 16:51:30 +01:00
Sam Brannen ba4105d4f0 Merge branch '6.2.x' 2024-11-20 11:30:48 +01:00
Brian Clozel f548da8a8d Temporarily ignore webflux tomcat integration tests
After our Tomcat 11 upgrade, several WebFlux integration tests with
Tomcat started failing because Tomcat considers some chunked client
requests as invalid.

While we're investigating this, this commit temporarily disables the
relevant tests.

See gh-33917
2024-11-19 18:11:24 +01:00
Brian Clozel 4b3e192ca1 Upgrade to Tomcat 11.0
This commit upgrades the baseline to Tomcat 11.0 and adapts to the
following behavior changes in Tomcat:

* the MimeHeaders#clear method has been removed
* expired cookies do not set "Max-Age=0" anymore
* responses to HEAD requests do not write the "Content-Length" header
  anymore.

Closes gh-33916
2024-11-19 18:11:24 +01:00
Brian Clozel c28cbfd582 Upgrade Servlet, JSP and WebSocket API versions
This commit updates the Spring Framework baseline for the Servlet, JSP
and WebSocket APIs.
This also removes the previously deprecated APIs in JSP `PageContext`
and guards against the deprecation of the `PushBuilder` API.

See gh-33918
2024-11-19 18:11:18 +01:00
Simon Baslé 1fb1801285 Merge branch '6.2.x' 2024-11-19 16:59:42 +01:00
Sam Brannen a7547cd311 Merge branch '6.2.x' 2024-11-19 13:33:53 +01:00
Sam Brannen e69ae513b9 Merge branch '6.2.x' 2024-11-19 13:22:08 +01:00
Simon Baslé 8d3d0e7ae5 Merge branch '6.2.x' 2024-11-18 16:37:21 +01:00
Sam Brannen 8d4a8cbbe5 Merge branch '6.2.x' 2024-11-18 14:16:20 +01:00
Brian Clozel 409bf5f889 Merge branch '6.2.x' 2024-11-18 11:57:43 +01:00
Sam Brannen 00831a06ea Merge branch '6.2.x' 2024-11-18 11:55:12 +01:00
Stéphane Nicoll e81fe79e2b Merge branch '6.2.x' 2024-11-18 11:52:42 +01:00
Sam Brannen e34189a793 Merge branch '6.2.x' 2024-11-18 11:41:07 +01:00
Sam Brannen cea5d9e3d1 Merge branch '6.2.x' 2024-11-17 15:16:16 +01:00
Sam Brannen def2d033a2 Merge branch '6.2.x' 2024-11-17 12:24:26 +01:00
Sam Brannen 7f8102a4cd Merge branch '6.2.x' 2024-11-17 11:46:50 +01:00
Sam Brannen e57464dac8 Merge branch '6.2.x' 2024-11-15 16:06:43 +01:00
Brian Clozel 2528fbe3b2 Merge branch '6.2.x' 2024-11-15 15:37:12 +01:00
Brian Clozel 600399cc96 Merge branch '6.2.x' 2024-11-15 15:35:53 +01:00
Sam Brannen c0d16eafb3 Merge branch '6.2.x' 2024-11-15 14:32:26 +01:00
Brian Clozel a4cea65ace Update GitHub workflows for 7.0 generation 2024-11-14 17:54:15 +01:00
Brian Clozel 6e17a05419 Merge branch '6.2.x' 2024-11-14 17:51:19 +01:00
Brian Clozel 2522a73111 Next development version (v7.0.0-SNAPSHOT) 2024-11-14 17:50:41 +01:00
6231 changed files with 143671 additions and 90286 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ inputs:
java-version:
description: 'Java version to compile and test with'
required: false
default: '17'
default: '25'
publish:
description: 'Whether to publish artifacts ready for deployment to Artifactory'
required: false
@@ -1,6 +1,13 @@
changelog:
repository: spring-projects/spring-framework
sections:
- title: ":warning: Attention Required"
labels:
- "for: upgrade-attention"
summary:
mode: "member-comment"
config:
prefix: "Attention Required:"
- title: ":star: New Features"
labels:
- "type: enhancement"
@@ -19,19 +19,20 @@ inputs:
java-version:
description: 'Java version to use for the build'
required: false
default: '17'
default: '25'
runs:
using: composite
steps:
- name: Set Up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: ${{ inputs.java-early-access == 'true' && 'temurin' || (inputs.java-distribution || 'liberica') }}
java-version: |
${{ inputs.java-early-access == 'true' && format('{0}-ea', inputs.java-version) || inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '17' || '' }}
25
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
cache-read-only: false
develocity-access-key: ${{ inputs.develocity-access-key }}
@@ -17,14 +17,14 @@ runs:
using: composite
steps:
- name: Set Up JFrog CLI
uses: jfrog/setup-jfrog-cli@f748a0599171a192a2668afee8d0497f7c1069df # v4.5.6
uses: jfrog/setup-jfrog-cli@5b06f730cc5a6f55d78b30753f8583454b08c0aa # v4.8.1
env:
JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }}
- name: Download Release Artifacts
shell: bash
run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-framework-{0}', inputs.spring-framework-version) }};buildNumber=${{ github.run_number }}'
- name: Sync
uses: spring-io/central-publish-action@0cdd90d12e6876341e82860d951e1bcddc1e51b6 # v0.2.0
uses: spring-io/central-publish-action@0c03960e9b16fdfe70e2443e1d5393cbc3a35622 # v0.3.0
with:
token: ${{ inputs.central-token-password }}
token-name: ${{ inputs.central-token-username }}
+3
View File
@@ -0,0 +1,3 @@
require:
members: false
+2 -2
View File
@@ -18,9 +18,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'liberica'
java-version: 17
@@ -2,7 +2,7 @@ name: Build and Deploy Snapshot
on:
push:
branches:
- 6.2.x
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -13,7 +13,7 @@ jobs:
timeout-minutes: 60
steps:
- name: Check Out Code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build and Publish
id: build-and-publish
uses: ./.github/actions/build
@@ -21,13 +21,13 @@ jobs:
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
publish: true
- name: Deploy
uses: spring-io/artifactory-deploy-action@dc1913008c0599f0c4b1fdafb6ff3c502b3565ea # v0.0.2
uses: spring-io/artifactory-deploy-action@926d7f7cc810569395346bf3a4d91b380b3e355b # v0.0.4
with:
artifact-properties: |
/**/framework-api-*.zip::zip.name=spring-framework,zip.deployed=false
/**/framework-api-*-docs.zip::zip.type=docs
/**/framework-api-*-schema.zip::zip.type=schema
build-name: 'spring-framework-6.2.x'
build-name: 'spring-framework-7.1.x'
folder: 'deployment-repository'
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository: 'libs-snapshot-local'
+2 -2
View File
@@ -10,7 +10,7 @@ jobs:
timeout-minutes: 60
steps:
- name: Check Out Code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build
id: build
uses: ./.github/actions/build
@@ -19,7 +19,7 @@ jobs:
uses: ./.github/actions/print-jvm-thread-dumps
- name: Upload Build Reports
if: failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: build-reports
path: '**/build/reports/'
+3 -4
View File
@@ -1,8 +1,7 @@
name: CI
on:
push:
branches:
- 6.2.x
schedule:
- cron: '30 9 * * *'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -36,7 +35,7 @@ jobs:
git config --global core.longPaths true
Stop-Service -name Docker
- name: Check Out Code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build
id: build
uses: ./.github/actions/build
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
ref: docs-build
+95
View File
@@ -0,0 +1,95 @@
name: Release Milestone
on:
push:
tags:
- v7.1.0-M[1-9]
- v7.1.0-RC[1-9]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
build-and-stage-release:
name: Build and Stage Release
if: ${{ github.repository == 'spring-projects/spring-framework' }}
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v6
- name: Build and Publish
id: build-and-publish
uses: ./.github/actions/build
with:
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
publish: true
- name: Stage Release
uses: spring-io/artifactory-deploy-action@926d7f7cc810569395346bf3a4d91b380b3e355b # v0.0.4
with:
artifact-properties: |
/**/framework-api-*.zip::zip.name=spring-framework,zip.deployed=false
/**/framework-api-*-docs.zip::zip.type=docs
/**/framework-api-*-schema.zip::zip.type=schema
build-name: ${{ format('spring-framework-{0}', steps.build-and-publish.outputs.version)}}
folder: 'deployment-repository'
password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository: 'libs-staging-local'
signing-key: ${{ secrets.GPG_PRIVATE_KEY }}
signing-passphrase: ${{ secrets.GPG_PASSPHRASE }}
uri: 'https://repo.spring.io'
username: ${{ secrets.ARTIFACTORY_USERNAME }}
outputs:
version: ${{ steps.build-and-publish.outputs.version }}
verify:
name: Verify
needs: build-and-stage-release
uses: ./.github/workflows/verify.yml
secrets:
google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }}
repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }}
repository-username: ${{ secrets.ARTIFACTORY_USERNAME }}
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
with:
staging: true
version: ${{ needs.build-and-stage-release.outputs.version }}
sync-to-maven-central:
name: Sync to Maven Central
needs:
- build-and-stage-release
- verify
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v6
- name: Sync to Maven Central
uses: ./.github/actions/sync-to-maven-central
with:
central-token-password: ${{ secrets.CENTRAL_TOKEN_PASSWORD }}
central-token-username: ${{ secrets.CENTRAL_TOKEN_USERNAME }}
jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }}
spring-framework-version: ${{ needs.build-and-stage-release.outputs.version }}
promote-release:
name: Promote Release
needs:
- build-and-stage-release
- sync-to-maven-central
runs-on: ubuntu-latest
steps:
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@5b06f730cc5a6f55d78b30753f8583454b08c0aa # v4.8.1
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote build
run: jfrog rt build-promote ${{ format('spring-framework-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-milestone-local
create-github-release:
name: Create GitHub Release
needs:
- build-and-stage-release
- promote-release
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v6
- name: Create GitHub Release
uses: ./.github/actions/create-github-release
with:
milestone: ${{ needs.build-and-stage-release.outputs.version }}
pre-release: true
token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
+6 -6
View File
@@ -2,7 +2,7 @@ name: Release
on:
push:
tags:
- v6.2.[0-9]+
- v7.1.[0-9]+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Build and Publish
id: build-and-publish
uses: ./.github/actions/build
@@ -20,7 +20,7 @@ jobs:
develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
publish: true
- name: Stage Release
uses: spring-io/artifactory-deploy-action@dc1913008c0599f0c4b1fdafb6ff3c502b3565ea # v0.0.2
uses: spring-io/artifactory-deploy-action@926d7f7cc810569395346bf3a4d91b380b3e355b # v0.0.4
with:
artifact-properties: |
/**/framework-api-*.zip::zip.name=spring-framework,zip.deployed=false
@@ -56,7 +56,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
uses: actions/checkout@v6
- name: Sync to Maven Central
uses: ./.github/actions/sync-to-maven-central
with:
@@ -72,7 +72,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up JFrog CLI
uses: jfrog/setup-jfrog-cli@dff217c085c17666e8849ebdbf29c8fe5e3995e6 # v4.5.2
uses: jfrog/setup-jfrog-cli@5b06f730cc5a6f55d78b30753f8583454b08c0aa # v4.8.1
env:
JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }}
- name: Promote build
@@ -85,7 +85,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check Out Code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
uses: actions/checkout@v6
- name: Create GitHub Release
uses: ./.github/actions/create-github-release
with:
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
branch: [ '6.1.x' ]
branch: [ '6.2.x', '7.0.x', 'main' ]
steps:
- uses: spring-io/spring-doc-actions/update-antora-spring-ui@5a57bcc6a0da2a1474136cf29571b277850432bc
name: Update
+5 -5
View File
@@ -30,23 +30,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check Out Release Verification Tests
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: 'v0.0.2'
repository: spring-projects/spring-framework-release-verification
token: ${{ secrets.token }}
- name: Check Out Send Notification Action
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
path: send-notification
sparse-checkout: .github/actions/send-notification
- name: Set Up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'liberica'
java-version: 17
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
cache-read-only: false
- name: Configure Gradle Properties
@@ -64,7 +64,7 @@ jobs:
run: ./gradlew spring-framework-release-verification-tests:test
- name: Upload Build Reports on Failure
if: failure()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: build-reports
path: '**/build/reports/'
+3 -1
View File
@@ -9,6 +9,7 @@ ivy-cache
argfile*
activemq-data/
classes/
.cursor/
# Log files
jxl.log
@@ -38,7 +39,7 @@ bin
.springBeans
spring-*/src/main/java/META-INF/MANIFEST.MF
# IDEA artifacts and output dirs
# IntelliJ IDEA artifacts and output dirs
*.iml
*.ipr
*.iws
@@ -54,3 +55,4 @@ atlassian-ide-plugin.xml
cached-antora-playbook.yml
node_modules
/.kotlin/
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.13-librca
java=25-librca
+2 -2
View File
@@ -1,4 +1,4 @@
# Contributing to the Spring Framework
# Contributing to the Spring Framework
First off, thank you for taking the time to contribute! :+1: :tada:
@@ -120,7 +120,7 @@ source code into your IDE.
The wiki pages
[Code Style](https://github.com/spring-projects/spring-framework/wiki/Code-Style) and
[IntelliJ IDEA Editor Settings](https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings)
define the source file coding standards we use along with some IDEA editor settings we customize.
define the source file coding standards we use along with some IntelliJ editor settings we customize.
### Reference Docs
+19 -42
View File
@@ -1,15 +1,12 @@
plugins {
id 'io.freefair.aspectj' version '8.4' apply false
id 'io.freefair.aspectj' version '8.13.1' apply false
// kotlinVersion is managed in gradle.properties
id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" apply false
id 'org.jetbrains.dokka' version '1.9.20'
id 'com.github.ben-manes.versions' version '0.51.0'
id 'org.jetbrains.dokka'
id 'com.github.bjornvester.xjc' version '1.8.2' apply false
id 'de.undercouch.download' version '5.4.0'
id 'io.github.goooler.shadow' version '8.1.8' apply false
id 'com.gradleup.shadow' version "9.2.2" apply false
id 'me.champeau.jmh' version '0.7.2' apply false
id 'me.champeau.mrjar' version '0.1.1'
id "net.ltgt.errorprone" version "4.1.0" apply false
id 'io.spring.nullability' version '0.0.11' apply false
}
ext {
@@ -24,13 +21,6 @@ configure(allprojects) { project ->
group = "org.springframework"
repositories {
mavenCentral()
maven {
url = "https://repo.spring.io/milestone"
content {
// Netty 5 optional support
includeGroup 'io.projectreactor.netty'
}
}
if (version.contains('-')) {
maven { url = "https://repo.spring.io/milestone" }
}
@@ -64,7 +54,6 @@ configure([rootProject] + javaProjects) { project ->
apply plugin: "java"
apply plugin: "java-test-fixtures"
apply plugin: 'org.springframework.build.conventions'
apply from: "${rootDir}/gradle/toolchains.gradle"
apply from: "${rootDir}/gradle/ide.gradle"
dependencies {
@@ -72,39 +61,27 @@ configure([rootProject] + javaProjects) { project ->
testImplementation("org.junit.platform:junit-platform-suite")
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
testImplementation("io.mockk:mockk")
testImplementation("io.mockk:mockk") {
exclude group: 'junit', module: 'junit'
}
testImplementation("org.assertj:assertj-core")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testRuntimeOnly("org.apache.logging.log4j:log4j-core")
testRuntimeOnly("org.apache.logging.log4j:log4j-jul")
testRuntimeOnly("org.apache.logging.log4j:log4j-slf4j2-impl")
// JSR-305 only used for non-required meta-annotations
compileOnly("com.google.code.findbugs:jsr305")
testCompileOnly("com.google.code.findbugs:jsr305")
}
ext.javadocLinks = [
"https://docs.oracle.com/en/java/javase/17/docs/api/",
"https://jakarta.ee/specifications/platform/9/apidocs/",
"https://docs.hibernate.org/orm/5.6/javadocs/",
"https://www.quartz-scheduler.org/api/2.3.0/",
"https://fasterxml.github.io/jackson-core/javadoc/2.14/",
"https://fasterxml.github.io/jackson-databind/javadoc/2.14/",
"https://fasterxml.github.io/jackson-dataformat-xml/javadoc/2.14/",
"https://hc.apache.org/httpcomponents-client-5.5.x/current/httpclient5/apidocs/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
// TODO Uncomment link to JUnit 5 docs once we execute Gradle with Java 18+.
// See https://github.com/spring-projects/spring-framework/issues/27497
//
// "https://junit.org/junit5/docs/5.14.1/api/",
"https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/",
//"https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/",
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
// Previously there could be a split-package issue between JSR250 and JSR305 javax.annotation packages,
// but since 6.0 JSR 250 annotations such as @Resource and @PostConstruct have been replaced by their
// JakartaEE equivalents in the jakarta.annotation package.
//"https://www.javadoc.io/doc/com.google.code.findbugs/jsr305/3.0.2/"
"https://docs.oracle.com/en/java/javase/17/docs/api/",
//"https://jakarta.ee/specifications/platform/11/apidocs/",
"https://docs.hibernate.org/orm/7.2/javadocs/",
"https://www.quartz-scheduler.org/api/2.3.0/",
"https://hc.apache.org/httpcomponents-client-5.6.x/5.6/httpclient5/apidocs/",
"https://projectreactor.io/docs/core/release/api/",
"https://projectreactor.io/docs/test/release/api/",
"https://junit.org/junit4/javadoc/4.13.2/",
"https://docs.junit.org/6.1.0/api/",
"https://www.reactive-streams.org/reactive-streams-1.0.4-javadoc/",
"https://r2dbc.io/spec/1.0.0.RELEASE/api/",
"https://jspecify.dev/docs/api/"
] as String[]
}
+31 -1
View File
@@ -9,7 +9,18 @@ The `org.springframework.build.conventions` plugin applies all conventions to th
* Configuring the Java compiler, see `JavaConventions`
* Configuring the Kotlin compiler, see `KotlinConventions`
* Configuring testing in the build with `TestConventions`
* Configuring testing in the build with `TestConventions`
* Configuring the ArchUnit rules for the project, see `org.springframework.build.architecture.ArchitectureRules`
This plugin also provides a DSL extension to optionally enable Java preview features for
compiling and testing sources in a module. This can be applied with the following in a
module build file:
```groovy
springFramework {
enableJavaPreviewFeatures = true
}
```
## Build Plugins
@@ -22,6 +33,25 @@ but doesn't affect the classpath of dependent projects.
This plugin does not provide a `provided` configuration, as the native `compileOnly` and `testCompileOnly`
configurations are preferred.
### MultiRelease Jar
The `org.springframework.build.multiReleaseJar` plugin configures the project with MultiRelease JAR support.
It creates a new SourceSet and dedicated tasks for each Java variant considered.
This can be configured with the DSL, by setting a list of Java variants to configure:
```groovy
plugins {
id 'org.springframework.build.multiReleaseJar'
}
multiRelease {
releaseVersions 21, 24
}
```
Note, Java classes will be compiled with the toolchain pre-configured by the project, assuming that its
Java language version is equal or higher than all variants we consider. Each compilation task will only
set the "-release" compilation option accordingly to produce the expected bytecode version.
### RuntimeHints Java Agent
+22 -2
View File
@@ -20,14 +20,24 @@ ext {
dependencies {
checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}"
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
implementation "org.jetbrains.kotlin:kotlin-compiler-embeddable:${kotlinVersion}"
implementation "org.gradle:test-retry-gradle-plugin:1.5.6"
implementation "org.jetbrains.dokka:dokka-gradle-plugin:2.2.0"
implementation "com.tngtech.archunit:archunit:1.4.1"
implementation "org.gradle:test-retry-gradle-plugin:1.6.2"
implementation "io.spring.javaformat:spring-javaformat-gradle-plugin:${javaFormatVersion}"
implementation "io.spring.nohttp:nohttp-gradle:0.0.11"
testImplementation("org.assertj:assertj-core:${assertjVersion}")
testImplementation(platform("org.junit:junit-bom:${junitVersion}"))
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
gradlePlugin {
plugins {
architecturePlugin {
id = "org.springframework.architecture"
implementationClass = "org.springframework.build.architecture.ArchitecturePlugin"
}
conventionsPlugin {
id = "org.springframework.build.conventions"
implementationClass = "org.springframework.build.ConventionsPlugin"
@@ -36,6 +46,10 @@ gradlePlugin {
id = "org.springframework.build.localdev"
implementationClass = "org.springframework.build.dev.LocalDevelopmentPlugin"
}
multiReleasePlugin {
id = "org.springframework.build.multiReleaseJar"
implementationClass = "org.springframework.build.multirelease.MultiReleaseJarPlugin"
}
optionalDependenciesPlugin {
id = "org.springframework.build.optional-dependencies"
implementationClass = "org.springframework.build.optional.OptionalDependenciesPlugin"
@@ -46,3 +60,9 @@ gradlePlugin {
}
}
}
test {
useJUnitPlatform()
}
jar.dependsOn check
+6 -7
View File
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="com.puppycrawl.tools.checkstyle.Checker">
<module name="Checker">
<!-- Root Checks -->
<module name="io.spring.javaformat.checkstyle.check.SpringHeaderCheck">
@@ -12,16 +12,15 @@
<module name="com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck"/>
<!-- TreeWalker Checks -->
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
<module name="TreeWalker">
<!-- Imports -->
<module name="com.puppycrawl.tools.checkstyle.checks.imports.UnusedImportsCheck">
<property name="processJavadoc" value="true"/>
</module>
<module name="AvoidStarImport"/>
<module name="UnusedImports"/>
<module name="RedundantImport"/>
<!-- Modifiers -->
<module name="com.puppycrawl.tools.checkstyle.checks.modifier.ModifierOrderCheck"/>
</module>
</module>
</module>
+2
View File
@@ -1,2 +1,4 @@
org.gradle.caching=true
assertjVersion=3.27.3
javaFormatVersion=0.0.43
junitVersion=5.12.2
@@ -50,7 +50,7 @@ public class CheckstyleConventions {
project.getPlugins().apply(CheckstylePlugin.class);
project.getTasks().withType(Checkstyle.class).forEach(checkstyle -> checkstyle.getMaxHeapSize().set("1g"));
CheckstyleExtension checkstyle = project.getExtensions().getByType(CheckstyleExtension.class);
checkstyle.setToolVersion("10.26.1");
checkstyle.setToolVersion("13.4.2");
checkstyle.getConfigDirectory().set(project.getRootProject().file("src/checkstyle"));
String version = SpringJavaFormatPlugin.class.getPackage().getImplementationVersion();
DependencySet checkstyleDependencies = project.getConfigurations().getByName("checkstyle").getDependencies();
@@ -63,8 +63,8 @@ public class CheckstyleConventions {
project.getPlugins().apply(NoHttpPlugin.class);
NoHttpExtension noHttp = project.getExtensions().getByType(NoHttpExtension.class);
noHttp.setAllowlistFile(project.file("src/nohttp/allowlist.lines"));
noHttp.getSource().exclude("**/test-output/**", "**/.settings/**",
"**/.classpath", "**/.project", "**/.gradle/**", "**/node_modules/**", "buildSrc/build/**");
noHttp.getSource().exclude("**/test-output/**", "**/.settings/**", "**/.classpath",
"**/.project", "**/.gradle/**", "**/node_modules/**", "**/spring-jcl/**", "buildSrc/build/**");
List<String> buildFolders = List.of("bin", "build", "out");
project.allprojects(subproject -> {
Path rootPath = project.getRootDir().toPath();
@@ -21,12 +21,15 @@ import org.gradle.api.Project;
import org.gradle.api.plugins.JavaBasePlugin;
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin;
import org.springframework.build.architecture.ArchitecturePlugin;
/**
* Plugin to apply conventions to projects that are part of Spring Framework's build.
* Conventions are applied in response to various plugins being applied.
*
* <p>When the {@link JavaBasePlugin} is applied, the conventions in {@link CheckstyleConventions},
* {@link TestConventions} and {@link JavaConventions} are applied.
* The {@link ArchitecturePlugin} plugin is also applied.
* When the {@link KotlinBasePlugin} is applied, the conventions in {@link KotlinConventions}
* are applied.
*
@@ -36,6 +39,8 @@ public class ConventionsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getExtensions().create("springFramework", SpringFrameworkExtension.class);
new ArchitecturePlugin().apply(project);
new CheckstyleConventions().apply(project);
new JavaConventions().apply(project);
new KotlinConventions().apply(project);
@@ -17,7 +17,6 @@
package org.springframework.build;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.gradle.api.Plugin;
@@ -27,7 +26,6 @@ import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.jvm.toolchain.JavaLanguageVersion;
import org.gradle.jvm.toolchain.JvmVendorSpec;
/**
* {@link Plugin} that applies conventions for compiling Java sources in Spring Framework.
@@ -42,8 +40,21 @@ public class JavaConventions {
private static final List<String> TEST_COMPILER_ARGS;
/**
* The Java version we should use as the JVM baseline for building the project.
* <p>NOTE: If you update this value, you should also update the value used in
* the {@code javadoc} task in {@code framework-api.gradle}.
*/
private static final JavaLanguageVersion DEFAULT_LANGUAGE_VERSION = JavaLanguageVersion.of(25);
/**
* The Java version we should use as the baseline for the compiled bytecode
* (the "-release" compiler argument).
*/
private static final JavaLanguageVersion DEFAULT_RELEASE_VERSION = JavaLanguageVersion.of(17);
static {
List<String> commonCompilerArgs = Arrays.asList(
List<String> commonCompilerArgs = List.of(
"-Xlint:serial", "-Xlint:cast", "-Xlint:classfile", "-Xlint:dep-ann",
"-Xlint:divzero", "-Xlint:empty", "-Xlint:finally", "-Xlint:overrides",
"-Xlint:path", "-Xlint:processing", "-Xlint:static", "-Xlint:try", "-Xlint:-options",
@@ -51,43 +62,74 @@ public class JavaConventions {
);
COMPILER_ARGS = new ArrayList<>();
COMPILER_ARGS.addAll(commonCompilerArgs);
COMPILER_ARGS.addAll(Arrays.asList(
COMPILER_ARGS.addAll(List.of(
"-Xlint:varargs", "-Xlint:fallthrough", "-Xlint:rawtypes", "-Xlint:deprecation",
"-Xlint:unchecked", "-Werror"
));
TEST_COMPILER_ARGS = new ArrayList<>();
TEST_COMPILER_ARGS.addAll(commonCompilerArgs);
TEST_COMPILER_ARGS.addAll(Arrays.asList("-Xlint:-varargs", "-Xlint:-fallthrough", "-Xlint:-rawtypes",
TEST_COMPILER_ARGS.addAll(List.of("-Xlint:-varargs", "-Xlint:-fallthrough", "-Xlint:-rawtypes",
"-Xlint:-deprecation", "-Xlint:-unchecked"));
}
public void apply(Project project) {
project.getPlugins().withType(JavaBasePlugin.class, javaPlugin -> applyJavaCompileConventions(project));
project.getPlugins().withType(JavaBasePlugin.class, javaPlugin -> {
applyToolchainConventions(project);
applyJavaCompileConventions(project);
});
}
/**
* Applies the common Java compiler options for main sources, test fixture sources, and
* Configure the Toolchain support for the project.
* @param project the current project
*/
private static void applyToolchainConventions(Project project) {
project.getExtensions().getByType(JavaPluginExtension.class).toolchain(toolchain -> {
toolchain.getLanguageVersion().set(DEFAULT_LANGUAGE_VERSION);
});
}
/**
* Apply the common Java compiler options for main sources, test fixture sources, and
* test sources.
* @param project the current project
*/
private void applyJavaCompileConventions(Project project) {
project.getExtensions().getByType(JavaPluginExtension.class).toolchain(toolchain -> {
toolchain.getVendor().set(JvmVendorSpec.BELLSOFT);
toolchain.getLanguageVersion().set(JavaLanguageVersion.of(17));
project.afterEvaluate(p -> {
p.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().startsWith(JavaPlugin.COMPILE_JAVA_TASK_NAME))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
setJavaRelease(compileTask);
});
p.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().startsWith(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME)
|| compileTask.getName().equals("compileTestFixturesJava"))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
setJavaRelease(compileTask);
});
});
project.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_JAVA_TASK_NAME))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
});
project.getTasks().withType(JavaCompile.class)
.matching(compileTask -> compileTask.getName().equals(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME)
|| compileTask.getName().equals("compileTestFixturesJava"))
.forEach(compileTask -> {
compileTask.getOptions().setCompilerArgs(TEST_COMPILER_ARGS);
compileTask.getOptions().setEncoding("UTF-8");
});
}
/**
* We should pick the {@link #DEFAULT_RELEASE_VERSION} for all compiled classes,
* unless the current task is compiling multi-release JAR code with a higher version.
*/
private void setJavaRelease(JavaCompile task) {
int defaultVersion = DEFAULT_RELEASE_VERSION.asInt();
int releaseVersion = defaultVersion;
int compilerVersion = task.getJavaCompiler().get().getMetadata().getLanguageVersion().asInt();
for (int version = defaultVersion ; version <= compilerVersion ; version++) {
if (task.getName().contains("Java" + version)) {
releaseVersion = version;
break;
}
}
task.getOptions().getRelease().set(releaseVersion);
}
}
@@ -16,33 +16,78 @@
package org.springframework.build;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.Project;
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.jetbrains.dokka.gradle.DokkaExtension;
import org.jetbrains.dokka.gradle.DokkaPlugin;
import org.jetbrains.kotlin.gradle.dsl.JvmTarget;
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion;
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile;
/**
* @author Brian Clozel
* @author Sebastien Deleuze
*/
public class KotlinConventions {
void apply(Project project) {
project.getPlugins().withId("org.jetbrains.kotlin.jvm",
(plugin) -> project.getTasks().withType(KotlinCompile.class, this::configure));
project.getPlugins().withId("org.jetbrains.kotlin.jvm", plugin -> {
project.getTasks().withType(KotlinCompile.class, this::configure);
if (project.getLayout().getProjectDirectory().dir("src/main/kotlin").getAsFile().exists()) {
project.getPlugins().apply(DokkaPlugin.class);
project.getExtensions().configure(DokkaExtension.class, dokka -> configure(project, dokka));
project.project(":framework-api").getDependencies().add("dokka", project);
}
});
}
private void configure(KotlinCompile compile) {
KotlinJvmOptions kotlinOptions = compile.getKotlinOptions();
kotlinOptions.setApiVersion("1.7");
kotlinOptions.setLanguageVersion("1.7");
kotlinOptions.setJvmTarget("17");
kotlinOptions.setJavaParameters(true);
kotlinOptions.setAllWarningsAsErrors(true);
List<String> freeCompilerArgs = new ArrayList<>(compile.getKotlinOptions().getFreeCompilerArgs());
freeCompilerArgs.addAll(List.of("-Xsuppress-version-warnings", "-Xjsr305=strict", "-opt-in=kotlin.RequiresOptIn"));
compile.getKotlinOptions().setFreeCompilerArgs(freeCompilerArgs);
compile.compilerOptions(options -> {
options.getApiVersion().set(KotlinVersion.KOTLIN_2_2);
options.getLanguageVersion().set(KotlinVersion.KOTLIN_2_2);
options.getJvmTarget().set(JvmTarget.JVM_17);
options.getJavaParameters().set(true);
options.getAllWarningsAsErrors().set(true);
options.getFreeCompilerArgs().addAll(
"-Xsuppress-version-warnings",
"-Xjsr305=strict", // For dependencies using JSR 305
"-opt-in=kotlin.RequiresOptIn",
"-Xjdk-release=17", // Needed due to https://youtrack.jetbrains.com/issue/KT-49746
"-Xannotation-default-target=param-property" // Upcoming default, see https://youtrack.jetbrains.com/issue/KT-73255
);
});
}
private void configure(Project project, DokkaExtension dokka) {
dokka.getDokkaSourceSets().forEach(sourceSet -> {
sourceSet.getSourceRoots().setFrom(project.file("src/main/kotlin"));
sourceSet.getClasspath()
.from(project.getExtensions()
.getByType(SourceSetContainer.class)
.getByName(SourceSet.MAIN_SOURCE_SET_NAME)
.getOutput());
var externalDocumentationLinks = sourceSet.getExternalDocumentationLinks();
var springVersion = project.getVersion();
externalDocumentationLinks.register("spring-framework", spec -> {
spec.url("https://docs.spring.io/spring-framework/docs/" + springVersion + "/javadoc-api/");
spec.packageListUrl("https://docs.spring.io/spring-framework/docs/" + springVersion + "/javadoc-api/element-list");
});
externalDocumentationLinks.register("reactor-core", spec ->
spec.url("https://projectreactor.io/docs/core/release/api/"));
externalDocumentationLinks.register("reactive-streams", spec ->
spec.url("https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/"));
externalDocumentationLinks.register("kotlinx-coroutines", spec ->
spec.url("https://kotlinlang.org/api/kotlinx.coroutines/"));
externalDocumentationLinks.register("hamcrest", spec ->
spec.url("https://javadoc.io/doc/org.hamcrest/hamcrest/2.1/"));
externalDocumentationLinks.register("jakarta-servlet", spec -> {
spec.url("https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/latest/");
spec.packageListUrl("https://javadoc.io/doc/jakarta.servlet/jakarta.servlet-api/latest/element-list");
});
externalDocumentationLinks.register("rsocket-core", spec ->
spec.url("https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/"));
});
}
}
@@ -0,0 +1,53 @@
/*
* Copyright 2002-present the original author 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.build;
import java.util.Collections;
import java.util.List;
import org.gradle.api.Project;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.testing.Test;
import org.gradle.process.CommandLineArgumentProvider;
public class SpringFrameworkExtension {
private final Property<Boolean> enableJavaPreviewFeatures;
public SpringFrameworkExtension(Project project) {
this.enableJavaPreviewFeatures = project.getObjects().property(Boolean.class);
project.getTasks().withType(JavaCompile.class).configureEach(javaCompile ->
javaCompile.getOptions().getCompilerArgumentProviders().add(asArgumentProvider()));
project.getTasks().withType(Test.class).configureEach(test ->
test.getJvmArgumentProviders().add(asArgumentProvider()));
}
public Property<Boolean> getEnableJavaPreviewFeatures() {
return this.enableJavaPreviewFeatures;
}
private CommandLineArgumentProvider asArgumentProvider() {
return () -> {
if (getEnableJavaPreviewFeatures().getOrElse(false)) {
return List.of("--enable-preview");
}
return Collections.emptyList();
};
}
}
@@ -16,9 +16,9 @@
package org.springframework.build;
import java.util.Map;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.tasks.testing.Test;
import org.gradle.api.tasks.testing.TestFrameworkOptions;
@@ -26,12 +26,16 @@ import org.gradle.api.tasks.testing.junitplatform.JUnitPlatformOptions;
import org.gradle.testretry.TestRetryPlugin;
import org.gradle.testretry.TestRetryTaskExtension;
import java.util.Map;
/**
* Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the
* plugin is applied:
* <ul>
* <li>The {@link TestRetryPlugin Test Retry} plugin is applied so that flaky tests
* are retried 3 times when running on the CI server.
* <li>Common test properties are configured
* <li>The ByteBuddy Java agent is configured on test tasks.
* </ul>
*
* @author Brian Clozel
@@ -45,6 +49,7 @@ class TestConventions {
}
private void configureTestConventions(Project project) {
configureByteBuddyAgent(project);
project.getTasks().withType(Test.class,
test -> {
configureTests(project, test);
@@ -63,9 +68,7 @@ class TestConventions {
test.setSystemProperties(Map.of(
"java.awt.headless", "true",
"io.netty.leakDetection.level", "paranoid",
"io.netty5.leakDetectionLevel", "paranoid",
"io.netty5.leakDetection.targetRecords", "32",
"io.netty5.buffer.lifecycleTracingEnabled", "true"
"junit.platform.discovery.issue.severity.critical", "INFO"
));
if (project.hasProperty("testGroups")) {
test.systemProperty("testGroups", project.getProperties().get("testGroups"));
@@ -77,6 +80,20 @@ class TestConventions {
);
}
private void configureByteBuddyAgent(Project project) {
if (project.hasProperty("byteBuddyVersion")) {
String byteBuddyVersion = (String) project.getProperties().get("byteBuddyVersion");
Configuration byteBuddyAgentConfig = project.getConfigurations().create("byteBuddyAgentConfig");
byteBuddyAgentConfig.setTransitive(false);
Dependency byteBuddyAgent = project.getDependencies().create("net.bytebuddy:byte-buddy-agent:" + byteBuddyVersion);
byteBuddyAgentConfig.getDependencies().add(byteBuddyAgent);
project.afterEvaluate(p -> {
p.getTasks().withType(Test.class, test -> test
.jvmArgs("-javaagent:" + byteBuddyAgentConfig.getAsPath()));
});
}
}
private void configureTestRetryPlugin(Project project, Test test) {
project.getPlugins().withType(TestRetryPlugin.class, testRetryPlugin -> {
TestRetryTaskExtension testRetry = test.getExtensions().getByType(TestRetryTaskExtension.class);
@@ -0,0 +1,135 @@
/*
* Copyright 2002-present the original author 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.build.architecture;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.EvaluationResult;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.List;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.Task;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.IgnoreEmptyDirectories;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
import org.gradle.api.tasks.TaskAction;
import static org.springframework.build.architecture.ArchitectureRules.allPackagesShouldBeFreeOfTangles;
import static org.springframework.build.architecture.ArchitectureRules.classesShouldNotImportForbiddenTypes;
import static org.springframework.build.architecture.ArchitectureRules.javaClassesShouldNotImportKotlinAnnotations;
import static org.springframework.build.architecture.ArchitectureRules.noClassesShouldCallStringToLowerCaseWithoutLocale;
import static org.springframework.build.architecture.ArchitectureRules.noClassesShouldCallStringToUpperCaseWithoutLocale;
/**
* {@link Task} that checks for architecture problems.
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
public abstract class ArchitectureCheck extends DefaultTask {
private FileCollection classes;
public ArchitectureCheck() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
getProhibitObjectsRequireNonNull().convention(true);
getRules().addAll(classesShouldNotImportForbiddenTypes(),
javaClassesShouldNotImportKotlinAnnotations(),
allPackagesShouldBeFreeOfTangles(),
noClassesShouldCallStringToLowerCaseWithoutLocale(),
noClassesShouldCallStringToUpperCaseWithoutLocale());
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
}
@TaskAction
void checkArchitecture() throws IOException {
JavaClasses javaClasses = new ClassFileImporter()
.importPaths(this.classes.getFiles().stream().map(File::toPath).toList());
List<EvaluationResult> violations = getRules().get()
.stream()
.map((rule) -> rule.evaluate(javaClasses))
.filter(EvaluationResult::hasViolation)
.toList();
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
outputFile.getParentFile().mkdirs();
if (!violations.isEmpty()) {
StringBuilder report = new StringBuilder();
for (EvaluationResult violation : violations) {
report.append(violation.getFailureReport());
report.append(String.format("%n"));
}
Files.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
throw new GradleException("Architecture check failed. See '" + outputFile + "' for details.");
}
else {
outputFile.createNewFile();
}
}
public void setClasses(FileCollection classes) {
this.classes = classes;
}
@Internal
public FileCollection getClasses() {
return this.classes;
}
@InputFiles
@SkipWhenEmpty
@IgnoreEmptyDirectories
@PathSensitive(PathSensitivity.RELATIVE)
final FileTree getInputClasses() {
return this.classes.getAsFileTree();
}
@Optional
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
public abstract DirectoryProperty getResourcesDirectory();
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@Internal
public abstract ListProperty<ArchRule> getRules();
@Internal
public abstract Property<Boolean> getProhibitObjectsRequireNonNull();
@Input
// The rules themselves can't be an input as they aren't serializable so we use
// their descriptions instead
abstract ListProperty<String> getRuleDescriptions();
}
@@ -0,0 +1,74 @@
/*
* Copyright 2002-present the original author 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.build.architecture;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* {@link Plugin} for verifying a project's architecture.
*
* @author Andy Wilkinson
*/
public class ArchitecturePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> registerTasks(project));
}
private void registerTasks(Project project) {
JavaPluginExtension javaPluginExtension = project.getExtensions().getByType(JavaPluginExtension.class);
List<TaskProvider<ArchitectureCheck>> architectureChecks = new ArrayList<>();
for (SourceSet sourceSet : javaPluginExtension.getSourceSets()) {
if (sourceSet.getName().contains("test")) {
// skip test source sets.
continue;
}
TaskProvider<ArchitectureCheck> checkArchitecture = project.getTasks()
.register(taskName(sourceSet), ArchitectureCheck.class,
(task) -> {
task.setClasses(sourceSet.getOutput().getClassesDirs());
task.getResourcesDirectory().set(sourceSet.getOutput().getResourcesDir());
task.dependsOn(sourceSet.getProcessResourcesTaskName());
task.setDescription("Checks the architecture of the classes of the " + sourceSet.getName()
+ " source set.");
task.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
});
architectureChecks.add(checkArchitecture);
}
if (!architectureChecks.isEmpty()) {
TaskProvider<Task> checkTask = project.getTasks().named(LifecycleBasePlugin.CHECK_TASK_NAME);
checkTask.configure((check) -> check.dependsOn(architectureChecks));
}
}
private static String taskName(SourceSet sourceSet) {
return "checkArchitecture"
+ sourceSet.getName().substring(0, 1).toUpperCase()
+ sourceSet.getName().substring(1);
}
}
@@ -0,0 +1,100 @@
/*
* Copyright 2002-present the original author 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.build.architecture;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import com.tngtech.archunit.library.dependencies.SliceAssignment;
import com.tngtech.archunit.library.dependencies.SliceIdentifier;
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;
import java.util.List;
abstract class ArchitectureRules {
static ArchRule allPackagesShouldBeFreeOfTangles() {
return SlicesRuleDefinition.slices()
.assignedFrom(new SpringSlices()).should().beFreeOfCycles();
}
static ArchRule noClassesShouldCallStringToLowerCaseWithoutLocale() {
return ArchRuleDefinition.noClasses()
.should()
.callMethod(String.class, "toLowerCase")
.because("String.toLowerCase(Locale.ROOT) should be used instead");
}
static ArchRule noClassesShouldCallStringToUpperCaseWithoutLocale() {
return ArchRuleDefinition.noClasses()
.should()
.callMethod(String.class, "toUpperCase")
.because("String.toUpperCase(Locale.ROOT) should be used instead");
}
static ArchRule classesShouldNotImportForbiddenTypes() {
return ArchRuleDefinition.noClasses()
.should().dependOnClassesThat()
.haveFullyQualifiedName("reactor.core.support.Assert")
.orShould().dependOnClassesThat()
.haveFullyQualifiedName("org.slf4j.LoggerFactory")
.orShould().dependOnClassesThat()
.haveFullyQualifiedName("org.springframework.lang.NonNull")
.orShould().dependOnClassesThat()
.haveFullyQualifiedName("org.springframework.lang.Nullable");
}
static ArchRule javaClassesShouldNotImportKotlinAnnotations() {
return ArchRuleDefinition.noClasses()
.that(new DescribedPredicate<JavaClass>("is not a Kotlin class") {
@Override
public boolean test(JavaClass javaClass) {
return javaClass.getSourceCodeLocation()
.getSourceFileName().endsWith(".java");
}
}
)
.should().dependOnClassesThat()
.resideInAnyPackage("org.jetbrains.annotations..")
.allowEmptyShould(true);
}
static class SpringSlices implements SliceAssignment {
private final List<String> ignoredPackages = List.of("org.springframework.asm",
"org.springframework.cglib",
"org.springframework.javapoet",
"org.springframework.objenesis");
@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
String packageName = javaClass.getPackageName();
for (String ignoredPackage : ignoredPackages) {
if (packageName.startsWith(ignoredPackage)) {
return SliceIdentifier.ignore();
}
}
return SliceIdentifier.of("spring framework");
}
@Override
public String getDescription() {
return "Spring Framework Slices";
}
}
}
@@ -0,0 +1,139 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import javax.inject.Inject;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.attributes.LibraryElements;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
import org.gradle.api.java.archives.Attributes;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.testing.Test;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* @author Cedric Champeau
* @author Brian Clozel
*/
public abstract class MultiReleaseExtension {
private final TaskContainer tasks;
private final SourceSetContainer sourceSets;
private final DependencyHandler dependencies;
private final ObjectFactory objects;
private final ConfigurationContainer configurations;
@Inject
public MultiReleaseExtension(SourceSetContainer sourceSets,
ConfigurationContainer configurations,
TaskContainer tasks,
DependencyHandler dependencies,
ObjectFactory objectFactory) {
this.sourceSets = sourceSets;
this.configurations = configurations;
this.tasks = tasks;
this.dependencies = dependencies;
this.objects = objectFactory;
}
public void releaseVersions(int... javaVersions) {
releaseVersions("src/main/", "src/test/", javaVersions);
}
private void releaseVersions(String mainSourceDirectory, String testSourceDirectory, int... javaVersions) {
for (int javaVersion : javaVersions) {
addLanguageVersion(javaVersion, mainSourceDirectory, testSourceDirectory);
}
}
private void addLanguageVersion(int javaVersion, String mainSourceDirectory, String testSourceDirectory) {
String javaN = "java" + javaVersion;
SourceSet langSourceSet = sourceSets.create(javaN, srcSet -> srcSet.getJava().srcDir(mainSourceDirectory + javaN));
SourceSet testSourceSet = sourceSets.create(javaN + "Test", srcSet -> srcSet.getJava().srcDir(testSourceDirectory + javaN));
SourceSet sharedSourceSet = sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME);
SourceSet sharedTestSourceSet = sourceSets.findByName(SourceSet.TEST_SOURCE_SET_NAME);
FileCollection mainClasses = objects.fileCollection().from(sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput().getClassesDirs());
dependencies.add(javaN + "Implementation", mainClasses);
tasks.named(langSourceSet.getCompileJavaTaskName(), JavaCompile.class, task ->
task.getOptions().getRelease().set(javaVersion)
);
tasks.named(testSourceSet.getCompileJavaTaskName(), JavaCompile.class, task ->
task.getOptions().getRelease().set(javaVersion)
);
TaskProvider<Test> testTask = createTestTask(javaVersion, testSourceSet, sharedTestSourceSet, langSourceSet, sharedSourceSet);
tasks.named("check", task -> task.dependsOn(testTask));
configureMultiReleaseJar(javaVersion, langSourceSet);
}
private TaskProvider<Test> createTestTask(int javaVersion, SourceSet testSourceSet, SourceSet sharedTestSourceSet, SourceSet langSourceSet, SourceSet sharedSourceSet) {
Configuration testImplementation = configurations.getByName(testSourceSet.getImplementationConfigurationName());
testImplementation.extendsFrom(configurations.getByName(sharedTestSourceSet.getImplementationConfigurationName()));
Configuration testCompileOnly = configurations.getByName(testSourceSet.getCompileOnlyConfigurationName());
testCompileOnly.extendsFrom(configurations.getByName(sharedTestSourceSet.getCompileOnlyConfigurationName()));
testCompileOnly.getDependencies().add(dependencies.create(langSourceSet.getOutput().getClassesDirs()));
testCompileOnly.getDependencies().add(dependencies.create(sharedSourceSet.getOutput().getClassesDirs()));
Configuration testRuntimeClasspath = configurations.getByName(testSourceSet.getRuntimeClasspathConfigurationName());
// so here's the deal. MRjars are JARs! Which means that to execute tests, we need
// the JAR on classpath, not just classes + resources as Gradle usually does
testRuntimeClasspath.getAttributes()
.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.class, LibraryElements.JAR));
TaskProvider<Test> testTask = tasks.register("java" + javaVersion + "Test", Test.class, test -> {
test.setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
ConfigurableFileCollection testClassesDirs = objects.fileCollection();
testClassesDirs.from(testSourceSet.getOutput());
testClassesDirs.from(sharedTestSourceSet.getOutput());
test.setTestClassesDirs(testClassesDirs);
ConfigurableFileCollection classpath = objects.fileCollection();
// must put the MRJar first on classpath
classpath.from(tasks.named("jar"));
// then we put the specific test sourceset tests, so that we can override
// the shared versions
classpath.from(testSourceSet.getOutput());
// then we add the shared tests
classpath.from(sharedTestSourceSet.getRuntimeClasspath());
test.setClasspath(classpath);
});
return testTask;
}
private void configureMultiReleaseJar(int version, SourceSet languageSourceSet) {
tasks.named("jar", Jar.class, jar -> {
jar.into("META-INF/versions/" + version, s -> s.from(languageSourceSet.getOutput()));
Attributes attributes = jar.getManifest().getAttributes();
attributes.put("Multi-Release", "true");
});
}
}
@@ -0,0 +1,76 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import javax.inject.Inject;
import org.gradle.api.JavaVersion;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.dsl.DependencyHandler;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.ExtensionContainer;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
import org.gradle.jvm.tasks.Jar;
import org.gradle.jvm.toolchain.JavaLanguageVersion;
import org.gradle.jvm.toolchain.JavaToolchainService;
/**
* A plugin which adds support for building multi-release jars
* with Gradle.
* @author Cedric Champeau
* @author Brian Clozel
* @see <a href="https://github.com/melix/mrjar-gradle-plugin">original project</a>
*/
public class MultiReleaseJarPlugin implements Plugin<Project> {
public static String VALIDATE_JAR_TASK_NAME = "validateMultiReleaseJar";
@Inject
protected JavaToolchainService getToolchains() {
throw new UnsupportedOperationException();
}
public void apply(Project project) {
project.getPlugins().apply(JavaPlugin.class);
ExtensionContainer extensions = project.getExtensions();
JavaPluginExtension javaPluginExtension = extensions.getByType(JavaPluginExtension.class);
ConfigurationContainer configurations = project.getConfigurations();
TaskContainer tasks = project.getTasks();
DependencyHandler dependencies = project.getDependencies();
ObjectFactory objects = project.getObjects();
extensions.create("multiRelease", MultiReleaseExtension.class,
javaPluginExtension.getSourceSets(),
configurations,
tasks,
dependencies,
objects);
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_25)) {
TaskProvider<MultiReleaseJarValidateTask> validateJarTask = tasks.register(VALIDATE_JAR_TASK_NAME, MultiReleaseJarValidateTask.class, (task) -> {
task.getJar().set(tasks.named("jar", Jar.class).flatMap(AbstractArchiveTask::getArchiveFile));
task.getJavaLauncher().set(task.getJavaToolchainService().launcherFor(spec -> spec.getLanguageVersion().set(JavaLanguageVersion.of(25))));
});
tasks.named("check", task -> task.dependsOn(validateJarTask));
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.jvm.toolchain.JavaToolchainService;
import java.util.List;
import javax.inject.Inject;
@CacheableTask
public abstract class MultiReleaseJarValidateTask extends JavaExec {
public MultiReleaseJarValidateTask() {
getMainModule().set("jdk.jartool");
getArgumentProviders().add(() -> List.of("--validate", "--file", getJar().get().getAsFile().getAbsolutePath()));
}
@Inject
protected abstract JavaToolchainService getJavaToolchainService();
@InputFile
@PathSensitive(PathSensitivity.RELATIVE)
public abstract RegularFileProperty getJar();
}
@@ -78,7 +78,7 @@ public class ShadowSource extends DefaultTask {
}
@OutputDirectory
DirectoryProperty getOutputDirectory() {
public DirectoryProperty getOutputDirectory() {
return this.outputDirectory;
}
@@ -0,0 +1,182 @@
/*
* Copyright 2002-present the original author 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.build.multirelease;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.gradle.testkit.runner.UnexpectedBuildFailure;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
import org.junit.jupiter.api.io.TempDir;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link MultiReleaseJarPlugin}
*/
public class MultiReleaseJarPluginTests {
private File projectDir;
private File buildFile;
private File propertiesFile;
@BeforeEach
void setup(@TempDir File projectDir) {
this.projectDir = projectDir;
this.buildFile = new File(this.projectDir, "build.gradle");
this.propertiesFile = new File(this.projectDir, "gradle.properties");
}
@Test
void configureSourceSets() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
multiRelease { releaseVersions 21, 24 }
task printSourceSets {
doLast {
sourceSets.all { println it.name }
}
}
""");
BuildResult buildResult = runGradle("printSourceSets");
assertThat(buildResult.getOutput()).contains("main", "test", "java21", "java21Test", "java24", "java24Test");
}
@Test
void configureToolchainReleaseVersion() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
multiRelease { releaseVersions 21 }
task printReleaseVersion {
doLast {
tasks.all { println it.name }
tasks.named("compileJava21Java") {
println "compileJava21Java releaseVersion: ${it.options.release.get()}"
}
tasks.named("compileJava21TestJava") {
println "compileJava21TestJava releaseVersion: ${it.options.release.get()}"
}
}
}
""");
BuildResult buildResult = runGradle("printReleaseVersion");
assertThat(buildResult.getOutput()).contains("compileJava21Java releaseVersion: 21")
.contains("compileJava21TestJava releaseVersion: 21");
}
@Test
void packageInJar() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
version = '1.2.3'
multiRelease { releaseVersions 17 }
""");
writeClass("src/main/java17", "Main.java", """
public class Main {}
""");
BuildResult buildResult = runGradle("assemble");
File file = new File(this.projectDir, "/build/libs/" + this.projectDir.getName() + "-1.2.3.jar");
assertThat(file).exists();
try (JarFile jar = new JarFile(file)) {
Attributes mainAttributes = jar.getManifest().getMainAttributes();
assertThat(mainAttributes.getValue("Multi-Release")).isEqualTo("true");
assertThat(jar.entries().asIterator()).toIterable()
.anyMatch(entry -> entry.getName().equals("META-INF/versions/17/Main.class"));
}
}
@Test
@DisabledForJreRange(max = JRE.JAVA_24, disabledReason = "'jar --validate' is available as of Java 25")
void validateJar() throws IOException {
writeBuildFile("""
plugins {
id 'java'
id 'org.springframework.build.multiReleaseJar'
}
version = '1.2.3'
tasks.withType(JavaCompile).configureEach {
options.release = 11
}
multiRelease { releaseVersions 17 }
""");
writeGradleProperties("""
org.gradle.jvmargs=-Duser.language=en
""");
writeClass("src/main/java17", "Main.java", """
public class Main {
public void method() {}
}
""");
writeClass("src/main/java", "Main.java", """
public class Main {}
""");
assertThatThrownBy(() ->runGradle("validateMultiReleaseJar"))
.isInstanceOf(UnexpectedBuildFailure.class)
.hasMessageContaining("entry: META-INF/versions/17/Main.class, contains a class with different api from earlier version");
}
private void writeBuildFile(String buildContent) throws IOException {
try (PrintWriter out = new PrintWriter(new FileWriter(this.buildFile))) {
out.print(buildContent);
}
}
private void writeGradleProperties(String properties) throws IOException {
try (PrintWriter out = new PrintWriter(new FileWriter(this.propertiesFile))) {
out.print(properties);
}
}
private void writeClass(String path, String fileName, String fileContent) throws IOException {
Path folder = this.projectDir.toPath().resolve(path);
Files.createDirectories(folder);
Path filePath = folder.resolve(fileName);
Files.createFile(filePath);
Files.writeString(filePath, fileContent);
}
private BuildResult runGradle(String... args) {
return GradleRunner.create().withProjectDir(this.projectDir).withArguments(args).withPluginClasspath().build();
}
}
+20 -14
View File
@@ -1,6 +1,7 @@
plugins {
id 'java-platform'
id 'io.freefair.aggregate-javadoc' version '8.13.1'
id 'org.jetbrains.dokka'
}
description = "Spring Framework API Docs"
@@ -19,7 +20,12 @@ dependencies {
}
}
def springAspectsOutput = project(":spring-aspects").sourceSets.main.output
javadoc {
javadocTool.set(javaToolchains.javadocToolFor({
languageVersion = JavaLanguageVersion.of(25)
}))
title = "${rootProject.description} ${version} API"
failOnError = true
options {
@@ -34,35 +40,35 @@ javadoc {
links(rootProject.ext.javadocLinks)
// Check for 'syntax' and 'reference' during linting.
addBooleanOption('Xdoclint:syntax,reference', true)
addBooleanOption('Werror', true) // fail build on Javadoc warnings
// Change modularity mismatch from warn to info.
// See https://github.com/spring-projects/spring-framework/issues/27497
addStringOption("-link-modularity-mismatch", "info")
// Fail build on Javadoc warnings.
addBooleanOption('Werror', true)
}
maxMemory = "1024m"
doFirst {
classpath += files(
// ensure the javadoc process can resolve types compiled from .aj sources
project(":spring-aspects").sourceSets.main.output
// ensure the javadoc process can resolve types compiled from .aj sources
springAspectsOutput
)
classpath += files(moduleProjects.collect { it.sourceSets.main.compileClasspath })
}
}
/**
* Produce KDoc for all Spring Framework modules in "build/docs/kdoc"
*/
rootProject.tasks.dokkaHtmlMultiModule.configure {
dependsOn {
tasks.named("javadoc")
dokka {
moduleName = "spring-framework"
dokkaPublications.html {
outputDirectory = project.java.docsDir.dir("kdoc-api")
includes.from("$rootProject.rootDir/framework-docs/src/docs/api/dokka-overview.md")
}
moduleName.set("spring-framework")
outputDirectory.set(project.java.docsDir.dir("kdoc-api").get().asFile)
includes.from("$rootProject.rootDir/framework-docs/src/docs/api/dokka-overview.md")
}
/**
* Zip all Java docs (javadoc & kdoc) into a single archive
*/
tasks.register('docsZip', Zip) {
dependsOn = ['javadoc', rootProject.tasks.dokkaHtmlMultiModule]
dependsOn = ['javadoc', 'dokkaGenerate']
group = "distribution"
description = "Builds -${archiveClassifier} archive containing api and reference " +
"for deployment at https://docs.spring.io/spring-framework/docs/."
@@ -75,7 +81,7 @@ tasks.register('docsZip', Zip) {
from(javadoc) {
into "javadoc-api"
}
from(rootProject.tasks.dokkaHtmlMultiModule.outputDirectory) {
from(project.java.docsDir.dir("kdoc-api")) {
into "kdoc-api"
}
}
+5 -3
View File
@@ -13,8 +13,10 @@ content:
- url: https://github.com/spring-projects/spring-framework
# Refname matching:
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
branches: ['main', '{6..9}.+({1..9}).x']
tags: ['v{6..9}.+({0..9}).+({0..9})?(-{RC,M}*)', '!(v6.0.{0..8})', '!(v6.0.0-{RC,M}{0..9})']
# branches: We include snapshots for main, 6.2.x, and 7.0.x to 9.*.x.
branches: ['main', '6.2.x', '{7..9}.+({0..9}).x']
# tags: include all releases from 6.2.0 to 9.*.*.
tags: ['v6.2.+({0..9})', 'v{7..9}.+({0..9}).+({0..9})?(-{RC,M}*)']
start_path: framework-docs
asciidoc:
extensions:
@@ -36,4 +38,4 @@ runtime:
failure_level: warn
ui:
bundle:
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.18/ui-bundle.zip
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.26/ui-bundle.zip
+27 -4
View File
@@ -1,3 +1,6 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
plugins {
id 'kotlin'
id 'io.spring.antora.generate-antora-yml' version '0.0.1'
@@ -12,11 +15,15 @@ apply from: "${rootDir}/gradle/publications.gradle"
antora {
options = [clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
environment = [
'BUILD_REFNAME': 'HEAD',
'BUILD_VERSION': project.version,
'BUILD_REFNAME': 'HEAD',
'BUILD_VERSION': project.version,
]
}
node {
version = '24.15.0'
}
tasks.named("generateAntoraYml") {
asciidocAttributes = project.provider( {
return ["spring-version": project.version ]
@@ -41,6 +48,16 @@ repositories {
}
}
// To avoid a redeclaration error with Kotlin compiler and set the JVM target
tasks.withType(KotlinCompilationTask.class).configureEach {
javaSources.from = []
compilerOptions.jvmTarget = JvmTarget.JVM_17
compilerOptions.freeCompilerArgs.addAll(
"-Xjdk-release=17", // Needed due to https://youtrack.jetbrains.com/issue/KT-49746
"-Xannotation-default-target=param-property" // Upcoming default, see https://youtrack.jetbrains.com/issue/KT-73255
)
}
dependencies {
implementation(project(":spring-aspects"))
implementation(project(":spring-context"))
@@ -54,10 +71,10 @@ dependencies {
implementation(project(":spring-webmvc"))
implementation(project(":spring-websocket"))
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation("com.fasterxml.jackson.module:jackson-module-parameter-names")
implementation("com.github.ben-manes.caffeine:caffeine")
implementation("com.mchange:c3p0:0.9.5.5")
implementation("com.oracle.database.jdbc:ojdbc11")
implementation("io.micrometer:context-propagation")
implementation("io.projectreactor.netty:reactor-netty-http")
implementation("jakarta.jms:jakarta.jms-api")
implementation("jakarta.servlet:jakarta.servlet-api")
@@ -67,9 +84,15 @@ dependencies {
implementation("javax.cache:cache-api")
implementation("org.apache.activemq:activemq-ra:6.1.2")
implementation("org.apache.commons:commons-dbcp2:2.11.0")
implementation("org.apache.groovy:groovy-templates")
implementation("org.aspectj:aspectjweaver")
implementation("org.assertj:assertj-core")
implementation("org.eclipse.jetty.websocket:jetty-websocket-jetty-api")
implementation("org.freemarker:freemarker")
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
implementation("org.junit.jupiter:junit-jupiter-api")
implementation("tools.jackson.core:jackson-databind")
implementation("tools.jackson.dataformat:jackson-dataformat-xml")
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 158 KiB

@@ -17,6 +17,7 @@
class="st5"
id="svg5499"
version="1.1"
font-family="Helvetica, Arial, sans-serif"
inkscape:version="0.91 r13725"
sodipodi:docname="mvc-splitted-contexts.svg"
style="font-size:12px;overflow:visible;color-interpolation-filters:sRGB;fill:none;fill-rule:evenodd;stroke-linecap:square;stroke-miterlimit:3"
@@ -36,7 +37,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path9164" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -47,7 +48,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path8836" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -58,7 +59,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path8520" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -69,7 +70,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path8216" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -80,7 +81,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7924" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -91,7 +92,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7644" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -102,7 +103,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7375" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -113,7 +114,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path7119" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -124,7 +125,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6875" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -135,7 +136,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6643" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -146,7 +147,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6423" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -157,7 +158,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6215" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -168,7 +169,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path6019" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -179,7 +180,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5835" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -190,7 +191,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5663" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -201,7 +202,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5503" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -212,7 +213,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5355" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -223,7 +224,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5219" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -234,7 +235,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path5095" /></marker><marker
inkscape:isstock="true"
style="overflow:visible;"
@@ -245,7 +246,7 @@
inkscape:stockid="Arrow2Mend"><path
transform="scale(0.6) rotate(180) translate(0,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
id="path4983" /></marker><marker
inkscape:stockid="Arrow2Mend"
orient="auto"
@@ -256,7 +257,7 @@
inkscape:isstock="true"
inkscape:collect="always"><path
id="path7394"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" /></marker><marker
inkscape:stockid="Arrow2Lend"
@@ -267,7 +268,7 @@
style="overflow:visible;"
inkscape:isstock="true"><path
id="path8123"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1;fill:#333333;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
@@ -279,7 +280,7 @@
inkscape:isstock="true"><path
id="path8035"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
@@ -290,7 +291,7 @@
inkscape:isstock="true"><path
id="path7959"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow1Mend"
orient="auto"
@@ -301,7 +302,7 @@
inkscape:isstock="true"><path
id="path7376"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.4) rotate(180) translate(10,0)" /></marker><marker
inkscape:stockid="Arrow2Lend"
orient="auto"
@@ -311,7 +312,7 @@
style="overflow:visible;"
inkscape:isstock="true"><path
id="path7388"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#333333;stroke-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" /></marker><marker
inkscape:stockid="Arrow1Lend"
@@ -323,7 +324,7 @@
inkscape:isstock="true"><path
id="path7370"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
style="fill-rule:evenodd;stroke:#333333;stroke-width:1pt;stroke-opacity:1;fill:#333333;fill-opacity:1"
transform="scale(0.8) rotate(180) translate(12.5,0)" /></marker></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
@@ -352,9 +353,9 @@
v:viewMarkup="false" /><style
type="text/css"
id="style5501"><![CDATA[
.st1 {fill:#969696;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#dde2cd;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st3 {fill:#000000;font-family:Arial;font-size:2.50001em;font-weight:bold}
.st1 {fill:#969696;stroke:#333333;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st2 {fill:#F8F9FA;stroke:#333333;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
.st3 {fill:#333333;font-family:Helvetica, Arial, sans-serif;font-size:2.50001em;font-weight:bold}
.st4 {font-size:0.333333em;font-weight:normal}
.st5 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]></style><g
@@ -363,20 +364,22 @@
v:groupContext="foregroundPage"
id="g5503"
transform="matrix(0.99998201,0,0,1.0824094,-40.812382,-98.908648)"><rect
style="fill:#dde2cd;fill-opacity:1;stroke:#000000;stroke-width:1.53790233;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
style="fill:#F8F9FA;fill-opacity:1;stroke:#6db33f;stroke-width:2;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6599"
width="382.68423"
height="146.09897"
x="87.884865"
y="148.26482" /><v:userDefs><v:ud
y="148.26482"
rx="8" /><v:userDefs><v:ud
v:nameU="SchemeName"
v:val="VT4(Default)" /></v:userDefs><rect
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.53790233;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;fill-opacity:1;stroke:#6db33f;stroke-width:2;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect5725"
width="464.31128"
height="374.11411"
x="41.684383"
y="112.3262" /><title
y="112.3262"
rx="8" /><title
id="title5505">Page-1</title><v:pageProperties
v:drawingScale="0.0393701"
v:pageScale="0.0393701"
@@ -385,15 +388,16 @@
v:shadowOffsetY="-8.50394" /><v:layer
v:name="Connector"
v:index="0" /><rect
style="fill:#dde2cd;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.53790233;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
style="fill:#F8F9FA;fill-opacity:1;fill-rule:evenodd;stroke:#6db33f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect5715"
width="322.8194"
height="43.63184"
x="119.95335"
y="-135.66222"
transform="scale(1,-1)" /><text
transform="scale(1,-1)"
rx="8" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.7580471px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="168.843"
y="124.32391"
id="text5717"
@@ -401,12 +405,12 @@
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan5719"
x="168.843"
x="172.843"
y="124.32391"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:sans-serif;-inkscape-font-specification:sans-serif">DispatcherServlet</tspan></text>
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;fill:#333333">DispatcherServlet</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="89.770851"
y="181.20923"
id="text6589"
@@ -414,12 +418,12 @@
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6591"
x="89.770851"
x="106.770851"
y="181.20923"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:sans-serif;-inkscape-font-specification:sans-serif">Servlet WebApplicationContext</tspan></text>
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;fill:#333333">Servlet WebApplicationContext</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="260.00443"
y="198.41273"
id="text6593"
@@ -429,36 +433,39 @@
id="tspan6595"
x="260.00443"
y="198.41273"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle">(containing controllers, view resolvers,</tspan><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555">(containing controllers, view resolvers,</tspan><tspan
sodipodi:role="line"
x="260.00443"
y="212.83057"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555"
id="tspan6597">and other web-related beans)</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6620"
width="82.040657"
height="36.72575"
x="114.52653"
y="-259.43161"
transform="scale(1,-1)" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.89166164;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
transform="scale(1,-1)"
rx="4" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6622"
width="87.843979"
height="36.697304"
x="223.39864"
y="-287.19809"
transform="scale(1,-1)" /><rect
transform="scale(1,-1)"
rx="4" /><rect
transform="scale(1,-1)"
y="-264.81918"
x="117.92834"
height="36.72575"
width="82.040657"
id="rect6614"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="121.24728"
y="260.14957"
id="text6616"
@@ -466,20 +473,20 @@
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6618"
x="121.24728"
x="124.24728"
y="260.14957"
style="font-size:11.53426838px">Controllers</tspan></text>
style="font-size:11.53426838px;fill:#333333">Controllers</tspan></text>
<text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6624"
y="282.70709"
x="219.61203"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:11.53426838px"
style="font-size:11.53426838px;fill:#333333"
y="282.70709"
x="219.61203"
x="221.61203"
id="tspan6626"
sodipodi:role="line">ViewResolver</tspan></text>
<rect
@@ -489,9 +496,10 @@
height="36.577778"
width="114.4539"
id="rect6628"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.0161339;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="327.51276"
y="255.28464"
id="text6630"
@@ -499,26 +507,27 @@
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6632"
x="327.51276"
x="332.51276"
y="255.28464"
style="font-size:11.53426838px">HandlerMapping</tspan></text>
style="font-size:11.53426838px;fill:#333333">HandlerMapping</tspan></text>
<rect
y="338.69724"
x="87.803261"
height="121.5683"
width="382.84744"
id="rect6634"
style="fill:#dde2cd;fill-opacity:1;stroke:#000000;stroke-width:1.53790233;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
style="fill:#F8F9FA;fill-opacity:1;stroke:#6db33f;stroke-width:2;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="8" /><text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6636"
y="376.61673"
x="108.61351"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:sans-serif;-inkscape-font-specification:sans-serif"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.06853676px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;fill:#333333"
y="376.61673"
x="108.61351"
x="113.61351"
id="tspan6638"
sodipodi:role="line">Root WebApplicationContext</tspan></text>
<text
@@ -527,10 +536,10 @@
id="text6640"
y="395.35812"
x="260.93863"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
id="tspan6644"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555"
y="395.35812"
x="260.93863"
sodipodi:role="line">(containing middle-tier services, datasources, etc.)</tspan></text>
@@ -541,43 +550,47 @@
height="36.72575"
width="82.040657"
id="rect6648"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.86203903;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6650"
width="82.040657"
height="36.72575"
x="167.73116"
y="-445.45563"
transform="scale(1,-1)" /><text
transform="scale(1,-1)"
rx="4" /><text
transform="scale(1.0403984,0.96117025)"
sodipodi:linespacing="125%"
id="text6652"
y="448.55054"
x="175.87148"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-size:11.53426838px"
style="font-size:11.53426838px;fill:#333333"
y="448.55054"
x="175.87148"
x="178.87148"
id="tspan6654"
sodipodi:role="line">Services</tspan></text>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.88435173;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
id="rect6656"
width="86.393044"
height="36.704323"
x="306.86328"
y="-439.60837"
transform="scale(1,-1)" /><rect
transform="scale(1,-1)"
rx="4" /><rect
transform="scale(1,-1)"
y="-444.99475"
x="310.26624"
height="36.701977"
width="86.876686"
id="rect6658"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.88679528;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1" /><text
style="fill:#ffffff;fill-opacity:1;stroke:#6db33f;stroke-width:1.5;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1"
rx="4" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="305.30771"
y="448.55054"
id="text6660"
@@ -585,20 +598,20 @@
transform="scale(1.0403984,0.96117025)"><tspan
sodipodi:role="line"
id="tspan6662"
x="305.30771"
x="308.30771"
y="448.55054"
style="font-size:11.53426838px">Repositories</tspan></text>
style="font-size:11.53426838px;fill:#333333">Repositories</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.76895118px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="fill:none;fill-rule:evenodd;stroke:#333333;stroke-width:0.76895118px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 265.33234,295.60379 c 0,42.65169 0,42.65169 0,0 z"
id="path7643"
inkscape:connector-curvature="0" /><path
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.46028023;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
style="fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:#333333;stroke-width:3.46028023;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:3;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)"
d="m 270.43505,294.70585 c 0,39.4721 0,39.87903 0,39.87903"
id="path7645"
inkscape:connector-curvature="0" /><text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-style:normal;font-weight:normal;font-size:30.7580471px;line-height:125%;font-family:Helvetica, Arial, sans-serif;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="352.55331"
y="333.03622"
id="text4963"
@@ -607,6 +620,6 @@
sodipodi:role="line"
x="352.55331"
y="333.03622"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.53426838px;font-family:Helvetica, Arial, sans-serif;-inkscape-font-specification:sans-serif;text-align:center;text-anchor:middle;fill:#555555"
id="tspan4965">Delegates if no bean found</tspan></text>
</g></svg>

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

+18 -10
View File
@@ -32,6 +32,7 @@
**** xref:core/beans/java/bean-annotation.adoc[]
**** xref:core/beans/java/configuration-annotation.adoc[]
**** xref:core/beans/java/composing-configuration-classes.adoc[]
**** xref:core/beans/java/programmatic-bean-registration.adoc[]
*** xref:core/beans/environment.adoc[]
*** xref:core/beans/context-load-time-weaver.adoc[]
*** xref:core/beans/context-introduction.adoc[]
@@ -39,8 +40,8 @@
** xref:core/resources.adoc[]
** xref:core/validation.adoc[]
*** xref:core/validation/validator.adoc[]
*** xref:core/validation/beans-beans.adoc[]
*** xref:core/validation/conversion.adoc[]
*** xref:core/validation/data-binding.adoc[]
*** xref:core/validation/error-code-resolution.adoc[]
*** xref:core/validation/convert.adoc[]
*** xref:core/validation/format.adoc[]
*** xref:core/validation/format-configuring-formatting-globaldatetimeformat.adoc[]
@@ -99,9 +100,9 @@
*** xref:core/aop-api/autoproxy.adoc[]
*** xref:core/aop-api/targetsource.adoc[]
*** xref:core/aop-api/extensibility.adoc[]
** xref:core/resilience.adoc[]
** xref:core/null-safety.adoc[]
** xref:core/databuffer-codec.adoc[]
** xref:core/spring-jcl.adoc[]
** xref:core/aot.adoc[]
** xref:core/appendix.adoc[]
*** xref:core/appendix/xsd-schemas.adoc[]
@@ -161,7 +162,6 @@
**** xref:web/webmvc/mvc-servlet/exceptionhandlers.adoc[]
**** xref:web/webmvc/mvc-servlet/viewresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/localeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/themeresolver.adoc[]
**** xref:web/webmvc/mvc-servlet/multipart.adoc[]
**** xref:web/webmvc/mvc-servlet/logging.adoc[]
*** xref:web/webmvc/filters.adoc[]
@@ -197,7 +197,10 @@
*** xref:web/webmvc-functional.adoc[]
*** xref:web/webmvc/mvc-uri-building.adoc[]
*** xref:web/webmvc/mvc-ann-async.adoc[]
*** xref:web/webmvc/mvc-range.adoc[]
*** xref:web/webmvc/mvc-data-binding.adoc[]
*** xref:web/webmvc-cors.adoc[]
*** xref:web/webmvc-versioning.adoc[]
*** xref:web/webmvc/mvc-ann-rest-exceptions.adoc[]
*** xref:web/webmvc/mvc-security.adoc[]
*** xref:web/webmvc/mvc-caching.adoc[]
@@ -226,6 +229,7 @@
**** xref:web/webmvc/mvc-config/static-resources.adoc[]
**** xref:web/webmvc/mvc-config/default-servlet-handler.adoc[]
**** xref:web/webmvc/mvc-config/path-matching.adoc[]
**** xref:web/webmvc/mvc-config/api-version.adoc[]
**** xref:web/webmvc/mvc-config/advanced-java.adoc[]
**** xref:web/webmvc/mvc-config/advanced-xml.adoc[]
*** xref:web/webmvc/mvc-http2.adoc[]
@@ -258,7 +262,6 @@
**** xref:web/websocket/stomp/configuration-performance.adoc[]
**** xref:web/websocket/stomp/stats.adoc[]
**** xref:web/websocket/stomp/testing.adoc[]
** xref:web/integration.adoc[]
* xref:web-reactive.adoc[]
** xref:web/webflux.adoc[]
*** xref:web/webflux/new-framework.adoc[]
@@ -292,7 +295,10 @@
**** xref:web/webflux/controller/ann-advice.adoc[]
*** xref:web/webflux-functional.adoc[]
*** xref:web/webflux/uri-building.adoc[]
*** xref:web/webflux/range.adoc[]
*** xref:web/webflux/data-binding.adoc[]
*** xref:web/webflux-cors.adoc[]
*** xref:web/webflux-versioning.adoc[]
*** xref:web/webflux/ann-rest-exceptions.adoc[]
*** xref:web/webflux/security.adoc[]
*** xref:web/webflux/caching.adoc[]
@@ -309,7 +315,7 @@
*** xref:web/webflux-webclient/client-context.adoc[]
*** xref:web/webflux-webclient/client-synchronous.adoc[]
*** xref:web/webflux-webclient/client-testing.adoc[]
** xref:web/webflux-http-interface-client.adoc[]
** xref:web/webflux-http-service-client.adoc[]
** xref:web/webflux-websocket.adoc[]
** xref:web/webflux-test.adoc[]
** xref:rsocket.adoc[]
@@ -326,9 +332,10 @@
*** xref:testing/testcontext-framework/application-events.adoc[]
*** xref:testing/testcontext-framework/test-execution-events.adoc[]
*** xref:testing/testcontext-framework/ctx-management.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/xml.adoc[]
**** xref:testing/testcontext-framework/ctx-management/groovy.adoc[]
**** xref:testing/testcontext-framework/ctx-management/javaconfig.adoc[]
**** xref:testing/testcontext-framework/ctx-management/default-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/mixed-config.adoc[]
**** xref:testing/testcontext-framework/ctx-management/context-customizers.adoc[]
**** xref:testing/testcontext-framework/ctx-management/initializers.adoc[]
@@ -339,6 +346,7 @@
**** xref:testing/testcontext-framework/ctx-management/web.adoc[]
**** xref:testing/testcontext-framework/ctx-management/web-mocks.adoc[]
**** xref:testing/testcontext-framework/ctx-management/caching.adoc[]
**** xref:testing/testcontext-framework/ctx-management/context-pausing.adoc[]
**** xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[]
**** xref:testing/testcontext-framework/ctx-management/hierarchies.adoc[]
*** xref:testing/testcontext-framework/fixture-di.adoc[]
@@ -350,6 +358,7 @@
*** xref:testing/testcontext-framework/support-classes.adoc[]
*** xref:testing/testcontext-framework/aot.adoc[]
** xref:testing/webtestclient.adoc[]
** xref:testing/resttestclient.adoc[]
** xref:testing/mockmvc.adoc[]
*** xref:testing/mockmvc/overview.adoc[]
*** xref:testing/mockmvc/setup-options.adoc[]
@@ -433,8 +442,8 @@
*** xref:integration/cache/plug.adoc[]
*** xref:integration/cache/specific-config.adoc[]
** xref:integration/observability.adoc[]
** xref:integration/aot-cache.adoc[]
** xref:integration/checkpoint-restore.adoc[]
** xref:integration/cds.adoc[]
** xref:integration/appendix.adoc[]
* xref:languages.adoc[]
** xref:languages/kotlin.adoc[]
@@ -443,14 +452,13 @@
*** xref:languages/kotlin/null-safety.adoc[]
*** xref:languages/kotlin/classes-interfaces.adoc[]
*** xref:languages/kotlin/annotations.adoc[]
*** xref:languages/kotlin/bean-definition-dsl.adoc[]
*** xref:languages/kotlin/bean-registration-dsl.adoc[]
*** xref:languages/kotlin/web.adoc[]
*** xref:languages/kotlin/coroutines.adoc[]
*** xref:languages/kotlin/spring-projects-in.adoc[]
*** xref:languages/kotlin/getting-started.adoc[]
*** xref:languages/kotlin/resources.adoc[]
** xref:languages/groovy.adoc[]
** xref:languages/dynamic.adoc[]
* xref:appendix.adoc[]
* {spring-framework-docs-root}/{spring-version}/javadoc-api/[Java API,window=_blank, role=link-external]
* {spring-framework-api-kdoc}/[Kotlin API,window=_blank, role=link-external]
@@ -74,6 +74,11 @@ expressions used in XML bean definitions, `@Value`, etc.
| The mode to use when compiling expressions for the
xref:core/expressions/evaluation.adoc#expressions-compiler-configuration[Spring Expression Language].
| `spring.expression.maxOperations`
| The default maximum number of operations permitted during
xref:core/expressions/evaluation.adoc#expressions-parser-configuration[Spring Expression Language]
expression evaluation.
| `spring.getenv.ignore`
| Instructs Spring to ignore operating system environment variables if a Spring
`Environment` property -- for example, a placeholder in a configuration String -- isn't
@@ -81,6 +86,11 @@ resolvable otherwise. See
{spring-framework-api}++/core/env/AbstractEnvironment.html#IGNORE_GETENV_PROPERTY_NAME++[`AbstractEnvironment`]
for details.
| `spring.http.response.flush.enabled`
| Configures the Spring MVC `ServletServerHttpResponse` to allow flushing on the `OutputStream`
returned by `ServletServerHttpResponse#getBody()`. By default, such flush calls are ignored and
only `ServletServerHttpResponse#flush()` will actually flush the response to the network.
| `spring.jdbc.getParameterType.ignore`
| Instructs Spring to ignore `java.sql.ParameterMetaData.getParameterType` completely.
See the note in xref:data-access/jdbc/advanced.adoc#jdbc-batch-list[Batch Operations with a List of Objects].
@@ -124,11 +134,20 @@ on a test class. See xref:testing/annotations/integration-junit-jupiter.adoc#int
| The maximum size of the context cache in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/caching.adoc[Context Caching].
| `spring.test.context.cache.pause`
| The pause mode for the context cache in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/context-pausing.adoc[Context Pausing].
| `spring.test.context.failure.threshold`
| The failure threshold for errors encountered while attempting to load an `ApplicationContext`
in the _Spring TestContext Framework_. See
xref:testing/testcontext-framework/ctx-management/failure-threshold.adoc[Context Failure Threshold].
| `spring.test.extension.context.scope`
| The default _extension context scope_ used by the `SpringExtension` in `@Nested` test
class hierarchies. See
xref:testing/annotations/integration-junit-jupiter.adoc#integration-testing-annotations-springextensionconfig[`@SpringExtensionConfig`].
| `spring.test.enclosing.configuration`
| The default _enclosing configuration inheritance mode_ to use if
`@NestedTestConfiguration` is not present on a test class. See
@@ -87,14 +87,12 @@ A crucial difference between Spring pooling and SLSB pooling is that Spring pool
be applied to any POJO. As with Spring in general, this service can be applied in a
non-invasive way.
Spring provides support for Commons Pool 2.2, which provides a
Spring provides support for Commons Pool 2, which provides a
fairly efficient pooling implementation. You need the `commons-pool` Jar on your
application's classpath to use this feature. You can also subclass
`org.springframework.aop.target.AbstractPoolingTargetSource` to support any other
pooling API.
NOTE: Commons Pool 1.5+ is also supported but is deprecated as of Spring Framework 4.2.
The following listing shows an example configuration:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -727,7 +727,7 @@ of determining parameter names, an exception will be thrown.
parameter names. This discoverer is only used if such APIs are present on the classpath.
`StandardReflectionParameterNameDiscoverer` :: Uses the standard `java.lang.reflect.Parameter`
API to determine parameter names. Requires that code be compiled with the `-parameters`
flag for `javac`. Recommended approach on Java 8+.
flag for `javac`. Recommended approach.
`AspectJAdviceParameterNameDiscoverer` :: Deduces parameter names from the pointcut
expression, `returning`, and `throwing` clauses. See the
{spring-framework-api}/aop/aspectj/AspectJAdviceParameterNameDiscoverer.html[javadoc]
@@ -104,7 +104,7 @@ Note that pointcut definitions are generally matched against any intercepted met
If a pointcut is strictly meant to be public-only, even in a CGLIB proxy scenario with
potential non-public interactions through proxies, it needs to be defined accordingly.
If your interception needs include method calls or even constructors within the target
If your interception needs to include method calls or even constructors within the target
class, consider the use of Spring-driven xref:core/aop/using-aspectj.adoc#aop-aj-ltw[native AspectJ weaving] instead
of Spring's proxy-based AOP framework. This constitutes a different mode of AOP usage
with different characteristics, so be sure to make yourself familiar with weaving
@@ -28,6 +28,10 @@ you can do so. However, you should consider the following issues:
deploying on the module path. Such cases require a JVM bootstrap flag
`--add-opens=java.base/java.lang=ALL-UNNAMED` which is not available for modules.
[[aop-forcing-proxy-types]]
== Forcing Specific AOP Proxy Types
To force the use of CGLIB proxies, set the value of the `proxy-target-class` attribute
of the `<aop:config>` element to true, as follows:
@@ -60,6 +64,24 @@ To be clear, using `proxy-target-class="true"` on `<tx:annotation-driven/>`,
proxies _for all three of them_.
====
`@EnableAspectJAutoProxy`, `@EnableTransactionManagement` and related configuration
annotations offer a corresponding `proxyTargetClass` attribute. These are collapsed
into a single unified auto-proxy creator too, effectively applying the _strongest_
proxy settings at runtime. As of 7.0, this applies to individual proxy processors
as well, for example `@EnableAsync`, consistently participating in unified global
default settings for all auto-proxying attempts in a given application.
The global default proxy type may differ between setups. While the core framework
suggests interface-based proxies by default, Spring Boot may - depending on
configuration properties - enable class-based proxies by default.
As of 7.0, forcing a specific proxy type for individual beans is possible through
the `@Proxyable` annotation on a given `@Bean` method or `@Component` class, with
`@Proxyable(INTERFACES)` or `@Proxyable(TARGET_CLASS)` overriding any globally
configured default. For very specific purposes, you may even specify the proxy
interface(s) to use through `@Proxyable(interfaces=...)`, limiting the exposure
to selected interfaces rather than all interfaces that the target bean implements.
[[aop-understanding-aop-proxies]]
== Understanding AOP Proxies
@@ -378,7 +378,7 @@ The container also supports creating a bean with {spring-framework-api}++/beans/
. The custom arguments require dynamic introspection of a matching constructor or factory method.
Those arguments cannot be detected by AOT, so the necessary reflection hints will have to be provided manually.
. By-passing the instance supplier means that all other optimizations after creation are skipped as well.
. Bypassing the instance supplier means that all other optimizations after creation are skipped as well.
For instance, autowiring on fields and methods will be skipped as they are handled in the instance supplier.
Rather than having prototype-scoped beans created with custom arguments, we recommend a manual factory pattern where a bean is responsible for the creation of the instance.
@@ -19,10 +19,6 @@ its behavior changes.
| Initialization of `SmartInitializingSingleton` beans.
| `beanName` the name of the bean.
| `spring.context.annotated-bean-reader.create`
| Creation of the `AnnotatedBeanDefinitionReader`.
|
| `spring.context.base-packages.scan`
| Scanning of base packages.
| `packages` array of base packages for scanning.
@@ -151,17 +151,17 @@ injected into a `Set<MovieCatalog>` annotated with `@Qualifier("action")`.
[TIP]
====
Letting qualifier values select against target bean names, within the type-matching
candidates, does not require a `@Qualifier` annotation at the injection point.
If there is no other resolution indicator (such as a qualifier or a primary marker),
for a non-unique dependency situation, Spring matches the injection point name
(that is, the field name or parameter name) against the target bean names and chooses
the same-named candidate, if any (either by bean name or by associated alias).
candidates, does not require a `@Qualifier` annotation at the injection point. If there
is no other resolution indicator (such as a qualifier, a primary marker, or a fallback
marker), for a non-unique dependency situation, Spring matches the injection point name
(that is, the field name or parameter name) against the target bean names and chooses the
same-named candidate, if any (either by bean name or by associated alias).
Since version 6.1, this requires the `-parameters` Java compiler flag to be present.
As of 6.2, the container applies fast shortcut resolution for bean name matches,
bypassing the full type matching algorithm when the parameter name matches the
bean name and no type, qualifier or primary conditions override the match. It is
therefore recommendable for your parameter names to match the target bean names.
Since version 6.1, this requires the `-parameters` Java compiler flag to be present. As
of 6.2, the container applies fast shortcut resolution for bean name matches, bypassing
the full type matching algorithm when the parameter name matches the bean name and no
type, qualifier, primary, or fallback conditions override the match. It is therefore
recommendable for your parameter names to match the target bean names.
====
As an alternative for injection by name, consider the JSR-250 `@Resource` annotation
@@ -274,7 +274,7 @@ Kotlin::
Next, you can provide the information for the candidate bean definitions. You can add
`<qualifier/>` tags as sub-elements of the `<bean/>` tag and then specify the `type` and
`value` to match your custom qualifier annotations. The type is matched against the
fully-qualified class name of the annotation. Alternately, as a convenience if no risk of
fully-qualified class name of the annotation. Alternatively, as a convenience if no risk of
conflicting names exists, you can use the short class name. The following example
demonstrates both approaches:
@@ -37,18 +37,18 @@ Kotlin::
----
======
[NOTE]
[TIP]
====
As of Spring Framework 4.3, an `@Autowired` annotation on such a constructor is no longer
necessary if the target bean defines only one constructor to begin with. However, if
several constructors are available and there is no primary/default constructor, at least
one of the constructors must be annotated with `@Autowired` in order to instruct the
container which one to use. See the discussion on
xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-constructor-resolution[constructor resolution] for details.
An `@Autowired` annotation on such a constructor is not necessary if the target bean
defines only one constructor. However, if several constructors are available and there is
no primary or default constructor, at least one of the constructors must be annotated
with `@Autowired` in order to instruct the container which one to use. See the discussion
on xref:core/beans/annotation-config/autowired.adoc#beans-autowired-annotation-constructor-resolution[constructor resolution]
for details.
====
You can also apply the `@Autowired` annotation to _traditional_ setter methods,
as the following example shows:
You can apply the `@Autowired` annotation to _traditional_ setter methods, as the
following example shows:
[tabs]
======
@@ -84,8 +84,8 @@ Kotlin::
----
======
You can also apply the annotation to methods with arbitrary names and multiple
arguments, as the following example shows:
You can apply `@Autowired` to methods with arbitrary names and multiple arguments, as the
following example shows:
[tabs]
======
@@ -176,14 +176,15 @@ Kotlin::
====
Make sure that your target components (for example, `MovieCatalog` or `CustomerPreferenceDao`)
are consistently declared by the type that you use for your `@Autowired`-annotated
injection points. Otherwise, injection may fail due to a "no type match found" error at runtime.
injection points. Otherwise, injection may fail due to a "no type match found" error at
runtime.
For XML-defined beans or component classes found via classpath scanning, the container
usually knows the concrete type up front. However, for `@Bean` factory methods, you need
to make sure that the declared return type is sufficiently expressive. For components
that implement several interfaces or for components potentially referred to by their
implementation type, consider declaring the most specific return type on your factory
method (at least as specific as required by the injection points referring to your bean).
implementation type, declare the most specific return type on your factory method (at
least as specific as required by the injection points referring to your bean).
====
.[[beans-autowired-annotation-self-injection]]Self Injection
@@ -308,12 +309,13 @@ set of multiple matches for the specific bean type (as returned by the factory m
Note that the standard `jakarta.annotation.Priority` annotation is not available at the
`@Bean` level, since it cannot be declared on methods. Its semantics can be modeled
through `@Order` values in combination with `@Primary` on a single bean for each type.
through `@Order` values in combination with `@Primary` or `@Fallback` on a single bean
for each type.
====
Even typed `Map` instances can be autowired as long as the expected key type is `String`.
The map values contain all beans of the expected type, and the keys contain the
corresponding bean names, as the following example shows:
The map values are all beans of the expected type, and the keys are the corresponding
bean names, as the following example shows:
[tabs]
======
@@ -431,7 +433,7 @@ annotated constructor does not have to be public.
====
Alternatively, you can express the non-required nature of a particular dependency
through Java 8's `java.util.Optional`, as the following example shows:
through Java's `java.util.Optional`, as the following example shows:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -445,8 +447,8 @@ through Java 8's `java.util.Optional`, as the following example shows:
----
You can also use a parameter-level `@Nullable` annotation (of any kind in any package --
for example, `javax.annotation.Nullable` from JSR-305) or just leverage Kotlin built-in
null-safety support:
for example, `org.jspecify.annotations.Nullable` from JSpecify) or just leverage Kotlin's
built-in null-safety support:
[tabs]
======
@@ -477,13 +479,6 @@ Kotlin::
----
======
[NOTE]
====
A type-level `@Nullable` annotation such as from JSpecify is not supported in Spring
Framework 6.2 yet. You need to upgrade to Spring Framework 7.0 where the framework
detects type-level annotations and consistently declares JSpecify in its own codebase.
====
You can also use `@Autowired` for interfaces that are well-known resolvable
dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`,
`ApplicationEventPublisher`, and `MessageSource`. These interfaces and their extended
@@ -528,5 +523,6 @@ class MovieRecommender {
The `@Autowired`, `@Inject`, `@Value`, and `@Resource` annotations are handled by Spring
`BeanPostProcessor` implementations. This means that you cannot apply these annotations
within your own `BeanPostProcessor` or `BeanFactoryPostProcessor` types (if any).
These types must be 'wired up' explicitly by using XML or a Spring `@Bean` method.
====
@@ -27,4 +27,5 @@ with the `CustomAutowireConfigurer`
When multiple beans qualify as autowire candidates, the determination of a "`primary`" is
as follows: If exactly one bean definition among the candidates has a `primary`
attribute set to `true`, it is selected.
attribute set to `true`, it is selected. For annotation-based configuration, see
xref:core/beans/annotation-config/autowired-primary.adoc[Fine-tuning with `@Primary` or `@Fallback`].
@@ -202,18 +202,17 @@ another file or files. The following example shows how to do so:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
----
In the preceding example, external bean definitions are loaded from three files:
`services.xml`, `messageSource.xml`, and `themeSource.xml`. All location paths are
In the preceding example, external bean definitions are loaded from the files
`services.xml` and `messageSource.xml`. All location paths are
relative to the definition file doing the importing, so `services.xml` must be in the
same directory or classpath location as the file doing the importing, while
`messageSource.xml` and `themeSource.xml` must be in a `resources` location below the
`messageSource.xml` must be in a `resources` location below the
location of the importing file. As you can see, a leading slash is ignored. However, given
that these paths are relative, it is better form not to use the slash at all. The
contents of the files being imported, including the top level `<beans/>` element, must
@@ -240,40 +239,6 @@ The namespace itself provides the import directive feature. Further
configuration features beyond plain bean definitions are available in a selection
of XML namespaces provided by Spring -- for example, the `context` and `util` namespaces.
[[beans-factory-groovy]]
=== The Groovy Bean Definition DSL
As a further example for externalized configuration metadata, bean definitions can also
be expressed in Spring's Groovy Bean Definition DSL, as known from the Grails framework.
Typically, such configuration live in a ".groovy" file with the structure shown in the
following example:
[source,groovy,indent=0,subs="verbatim,quotes"]
----
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
----
This configuration style is largely equivalent to XML bean definitions and even
supports Spring's XML configuration namespaces. It also allows for importing XML
bean definition files through an `importBeans` directive.
[[beans-factory-client]]
== Using the Container
@@ -9,7 +9,7 @@ annotations. Even in those examples, however, the "base" bean definitions are ex
defined in the XML file, while the annotations drive only the dependency injection.
This section describes an option for implicitly detecting the candidate components by
scanning the classpath. Candidate components are classes that match against a filter
scanning the classpath. Candidate components are classes that match against filter
criteria and have a corresponding bean definition registered with the container.
This removes the need to use XML to perform bean registration. Instead, you can use
annotations (for example, `@Component`), AspectJ type expressions, or your own
@@ -70,7 +70,7 @@ Java::
// ...
}
----
<1> The `@Component` causes `@Service` to be treated in the same way as `@Component`.
<1> The `@Component` meta-annotation causes `@Service` to be treated in the same way as `@Component`.
Kotlin::
+
@@ -85,7 +85,7 @@ Kotlin::
// ...
}
----
<1> The `@Component` causes `@Service` to be treated in the same way as `@Component`.
<1> The `@Component` meta-annotation causes `@Service` to be treated in the same way as `@Component`.
======
You can also combine meta-annotations to create "`composed annotations`". For example,
@@ -97,7 +97,7 @@ meta-annotations to allow customization. This can be particularly useful when yo
want to only expose a subset of the meta-annotation's attributes. For example, Spring's
`@SessionScope` annotation hard codes the scope name to `session` but still allows
customization of the `proxyMode`. The following listing shows the definition of the
`SessionScope` annotation:
`@SessionScope` annotation:
[tabs]
======
@@ -211,7 +211,7 @@ Java::
@Service
public class SimpleMovieLister {
private MovieFinder movieFinder;
private final MovieFinder movieFinder;
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
@@ -251,11 +251,11 @@ Kotlin::
----
======
To autodetect these classes and register the corresponding beans, you need to add
`@ComponentScan` to your `@Configuration` class, where the `basePackages` attribute
is a common parent package for the two classes. (Alternatively, you can specify a
comma- or semicolon- or space-separated list that includes the parent package of each class.)
`@ComponentScan` to your `@Configuration` class, where the `basePackages` attribute is
configured with a common parent package for the two classes. Alternatively, you can
specify a comma-, semicolon-, or space-separated list that includes the parent package
of each class.
[tabs]
======
@@ -282,10 +282,10 @@ Kotlin::
----
======
NOTE: For brevity, the preceding example could have used the `value` attribute of the
annotation (that is, `@ComponentScan("org.example")`).
TIP: For brevity, the preceding example could have used the implicit `value` attribute of
the annotation instead: `@ComponentScan("org.example")`
The following alternative uses XML:
The following example uses XML configuration:
[source,xml,indent=0,subs="verbatim,quotes"]
----
@@ -325,16 +325,68 @@ sure that they are 'opened' (that is, that they use an `opens` declaration inste
Furthermore, the `AutowiredAnnotationBeanPostProcessor` and
`CommonAnnotationBeanPostProcessor` are both implicitly included when you use the
component-scan element. That means that the two components are autodetected and
wired together -- all without any bean configuration metadata provided in XML.
`<context:component-scan>` element. That means that the two components are autodetected
and wired together -- all without any bean configuration metadata provided in XML.
NOTE: You can disable the registration of `AutowiredAnnotationBeanPostProcessor` and
`CommonAnnotationBeanPostProcessor` by including the `annotation-config` attribute
with a value of `false`.
[[beans-scanning-placeholders-and-patterns]]
=== Property Placeholders and Ant-style Patterns
The `basePackages` and `value` attributes in `@ComponentScan` support `${...}` property
placeholders which are resolved against the `Environment` as well as Ant-style package
patterns such as `"org.example.+++**+++"`.
In addition, multiple packages or patterns may be specified, either separately or within
a single String — for example, `{"org.example.config", "org.example.service.+++**+++"}`
or `"org.example.config, org.example.service.+++**+++"`.
The following example specifies the `app.scan.packages` property placeholder for the
implicit `value` attribute in `@ComponentScan`.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan("${app.scan.packages}") // <1>
public class AppConfig {
// ...
}
----
<1> `app.scan.packages` property placeholder to be resolved against the `Environment`
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(["\${app.scan.packages}"]) // <1>
class AppConfig {
// ...
}
----
<1> `app.scan.packages` property placeholder to be resolved against the `Environment`
======
The following listing represents a properties file which defines the `app.scan.packages`
property. In the preceding example, it is assumed that this properties file has been
registered with the `Environment` for example, via `@PropertySource` or a similar
mechanism.
[source,properties,indent=0,subs="verbatim,quotes"]
----
app.scan.packages=org.example.config, org.example.service.**
----
[[beans-scanning-filters]]
== Using Filters to Customize Scanning
=== Using Filters to Customize Scanning
By default, classes annotated with `@Component`, `@Repository`, `@Service`, `@Controller`,
`@Configuration`, or a custom annotation that itself is annotated with `@Component` are
@@ -371,8 +423,8 @@ The following table describes the filtering options:
| A custom implementation of the `org.springframework.core.type.TypeFilter` interface.
|===
The following example shows the configuration ignoring all `@Repository` annotations
and using "`stub`" repositories instead:
The following example shows `@ComponentScan` configuration that excludes all
`@Repository` annotations and includes "`Stub`" repositories instead:
[tabs]
======
@@ -424,6 +476,367 @@ annotated or meta-annotated with `@Component`, `@Repository`, `@Service`, `@Cont
`@RestController`, or `@Configuration`.
[[beans-scanning-name-generator]]
=== Naming Autodetected Components
When a component is autodetected as part of the scanning process, its bean name is
generated by the `BeanNameGenerator` strategy known to that scanner.
By default, the `AnnotationBeanNameGenerator` is used. For Spring
xref:core/beans/classpath-scanning.adoc#beans-stereotype-annotations[stereotype annotations],
if you supply a name via the annotation's `value` attribute that name will be used as
the name in the corresponding bean definition. This convention also applies when the
`@jakarta.inject.Named` annotation is used instead of Spring stereotype annotations.
As of Spring Framework 6.1, the name of the annotation attribute that is used to specify
the bean name is no longer required to be `value`. Custom stereotype annotations can
declare an attribute with a different name (such as `name`) and annotate that attribute
with `@AliasFor(annotation = Component.class, attribute = "value")`. See the source code
declaration of `ControllerAdvice#name()` for a concrete example.
[WARNING]
====
As of Spring Framework 6.1, support for convention-based stereotype names is deprecated
and will be removed in a future version of the framework. Consequently, custom stereotype
annotations must use `@AliasFor` to declare an explicit alias for the `value` attribute
in `@Component`. See the source code declaration of `Repository#value()` and
`ControllerAdvice#name()` for concrete examples.
====
If an explicit bean name cannot be derived from such an annotation or for any other
detected component (such as those discovered by custom filters), the default bean name
generator returns the uncapitalized non-qualified class name. For example, if the
following component classes were detected, the names would be `myMovieLister` and
`movieFinderImpl`.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Service("myMovieLister")
class SimpleMovieLister {
// ...
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
----
======
If you do not want to rely on the default bean-naming strategy, you can provide a custom
bean-naming strategy. First, implement either the
{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`] or
{spring-framework-api}/context/annotation/ConfigurationBeanNameGenerator.html[`ConfigurationBeanNameGenerator`]
interface, and be sure to include a default no-arg constructor. Then, provide the fully
qualified class name when configuring the scanner, as the following examples show.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
class AppConfig {
// ...
}
----
======
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
----
[TIP]
====
If you run into naming conflicts due to multiple autodetected components having the same
non-qualified class name (for example, classes with identical names but residing in
different packages), you can configure a `BeanNameGenerator` that defaults to the
fully-qualified class name for the generated bean name. The
`FullyQualifiedAnnotationBeanNameGenerator` can be used for such purposes.
As of Spring Framework 7.0, if you encounter naming conflicts among `@Bean` methods in
`@Configuration` classes, you can alternatively configure a
`ConfigurationBeanNameGenerator` that generates unique bean names for `@Bean` methods.
The `FullyQualifiedConfigurationBeanNameGenerator` can be used to generate
fully-qualified default bean names for `@Bean` methods without an explicit `name`
attribute — for example, `com.example.MyConfig.myBean` for an `@Bean` method named
`myBean()` declared in `@Configuration` class `com.example.MyConfig`.
The `FullyQualifiedAnnotationBeanNameGenerator` and
`FullyQualifiedConfigurationBeanNameGenerator` both reside in the
`org.springframework.context.annotation` package.
====
As a general rule, consider specifying the name with the annotation whenever other
components may be making explicit references to it. On the other hand, the
auto-generated names are adequate whenever the container is responsible for wiring.
[[beans-scanning-scope-resolver]]
=== Providing a Scope for Autodetected Components
As with Spring-managed components in general, the default and most common scope for
autodetected components is `singleton`. However, sometimes you need a different scope
that can be specified by the `@Scope` annotation. You can provide the name of the
scope within the annotation, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Scope("prototype")
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
----
======
NOTE: `@Scope` annotations are only introspected on the concrete bean class (for annotated
components) or the factory method (for `@Bean` methods). In contrast to XML bean
definitions, there is no notion of bean definition inheritance, and inheritance
hierarchies at the class level are irrelevant for metadata purposes.
For details on web-specific scopes such as "`request`" or "`session`" in a Spring context,
see xref:core/beans/factory-scopes.adoc#beans-factory-scopes-other[Request, Session, Application, and WebSocket Scopes].
As with the pre-built annotations for those scopes, you may also compose your own scoping
annotations by using Spring's meta-annotation approach: for example, a custom annotation
meta-annotated with `@Scope("prototype")`, possibly also declaring a custom scoped-proxy mode.
NOTE: To provide a custom strategy for scope resolution rather than relying on the
annotation-based approach, you can implement the
{spring-framework-api}/context/annotation/ScopeMetadataResolver.html[`ScopeMetadataResolver`]
interface. Be sure to include a default no-arg constructor. Then you can provide the
fully qualified class name when configuring the scanner, as the following example of both
an annotation and a bean definition shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
class AppConfig {
// ...
}
----
======
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
----
When using certain non-singleton scopes, it may be necessary to generate proxies for the
scoped objects. The reasoning is described in
xref:core/beans/factory-scopes.adoc#beans-factory-scopes-other-injection[Scoped Beans as Dependencies].
For this purpose, a scoped-proxy attribute is available on the component-scan
element. The three possible values are: `no`, `interfaces`, and `targetClass`. For example,
the following configuration results in standard JDK dynamic proxies:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
class AppConfig {
// ...
}
----
======
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
----
[[beans-scanning-qualifiers]]
=== Providing Qualifier Metadata with Annotations
The `@Qualifier` annotation is discussed in
xref:core/beans/annotation-config/autowired-qualifiers.adoc[Fine-tuning Annotation-based Autowiring with Qualifiers].
The examples in that section demonstrate the use of the `@Qualifier` annotation and
custom qualifier annotations to provide fine-grained control when you resolve autowire
candidates. Because those examples were based on XML bean definitions, the qualifier
metadata was provided on the candidate bean definitions by using the `qualifier` or `meta`
child elements of the `bean` element in the XML. When relying upon classpath scanning for
auto-detection of components, you can provide the qualifier metadata with type-level
annotations on the candidate class. The following three examples demonstrate this
technique:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Qualifier("Action")
class ActionMovieCatalog : MovieCatalog
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Genre("Action")
class ActionMovieCatalog : MovieCatalog {
// ...
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Offline
class CachingMovieCatalog : MovieCatalog {
// ...
}
----
======
NOTE: As with most annotation-based alternatives, keep in mind that the annotation metadata is
bound to the class definition itself, while the use of XML allows for multiple beans
of the same type to provide variations in their qualifier metadata, because that
metadata is provided per-instance rather than per-class.
[[beans-factorybeans-annotations]]
== Defining Bean Metadata within Components
@@ -646,10 +1059,10 @@ methods anywhere. However, regular `@Bean` methods in `@Configuration` classes n
to be overridable -- that is, they must not be declared as `private` or `final`.
`@Bean` methods are also discovered on base classes of a given component or
configuration class, as well as on Java 8 default methods declared in interfaces
configuration class, as well as on Java default methods declared in interfaces
implemented by the component or configuration class. This allows for a lot of
flexibility in composing complex configuration arrangements, with even multiple
inheritance being possible through Java 8 default methods as of Spring 4.2.
inheritance being possible through Java default methods.
Finally, a single class may hold multiple `@Bean` methods for the same
bean, as an arrangement of multiple factory methods to use depending on available
@@ -658,352 +1071,3 @@ constructor or factory method in other configuration scenarios: The variant with
the largest number of satisfiable dependencies is picked at construction time,
analogous to how the container selects between multiple `@Autowired` constructors.
====
[[beans-scanning-name-generator]]
== Naming Autodetected Components
When a component is autodetected as part of the scanning process, its bean name is
generated by the `BeanNameGenerator` strategy known to that scanner.
By default, the `AnnotationBeanNameGenerator` is used. For Spring
xref:core/beans/classpath-scanning.adoc#beans-stereotype-annotations[stereotype annotations],
if you supply a name via the annotation's `value` attribute that name will be used as
the name in the corresponding bean definition. This convention also applies when the
following JSR-250 and JSR-330 annotations are used instead of Spring stereotype
annotations: `@jakarta.annotation.ManagedBean`, `@javax.annotation.ManagedBean`,
`@jakarta.inject.Named`, and `@javax.inject.Named`.
As of Spring Framework 6.1, the name of the annotation attribute that is used to specify
the bean name is no longer required to be `value`. Custom stereotype annotations can
declare an attribute with a different name (such as `name`) and annotate that attribute
with `@AliasFor(annotation = Component.class, attribute = "value")`. See the source code
declaration of `ControllerAdvice#name()` for a concrete example.
[WARNING]
====
As of Spring Framework 6.1, support for convention-based stereotype names is deprecated
and will be removed in a future version of the framework. Consequently, custom stereotype
annotations must use `@AliasFor` to declare an explicit alias for the `value` attribute
in `@Component`. See the source code declaration of `Repository#value()` and
`ControllerAdvice#name()` for concrete examples.
====
If an explicit bean name cannot be derived from such an annotation or for any other
detected component (such as those discovered by custom filters), the default bean name
generator returns the uncapitalized non-qualified class name. For example, if the
following component classes were detected, the names would be `myMovieLister` and
`movieFinderImpl`.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Service("myMovieLister")
public class SimpleMovieLister {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Service("myMovieLister")
class SimpleMovieLister {
// ...
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
----
======
If you do not want to rely on the default bean-naming strategy, you can provide a custom
bean-naming strategy. First, implement the
{spring-framework-api}/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`]
interface, and be sure to include a default no-arg constructor. Then, provide the fully
qualified class name when configuring the scanner, as the following example annotation
and bean definition show.
TIP: If you run into naming conflicts due to multiple autodetected components having the
same non-qualified class name (i.e., classes with identical names but residing in
different packages), you may need to configure a `BeanNameGenerator` that defaults to the
fully qualified class name for the generated bean name. The
`FullyQualifiedAnnotationBeanNameGenerator` located in package
`org.springframework.context.annotation` can be used for such purposes.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], nameGenerator = MyNameGenerator::class)
class AppConfig {
// ...
}
----
======
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
----
As a general rule, consider specifying the name with the annotation whenever other
components may be making explicit references to it. On the other hand, the
auto-generated names are adequate whenever the container is responsible for wiring.
[[beans-scanning-scope-resolver]]
== Providing a Scope for Autodetected Components
As with Spring-managed components in general, the default and most common scope for
autodetected components is `singleton`. However, sometimes you need a different scope
that can be specified by the `@Scope` annotation. You can provide the name of the
scope within the annotation, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Scope("prototype")
@Repository
class MovieFinderImpl : MovieFinder {
// ...
}
----
======
NOTE: `@Scope` annotations are only introspected on the concrete bean class (for annotated
components) or the factory method (for `@Bean` methods). In contrast to XML bean
definitions, there is no notion of bean definition inheritance, and inheritance
hierarchies at the class level are irrelevant for metadata purposes.
For details on web-specific scopes such as "`request`" or "`session`" in a Spring context,
see xref:core/beans/factory-scopes.adoc#beans-factory-scopes-other[Request, Session, Application, and WebSocket Scopes].
As with the pre-built annotations for those scopes, you may also compose your own scoping
annotations by using Spring's meta-annotation approach: for example, a custom annotation
meta-annotated with `@Scope("prototype")`, possibly also declaring a custom scoped-proxy mode.
NOTE: To provide a custom strategy for scope resolution rather than relying on the
annotation-based approach, you can implement the
{spring-framework-api}/context/annotation/ScopeMetadataResolver.html[`ScopeMetadataResolver`]
interface. Be sure to include a default no-arg constructor. Then you can provide the
fully qualified class name when configuring the scanner, as the following example of both
an annotation and a bean definition shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], scopeResolver = MyScopeResolver::class)
class AppConfig {
// ...
}
----
======
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<context:component-scan base-package="org.example" scope-resolver="org.example.MyScopeResolver"/>
</beans>
----
When using certain non-singleton scopes, it may be necessary to generate proxies for the
scoped objects. The reasoning is described in
xref:core/beans/factory-scopes.adoc#beans-factory-scopes-other-injection[Scoped Beans as Dependencies].
For this purpose, a scoped-proxy attribute is available on the component-scan
element. The three possible values are: `no`, `interfaces`, and `targetClass`. For example,
the following configuration results in standard JDK dynamic proxies:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"], scopedProxy = ScopedProxyMode.INTERFACES)
class AppConfig {
// ...
}
----
======
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<context:component-scan base-package="org.example" scoped-proxy="interfaces"/>
</beans>
----
[[beans-scanning-qualifiers]]
== Providing Qualifier Metadata with Annotations
The `@Qualifier` annotation is discussed in
xref:core/beans/annotation-config/autowired-qualifiers.adoc[Fine-tuning Annotation-based Autowiring with Qualifiers].
The examples in that section demonstrate the use of the `@Qualifier` annotation and
custom qualifier annotations to provide fine-grained control when you resolve autowire
candidates. Because those examples were based on XML bean definitions, the qualifier
metadata was provided on the candidate bean definitions by using the `qualifier` or `meta`
child elements of the `bean` element in the XML. When relying upon classpath scanning for
auto-detection of components, you can provide the qualifier metadata with type-level
annotations on the candidate class. The following three examples demonstrate this
technique:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Qualifier("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Qualifier("Action")
class ActionMovieCatalog : MovieCatalog
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Genre("Action")
public class ActionMovieCatalog implements MovieCatalog {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Genre("Action")
class ActionMovieCatalog : MovieCatalog {
// ...
}
----
======
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
@Offline
public class CachingMovieCatalog implements MovieCatalog {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
@Component
@Offline
class CachingMovieCatalog : MovieCatalog {
// ...
}
----
======
NOTE: As with most annotation-based alternatives, keep in mind that the annotation metadata is
bound to the class definition itself, while the use of XML allows for multiple beans
of the same type to provide variations in their qualifier metadata, because that
metadata is provided per-instance rather than per-class.
@@ -575,7 +575,7 @@ Kotlin::
----
======
NOTE: Do not define such beans to be lazy as the `ApplicationContext` will honour that and will not register the method to listen to events.
NOTE: Do not define such beans to be lazy as the `ApplicationContext` will honor that and will not register the method to listen to events.
The method signature once again declares the event type to which it listens,
but, this time, with a flexible name and without implementing a specific listener interface.
@@ -933,13 +933,12 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
// create a startup step and start recording
StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan");
// add tagging information to the current step
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
// perform the actual phase we're instrumenting
this.scanner.scan(basePackages);
// end the current step
scanPackages.end();
try (StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")) {
// add tagging information to the current step
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
// perform the actual phase we're instrumenting
this.scanner.scan(basePackages);
}
----
Kotlin::
@@ -947,13 +946,12 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
// create a startup step and start recording
val scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")
// add tagging information to the current step
scanPackages.tag("packages", () -> Arrays.toString(basePackages))
// perform the actual phase we're instrumenting
this.scanner.scan(basePackages)
// end the current step
scanPackages.end()
try (val scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")) {
// add tagging information to the current step
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
// perform the actual phase we're instrumenting
this.scanner.scan(basePackages);
}
----
======
@@ -99,7 +99,7 @@ the `@Bean` factory method in favor of any pre-declared constructor on the bean
****
NOTE: We acknowledge that overriding beans in test scenarios is convenient, and there is
explicit support for this as of Spring Framework 6.2. Please refer to
explicit support for this. Please refer to
xref:testing/testcontext-framework/bean-overriding.adoc[this section] for more details.
@@ -50,9 +50,8 @@ XML configuration:
The preceding XML is more succinct. However, typos are discovered at runtime rather than
design time, unless you use an IDE (such as https://www.jetbrains.com/idea/[IntelliJ
IDEA] or the {spring-site-tools}[Spring Tools for Eclipse])
that supports automatic property completion when you create bean definitions. Such IDE
assistance is highly recommended.
IDEA] or the {spring-site-tools}[Spring Tools]) that supports automatic property
completion when you create bean definitions. Such IDE assistance is highly recommended.
You can also configure a `java.util.Properties` instance, as follows:
@@ -67,6 +67,13 @@ interface, clearly indicating the post-processor nature of that bean. Otherwise,
Since a `BeanPostProcessor` needs to be instantiated early in order to apply to the
initialization of other beans in the context, this early type detection is critical.
Furthermore, when registering a `BeanPostProcessor` via an `@Bean` factory method,
declare the method as `static` and ideally with no dependencies. Doing so avoids eager
initialization of the configuration class and other beans, which would make them
ineligible for full post-processing (such as auto-proxying). See the
"BeanPostProcessor-returning `@Bean` methods" section in the
{spring-framework-api}/context/annotation/Bean.html[`@Bean`] javadoc for details.
[[beans-factory-programmatically-registering-beanpostprocessors]]
.Programmatically registering `BeanPostProcessor` instances
NOTE: While the recommended approach for `BeanPostProcessor` registration is through
@@ -80,7 +87,7 @@ of execution. Note also that `BeanPostProcessor` instances registered programmat
are always processed before those registered through auto-detection, regardless of any
explicit ordering.
.`BeanPostProcessor` instances and AOP auto-proxying
.`BeanPostProcessor` instances and early initialization
[NOTE]
====
Classes that implement the `BeanPostProcessor` interface are special and are treated
@@ -90,17 +97,23 @@ of the `ApplicationContext`. Next, all `BeanPostProcessor` instances are registe
in a sorted fashion and applied to all further beans in the container. Because AOP
auto-proxying is implemented as a `BeanPostProcessor` itself, neither `BeanPostProcessor`
instances nor the beans they directly reference are eligible for auto-proxying and,
thus, do not have aspects woven into them.
thus, do not have aspects woven into them. More generally, any bean that is instantiated
during this early phase is not eligible for full post-processing by all
`BeanPostProcessor` instances.
For any such bean, you should see an informational log message: `Bean someBean is not
eligible for getting processed by all BeanPostProcessor interfaces (for example: not
eligible for auto-proxying)`.
For any such bean, you should see a WARN-level log message similar to the following.
If you have beans wired into your `BeanPostProcessor` by using autowiring or
`@Resource` (which may fall back to autowiring), Spring might access unexpected beans
when searching for type-matching dependency candidates and, therefore, make them
ineligible for auto-proxying or other kinds of bean post-processing. For example, if you
have a dependency annotated with `@Resource` where the field or setter name does not
[quote]
Bean 'someBean' of type [org.example.SomeType] is not eligible for getting processed by
all BeanPostProcessors (for example: not eligible for auto-proxying).
To minimize the number of beans affected, register a `BeanPostProcessor` with a
`static` `@Bean` method that has no dependencies (see the note above). If you have
beans wired into your `BeanPostProcessor` by using autowiring or `@Resource` (which
may fall back to autowiring), Spring might access unexpected beans when searching
for type-matching dependency candidates and, therefore, make them ineligible for
auto-proxying or other kinds of bean post-processing. For example, if you have a
dependency annotated with `@Resource` where the field or setter name does not
directly correspond to the declared name of a bean and no name attribute is used,
Spring accesses other beans for matching them by type.
====
@@ -135,7 +148,7 @@ Java::
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean '" + beanName + "' created : " + bean.toString());
System.out.println("Bean '" + beanName + "' created : " + bean);
return bean;
}
}
@@ -164,7 +177,48 @@ Kotlin::
----
======
The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
You can register the `InstantiationTracingBeanPostProcessor` with Java configuration
by using a `static` `@Bean` method (recommended to avoid eager initialization of the
configuration class and other beans):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
@Configuration
public class AppConfig {
@Bean
public static InstantiationTracingBeanPostProcessor instantiationTracingBeanPostProcessor() {
return new InstantiationTracingBeanPostProcessor();
}
// ... other bean definitions
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
@Configuration
class AppConfig {
@Bean
companion object {
@JvmStatic
fun instantiationTracingBeanPostProcessor() = InstantiationTracingBeanPostProcessor()
}
// ... other bean definitions
}
----
======
Alternatively, the `InstantiationTracingBeanPostProcessor` can be registered via the
`bean` element with XML configuration:
[source,xml,indent=0,subs="verbatim,quotes"]
----
@@ -192,10 +246,9 @@ The following `beans` element uses the `InstantiationTracingBeanPostProcessor`:
----
Notice how the `InstantiationTracingBeanPostProcessor` is merely defined. It does not
even have a name, and, because it is a bean, it can be dependency-injected as you would any
even have a name, and, because it is a bean, it can be dependency-injected as with any
other bean. (The preceding configuration also defines a bean that is backed by a Groovy
script. The Spring dynamic language support is detailed in the chapter entitled
xref:languages/dynamic.adoc[Dynamic Language Support].)
script.)
The following Java application runs the preceding code and configuration:
@@ -301,6 +354,23 @@ implement the `BeanFactoryPostProcessor` interface. It uses these beans as bean
post-processors, at the appropriate time. You can deploy these post-processor beans as
you would any other bean.
When registering a `BeanFactoryPostProcessor` via an `@Bean` factory method in a
`@Configuration` class, declare the method as `static` to avoid lifecycle conflicts
with annotation processing (such as `@Autowired`, `@Value`, and `@PostConstruct`) in the
configuration class. See the "BeanFactoryPostProcessor-returning `@Bean` methods"
section in the {spring-framework-api}/context/annotation/Bean.html[`@Bean`] javadoc
for details and an example.
For any non-static `@Bean` factory method with a `BeanFactoryPostProcessor` return type,
you should see an INFO-level log message similar to the following.
[quote]
@Bean method MyConfig.myBfpp is non-static and returns an object assignable to Spring's
BeanFactoryPostProcessor interface. This will result in a failure to process annotations
such as @Autowired, @Resource, and @PostConstruct within the method's declaring
@Configuration class. Add the 'static' modifier to this method to avoid these container
lifecycle issues; see @Bean javadoc for complete details.
NOTE: As with ``BeanPostProcessor``s , you typically do not want to configure
``BeanFactoryPostProcessor``s for lazy initialization. If no other bean references a
`Bean(Factory)PostProcessor`, that post-processor will not get instantiated at all.
@@ -4,10 +4,10 @@
`@Bean` is a method-level annotation and a direct analog of the XML `<bean/>` element.
The annotation supports some of the attributes offered by `<bean/>`, such as:
* xref:core/beans/definition.adoc#beans-beanname[name]
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-initializingbean[init-method]
* xref:core/beans/factory-nature.adoc#beans-factory-lifecycle-disposablebean[destroy-method]
* xref:core/beans/dependencies/factory-autowire.adoc[autowiring]
* `name`.
You can use the `@Bean` annotation in a `@Configuration`-annotated or in a
`@Component`-annotated class.
@@ -17,9 +17,10 @@ You can use the `@Bean` annotation in a `@Configuration`-annotated or in a
== Declaring a Bean
To declare a bean, you can annotate a method with the `@Bean` annotation. You use this
method to register a bean definition within an `ApplicationContext` of the type
specified as the method's return value. By default, the bean name is the same as
the method name. The following example shows a `@Bean` method declaration:
method to register a bean definition within an `ApplicationContext` of the type specified
by the method's return type. By default, the bean name is the same as the method name
(unless a different xref:#beans-java-customizing-bean-naming[bean name generator] is
configured). The following example shows a `@Bean` method declaration:
[tabs]
======
@@ -126,7 +127,7 @@ Kotlin::
----
======
However, this limits the visibility for advance type prediction to the specified
However, this limits the visibility for advanced type prediction to the specified
interface type (`TransferService`). Then, with the full type (`TransferServiceImpl`)
known to the container only once the affected singleton bean has been instantiated.
Non-lazy singleton beans get instantiated according to their declaration order,
@@ -473,8 +474,15 @@ Kotlin::
== Customizing Bean Naming
By default, configuration classes use a `@Bean` method's name as the name of the
resulting bean. This functionality can be overridden, however, with the `name` attribute,
as the following example shows:
resulting bean. However, as of Spring Framework 7.0, you can change this default strategy
by configuring a custom
{spring-framework-api}/context/annotation/ConfigurationBeanNameGenerator.html[`ConfigurationBeanNameGenerator`]
when bootstrapping the context or configuring component scanning. For example,
{spring-framework-api}/context/annotation/FullyQualifiedConfigurationBeanNameGenerator.html[`FullyQualifiedConfigurationBeanNameGenerator`]
can be used to generate fully-qualified default bean names for `@Bean` methods without an
explicit `name` attribute. For individual `@Bean` methods, the default or
generator-derived name can be overridden with the `name` attribute, as the following
example shows:
[tabs]
======
@@ -505,6 +513,7 @@ Kotlin::
----
======
NOTE: `@Bean("myThing")` is equivalent to `@Bean(name = "myThing")`.
[[beans-java-bean-aliasing]]
== Bean Aliasing
@@ -327,9 +327,8 @@ Kotlin::
----
======
TIP: Constructor injection in `@Configuration` classes is only supported as of Spring
Framework 4.3. Note also that there is no need to specify `@Autowired` if the target
bean defines only one constructor.
TIP: Note that there is no need to specify `@Autowired` if the target bean defines
only one constructor.
[discrete]
[[beans-java-injecting-imported-beans-fq]]
@@ -339,11 +338,11 @@ In the preceding scenario, using `@Autowired` works well and provides the desire
modularity, but determining exactly where the autowired bean definitions are declared is
still somewhat ambiguous. For example, as a developer looking at `ServiceConfig`, how do
you know exactly where the `@Autowired AccountRepository` bean is declared? It is not
explicit in the code, and this may be just fine. Remember that the
{spring-site-tools}[Spring Tools for Eclipse] provides tooling that
can render graphs showing how everything is wired, which may be all you need. Also,
your Java IDE can easily find all declarations and uses of the `AccountRepository` type
and quickly show you the location of `@Bean` methods that return that type.
explicit in the code, and this may be just fine. Note that the
{spring-site-tools}[Spring Tools] IDE support provides tooling that can render graphs
showing how everything is wired, which may be all you need. Also, your Java IDE can
easily find all declarations and uses of the `AccountRepository` type and quickly show
you the location of `@Bean` methods that return that type.
In cases where this ambiguity is not acceptable and you wish to have direct navigation
from within your IDE from one `@Configuration` class to another, consider autowiring the
@@ -611,6 +610,19 @@ Kotlin::
See the {spring-framework-api}/context/annotation/Conditional.html[`@Conditional`]
javadoc for more detail.
[NOTE]
====
A `@Conditional` annotation declared on an enclosing `@Configuration` class is only
applied to the registration of a nested `@Configuration` class if the nested class is
reached through the parser's recursion from its enclosing class, or via `@Import`. If a
nested class is discovered independently of its enclosing class — for example, via
`@ComponentScan` or by directly registering it against the application context — it is
processed using only its own `@Conditional` annotations. Thus, if you wish to ensure that
the same `@Conditional` annotations apply in such scenarios, you must redeclare the
relevant annotations on the nested class, or extract them into a composed annotation
which you apply to both the enclosing class and the nested class.
====
[[beans-java-combining]]
== Combining Java and XML Configuration
@@ -0,0 +1,25 @@
[[beans-java-programmatic-registration]]
= Programmatic Bean Registration
As of Spring Framework 7, a first-class support for programmatic bean registration is
provided via the {spring-framework-api}/beans/factory/BeanRegistrar.html[`BeanRegistrar`]
interface that can be implemented to register beans programmatically in a flexible and
efficient way.
Those bean registrar implementations are typically imported with an `@Import` annotation
on `@Configuration` classes.
include-code::./MyConfiguration[tag=snippet,indent=0]
NOTE: You can leverage type-level conditional annotations ({spring-framework-api}/context/annotation/Conditional.html[`@Conditional`],
but also other variants) to conditionally import the related bean registrars.
The bean registrar implementation uses {spring-framework-api}/beans/factory/BeanRegistry.html[`BeanRegistry`] and
{spring-framework-api}/core/env/Environment.html[`Environment`] APIs to register beans programmatically in a concise
and flexible way. For example, it allows custom registration through an `if` expression, a
`for` loop, etc.
include-code::./MyBeanRegistrar[tag=snippet,indent=0]
NOTE: Bean registrars are supported with xref:core/aot.adoc[Ahead of Time Optimizations],
either on the JVM or with GraalVM native images, including when instance suppliers are used.
@@ -1,16 +1,17 @@
[[beans-standard-annotations]]
= Using JSR 330 Standard Annotations
= Using JSR-330 Standard Annotations
Spring offers support for JSR-330 standard annotations (Dependency Injection). Those
annotations are scanned in the same way as the Spring annotations. To use them, you need
to have the relevant jars in your classpath.
Spring offers support for JSR-330 standard _Dependency Injection_ annotations which are
available in the `jakarta.inject` package. These annotations may optionally be used as
alternatives to Spring annotations.
To use them, you need to have the relevant jar in your classpath. For example, the
`jakarta.inject` artifact is available in the standard Maven repository
(`https://repo.maven.apache.org/maven2/jakarta/inject/jakarta.inject-api/2.0.0/`),
[NOTE]
=====
If you use Maven, the `jakarta.inject` artifact is available in the standard Maven
repository (
https://repo.maven.apache.org/maven2/jakarta/inject/jakarta.inject-api/2.0.0/[https://repo.maven.apache.org/maven2/jakarta/inject/jakarta.inject-api/2.0.0/]).
You can add the following dependency to your file pom.xml:
If you use Maven, you can add the following dependency to your `pom.xml` file.
[source,xml,indent=0,subs="verbatim,quotes"]
----
@@ -26,13 +27,14 @@ You can add the following dependency to your file pom.xml:
[[beans-inject-named]]
== Dependency Injection with `@Inject` and `@Named`
Instead of `@Autowired`, you can use `@jakarta.inject.Inject` as follows:
Instead of using `@Autowired` for dependency injection, you may optionally choose to use
`@jakarta.inject.Inject` as follows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
@@ -54,7 +56,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject
@@ -72,17 +74,19 @@ Kotlin::
----
======
As with `@Autowired`, you can use `@Inject` at the field level, method level
and constructor-argument level. Furthermore, you may declare your injection point as a
`Provider`, allowing for on-demand access to beans of shorter scopes or lazy access to
other beans through a `Provider.get()` call. The following example offers a variant of the
preceding example:
As with `@Autowired`, you can use `@Inject` at the field level, method level, and
constructor-argument level.
Furthermore, as an alternative to Spring's `ObjectProvider` mechanism, you may choose to
declare your injection point as a `jakarta.inject.Provider`, allowing for on-demand
access to beans of shorter scopes or lazy access to other beans through a
`Provider.get()` call. The following example offers a variant of the preceding example.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
import jakarta.inject.Provider;
@@ -105,9 +109,10 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject
import jakarta.inject.Provider
class SimpleMovieLister {
@@ -123,14 +128,15 @@ Kotlin::
----
======
If you would like to use a qualified name for the dependency that should be injected,
you should use the `@Named` annotation, as the following example shows:
If you would like to use a qualified name for the dependency that should be injected, you
may choose to use the `@Named` annotation as an alternative to Spring's `@Qualifier`
support, as the following example shows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -150,7 +156,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject
import jakarta.inject.Named
@@ -170,12 +176,15 @@ Kotlin::
======
As with `@Autowired`, `@Inject` can also be used with `java.util.Optional` or
`@Nullable`. This is even more applicable here, since `@Inject` does not have
a `required` attribute. The following pair of examples show how to use `@Inject` and
`@Nullable`:
`@Nullable`. This is even more applicable here, since `@Inject` does not have a
`required` attribute. The following examples show how to use `@Inject` with `Optional`,
`@Nullable`, and Kotlin's built-in support for nullable types.
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
import java.util.Optional;
public class SimpleMovieLister {
@Inject
@@ -189,8 +198,11 @@ a `required` attribute. The following pair of examples show how to use `@Inject`
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
import org.jspecify.annotations.Nullable;
public class SimpleMovieLister {
@Inject
@@ -202,8 +214,10 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject
class SimpleMovieLister {
@Inject
@@ -214,21 +228,21 @@ Kotlin::
[[beans-named]]
== `@Named` and `@ManagedBean`: Standard Equivalents to the `@Component` Annotation
== `@Named`: Standard Equivalent to the `@Component` Annotation
Instead of `@Component`, you can use `@jakarta.inject.Named` or `jakarta.annotation.ManagedBean`,
as the following example shows:
Instead of `@Component` or other Spring stereotype annotations, you may optionally choose
to use `@jakarta.inject.Named`, as the following example shows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named("movieListener") // @ManagedBean("movieListener") could be used as well
@Named("movieListener")
public class SimpleMovieLister {
private MovieFinder movieFinder;
@@ -244,12 +258,12 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject
import jakarta.inject.Named
@Named("movieListener") // @ManagedBean("movieListener") could be used as well
@Named("movieListener")
class SimpleMovieLister {
@Inject
@@ -260,14 +274,15 @@ Kotlin::
----
======
It is very common to use `@Component` without specifying a name for the component.
`@Named` can be used in a similar fashion, as the following example shows:
It is very common to use `@Component` or other Spring stereotype annotations without
specifying an explicit name for the component, and `@Named` can be used in a similar
fashion, as the following example shows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -288,7 +303,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
import jakarta.inject.Inject
import jakarta.inject.Named
@@ -304,14 +319,14 @@ Kotlin::
----
======
When you use `@Named` or `@ManagedBean`, you can use component scanning in the
exact same way as when you use Spring annotations, as the following example shows:
When you use `@Named`, you can use component scanning in the exact same way as when you
use Spring annotations, as the following example shows.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
@Configuration
@ComponentScan(basePackages = "org.example")
@@ -322,7 +337,7 @@ Java::
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
@Configuration
@ComponentScan(basePackages = ["org.example"])
@@ -332,55 +347,106 @@ Kotlin::
----
======
NOTE: In contrast to `@Component`, the JSR-330 `@Named` and the JSR-250 `@ManagedBean`
annotations are not composable. You should use Spring's stereotype model for building
custom component annotations.
NOTE: In contrast to `@Component`, the JSR-330 `@Named` annotation is not composable. You
should use Spring's stereotype model for building custom component annotations.
[TIP]
====
If you work with legacy systems that still use `@javax.inject.Named` or
`@javax.annotation.ManagedBean` for components (note the `javax` package namespace), you
can explicitly configure component scanning to include those annotation types, as shown
in the following example.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",fold="-imports"]
----
@Configuration
@ComponentScan(
basePackages = "org.example",
includeFilters = @Filter({
javax.inject.Named.class,
javax.annotation.ManagedBean.class
})
)
public class AppConfig {
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",fold="-imports"]
----
@Configuration
@ComponentScan(
basePackages = ["org.example"],
includeFilters = [Filter([
javax.inject.Named::class,
javax.annotation.ManagedBean::class
])]
)
class AppConfig {
// ...
}
----
======
In addition, if you would like for the `value` attributes in `@javax.inject.Named` and
`@javax.annotation.ManagedBean` to be used as component names, you need to override the
`isStereotypeWithNameValue(...)` method in `AnnotationBeanNameGenerator` to add explicit
support for `javax.annotation.ManagedBean` and `javax.inject.Named` and register your
custom `AnnotationBeanNameGenerator` via the `nameGenerator` attribute in
`@ComponentScan`.
====
[[beans-standard-annotations-limitations]]
== Limitations of JSR-330 Standard Annotations
When you work with standard annotations, you should know that some significant
features are not available, as the following table shows:
When you work with JSR-330 standard annotations, you should know that some significant
features are not available, as the following table shows.
[[annotations-comparison]]
.Spring component model elements versus JSR-330 variants
.Spring component model versus JSR-330 variants
|===
| Spring| jakarta.inject.*| jakarta.inject restrictions / comments
| Spring | JSR-330 | JSR-330 restrictions / comments
| @Autowired
| @Inject
| `@Inject` has no 'required' attribute. Can be used with Java 8's `Optional` instead.
| `@Autowired`
| `@Inject`
| `@Inject` has no `required` attribute. Can be used with Java's `Optional` instead.
| @Component
| @Named / @ManagedBean
| `@Component`
| `@Named`
| JSR-330 does not provide a composable model, only a way to identify named components.
| @Scope("singleton")
| @Singleton
| `@Scope("singleton")`
| `@Singleton`
| The JSR-330 default scope is like Spring's `prototype`. However, in order to keep it
consistent with Spring's general defaults, a JSR-330 bean declared in the Spring
container is a `singleton` by default. In order to use a scope other than `singleton`,
you should use Spring's `@Scope` annotation. `jakarta.inject` also provides a
`jakarta.inject.Scope` annotation: however, this one is only intended to be used
`jakarta.inject.Scope` annotation; however, this one is only intended to be used
for creating custom annotations.
| @Qualifier
| @Qualifier / @Named
| `@Qualifier`
| `@Qualifier` / `@Named`
| `jakarta.inject.Qualifier` is just a meta-annotation for building custom qualifiers.
Concrete `String` qualifiers (like Spring's `@Qualifier` with a value) can be associated
through `jakarta.inject.Named`.
| @Value
| `@Value`
| -
| no equivalent
| @Lazy
| `@Lazy`
| -
| no equivalent
| ObjectFactory
| Provider
| `ObjectFactory`
| `Provider`
| `jakarta.inject.Provider` is a direct alternative to Spring's `ObjectFactory`,
only with a shorter `get()` method name. It can also be used in combination with
Spring's `@Autowired` or with non-annotated constructors and setter methods.
@@ -3,8 +3,8 @@
Java NIO provides `ByteBuffer` but many libraries build their own byte buffer API on top,
especially for network operations where reusing buffers and/or using direct buffers is
beneficial for performance. For example Netty has the `ByteBuf` hierarchy, Undertow uses
XNIO, Jetty uses pooled byte buffers with a callback to be released, and so on.
beneficial for performance. For example Netty has the `ByteBuf` hierarchy,
Jetty uses pooled byte buffers with a callback to be released, and so on.
The `spring-core` module provides a set of abstractions to work with various byte buffer
APIs as follows:
@@ -7,14 +7,14 @@ similar to the https://jakarta.ee/specifications/expression-language/[Jakarta Ex
Language] but offers additional features, most notably method invocation and basic string
templating functionality.
While there are several other Java expression languages available -- OGNL, MVEL, and JBoss
EL, to name a few -- the Spring Expression Language was created to provide the Spring
community with a single well supported expression language that can be used across all
the products in the Spring portfolio. Its language features are driven by the
requirements of the projects in the Spring portfolio, including tooling requirements
for code completion support within the {spring-site-tools}[Spring Tools for Eclipse].
That said, SpEL is based on a technology-agnostic API that lets other expression language
implementations be integrated, should the need arise.
While there are several other Java expression languages available -- OGNL, MVEL, and
JBoss EL, to name a few -- the Spring Expression Language was created to provide the
Spring community with a single well supported expression language that can be used across
all the products in the Spring portfolio. Its language features are driven by the
requirements of the projects in the Spring portfolio, including tooling requirements for
code completion within the {spring-site-tools}[Spring Tools] IDE support. That said, SpEL
is based on a technology-agnostic API that lets other expression language implementations
be integrated, should the need arise.
While SpEL serves as the foundation for expression evaluation within the Spring
portfolio, it is not directly tied to Spring and can be used independently. To
@@ -395,6 +395,16 @@ set a JVM system property or Spring property named `spring.context.expression.ma
to the maximum expression length needed by your application (see
xref:appendix.adoc#appendix-spring-properties[Supported Spring Properties]).
Similarly, the number of operations performed during the evaluation of a SpEL expression
cannot exceed 10,000 by default; however, the `maxOperations` value is configurable. If
you create a `SpelExpressionParser` programmatically (the recommend approach), you can
specify a custom `maxOperations` value when creating the `SpelParserConfiguration` that
you provide to the `SpelExpressionParser`. If you are not able to configure an explicit
value for `maxOperations` via `SpelParserConfiguration`, you can set a JVM system
property or Spring property named `spring.expression.maxOperations` to the maximum number
of operations required by your application (see
xref:appendix.adoc#appendix-spring-properties[Supported Spring Properties]).
[[expressions-spel-compilation]]
== SpEL Compilation
@@ -2,4 +2,12 @@
= Language Reference
:page-section-summary-toc: 1
This section describes how the Spring Expression Language works.
Spring Expression Language (SpEL) expressions are composed of a sequence of tokens such
as literals, operators, method invocations, and so forth.
Whitespace can be used freely between tokens to format and improve the readability of
expressions. Specifically, the `\s` (space), `\t` (tab), `\r` (carriage return), and `\n`
(newline) characters are all valid separators between tokens. However, whitespace is
ignored by the expression parser unless it is part of a string literal.
The following sections describe the features and syntax of SpEL.
@@ -1,19 +1,19 @@
[[expressions-operator-elvis]]
= The Elvis Operator
The Elvis operator is a shortening of the ternary operator syntax and is used in the
https://www.groovy-lang.org/operators.html#_elvis_operator[Groovy] language.
With the ternary operator syntax, you usually have to repeat a variable twice, as the
following example shows:
The Elvis operator (`?:`) is a shortening of the ternary operator syntax and is used in
the https://www.groovy-lang.org/operators.html#_elvis_operator[Groovy] language. With the
ternary operator syntax, you often have to repeat a variable twice, as the following Java
example shows:
[source,groovy,indent=0,subs="verbatim,quotes"]
[source,java,indent=0,subs="verbatim,quotes"]
----
String name = "Elvis Presley";
String displayName = (name != null ? name : "Unknown");
----
Instead, you can use the Elvis operator (named for the resemblance to Elvis' hair style).
The following example shows how to use the Elvis operator:
The following example shows how to use the Elvis operator in a SpEL expression:
[tabs]
======
@@ -23,7 +23,7 @@ Java::
----
ExpressionParser parser = new SpelExpressionParser();
String name = parser.parseExpression("name?:'Unknown'").getValue(new Inventor(), String.class);
String name = parser.parseExpression("name ?: 'Unknown'").getValue(new Inventor(), String.class);
System.out.println(name); // 'Unknown'
----
@@ -33,14 +33,29 @@ Kotlin::
----
val parser = SpelExpressionParser()
val name = parser.parseExpression("name?:'Unknown'").getValue(Inventor(), String::class.java)
val name = parser.parseExpression("name ?: 'Unknown'").getValue(Inventor(), String::class.java)
println(name) // 'Unknown'
----
======
NOTE: The SpEL Elvis operator also checks for _empty_ Strings in addition to `null` objects.
The original snippet is thus only close to emulating the semantics of the operator (it would need an
additional `!name.isEmpty()` check).
[NOTE]
====
The SpEL Elvis operator also treats an _empty_ String like a `null` object. Thus, the
original Java example is only close to emulating the semantics of the operator: it would
need to use `name != null && !name.isEmpty()` as the predicate to be compatible with the
semantics of the SpEL Elvis operator.
====
[TIP]
====
As of Spring Framework 7.0, the SpEL Elvis operator supports `java.util.Optional` with
transparent unwrapping semantics.
For example, given the expression `A ?: B`, if `A` is `null` or an _empty_ `Optional`,
the expression evaluates to `B`. However, if `A` is a non-empty `Optional` the expression
evaluates to the object contained in the `Optional`, thereby effectively unwrapping the
`Optional` which correlates to `A.get()`.
====
The following listing shows a more complex example:
@@ -54,11 +69,11 @@ Java::
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
String name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String.class);
String name = parser.parseExpression("name ?: 'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name); // Nikola Tesla
tesla.setName("");
name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String.class);
name = parser.parseExpression("name ?: 'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name); // Elvis Presley
----
@@ -70,16 +85,16 @@ Kotlin::
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
val tesla = Inventor("Nikola Tesla", "Serbian")
var name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String::class.java)
var name = parser.parseExpression("name ?: 'Elvis Presley'").getValue(context, tesla, String::class.java)
println(name) // Nikola Tesla
tesla.setName("")
name = parser.parseExpression("name?:'Elvis Presley'").getValue(context, tesla, String::class.java)
name = parser.parseExpression("name ?: 'Elvis Presley'").getValue(context, tesla, String::class.java)
println(name) // Elvis Presley
----
======
[NOTE]
[TIP]
=====
You can use the Elvis operator to apply default values in expressions. The following
example shows how to use the Elvis operator in a `@Value` expression:
@@ -89,7 +104,6 @@ example shows how to use the Elvis operator in a `@Value` expression:
@Value("#{systemProperties['pop3.port'] ?: 25}")
----
This will inject a system property `pop3.port` if it is defined or 25 if not.
This will inject the value of the system property named `pop3.port` if it is defined or
`25` if the property is not defined.
=====
@@ -252,7 +252,6 @@ Kotlin::
<1> Use "null-safe select first" operator on potentially null `members` list
======
The following example shows how to use the "null-safe select last" operator for
collections (`?.$`).
@@ -351,6 +350,50 @@ Kotlin::
<2> Use null-safe projection operator on null `members` list
======
[[expressions-operator-safe-navigation-optional]]
== Null-safe Operations on `Optional`
As of Spring Framework 7.0, null-safe operations are supported on instances of
`java.util.Optional` with transparent unwrapping semantics.
Specifically, when a null-safe operator is applied to an _empty_ `Optional`, it will be
treated as if the `Optional` were `null`, and the subsequent operation will evaluate to
`null`. However, if a null-safe operator is applied to a non-empty `Optional`, the
subsequent operation will be applied to the object contained in the `Optional`, thereby
effectively unwrapping the `Optional`.
For example, if `user` is of type `Optional<User>`, the expression `user?.name` will
evaluate to `null` if `user` is either `null` or an _empty_ `Optional` and will otherwise
evaluate to the `name` of the `user`, effectively `user.get().getName()` or
`user.get().name` for property or field access, respectively.
[NOTE]
====
Invocations of methods defined in the `Optional` API are still supported on an _empty_
`Optional`. For example, if `name` is of type `Optional<String>`, the expression
`name?.orElse('Unknown')` will evaluate to `"Unknown"` if `name` is an empty `Optional`
and will otherwise evaluate to the `String` contained in the `Optional` if `name` is a
non-empty `Optional`, effectively `name.get()`.
====
// NOTE: &#8288; is the Unicode Character 'WORD JOINER', which prevents undesired line wraps.
Similarly, if `names` is of type `Optional<List<String>>`, the expression
`names?.?&#8288;[#this.length > 5]` will evaluate to `null` if `names` is `null` or an _empty_
`Optional` and will otherwise evaluate to a sequence containing the names whose lengths
are greater than 5, effectively
`names.get().stream().filter(s -> s.length() > 5).toList()`.
The same semantics apply to all of the null-safe operators mentioned previously in this
chapter.
For further details and examples, consult the javadoc for the following operators.
* {spring-framework-api}/expression/spel/ast/PropertyOrFieldReference.html[`PropertyOrFieldReference`]
* {spring-framework-api}/expression/spel/ast/MethodReference.html[`MethodReference`]
* {spring-framework-api}/expression/spel/ast/Indexer.html[`Indexer`]
* {spring-framework-api}/expression/spel/ast/Selection.html[`Selection`]
* {spring-framework-api}/expression/spel/ast/Projection.html[`Projection`]
[[expressions-operator-safe-navigation-compound-expressions]]
== Null-safe Operations in Compound Expressions
@@ -53,7 +53,7 @@ Kotlin::
val trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean::class.java)
// uses CustomValue:::compareTo
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java);
val trueValue = parser.parseExpression("new CustomValue(1) < new CustomValue(2)").getValue(Boolean::class.java)
----
======
@@ -167,7 +167,7 @@ Kotlin::
[CAUTION]
====
The syntax for the `between` operator is `<input> between {<range_begin>, <range_end>}`,
which is effectively a shortcut for `<input> >= <range_begin> && <input> \<= <range_end>}`.
which is effectively a shortcut for `<input> >= <range_begin> && <input> \<= <range_end>`.
Consequently, `1 between {1, 5}` evaluates to `true`, while `1 between {5, 1}` evaluates
to `false`.
@@ -312,13 +312,13 @@ Kotlin::
// evaluates to 'a'
val ch = parser.parseExpression("'d' - 3")
.getValue(Character::class.java);
.getValue(Char::class.java)
// -- Repeat --
// evaluates to "abcabc"
val repeated = parser.parseExpression("'abc' * 2")
.getValue(String::class.java);
.getValue(String::class.java)
----
======
@@ -485,7 +485,7 @@ Kotlin::
// -- Operator precedence --
val minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Int::class.java) // -21
val minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Int::class.java) // -21
----
======
@@ -541,32 +541,7 @@ For example, if we want to overload the `ADD` operator to allow two lists to be
concatenated using the `+` sign, we can implement a custom `OperatorOverloader` as
follows.
[source,java,indent=0,subs="verbatim,quotes"]
----
pubic class ListConcatenation implements OperatorOverloader {
@Override
public boolean overridesOperation(Operation operation, Object left, Object right) {
return (operation == Operation.ADD &&
left instanceof List && right instanceof List);
}
@Override
@SuppressWarnings("unchecked")
public Object operate(Operation operation, Object left, Object right) {
if (operation == Operation.ADD &&
left instanceof List list1 && right instanceof List list2) {
List result = new ArrayList(list1);
result.addAll(list2);
return result;
}
throw new UnsupportedOperationException(
"No overload for operation %s and operands [%s] and [%s]"
.formatted(operation, left, right));
}
}
----
include-code::./ListConcatenation[]
If we register `ListConcatenation` as the `OperatorOverloader` in a
`StandardEvaluationContext`, we can then evaluate expressions like `{1, 2, 3} + {4, 5}`
@@ -589,8 +564,8 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
StandardEvaluationContext context = StandardEvaluationContext()
context.setOperatorOverloader(ListConcatenation())
val context = StandardEvaluationContext()
context.operatorOverloader = ListConcatenation()
// evaluates to a new list: [1, 2, 3, 4, 5]
parser.parseExpression("{1, 2, 3} + {2 + 2, 5}").getValue(context, List::class.java)
@@ -270,7 +270,7 @@ is applicable for typical implementations of indexed structures.
NOTE: `ReflectiveIndexAccessor` also implements `CompilableIndexAccessor` in order to
support xref:core/expressions/evaluation.adoc#expressions-spel-compilation[compilation]
to bytecode for read access. Note, however, that the configured read-method must be
invokable via a `public` class or `public` interface for compilation to succeed.
invocable via a `public` class or `public` interface for compilation to succeed.
The following code listings define a `Color` enum and `FruitMap` type that behaves like a
map but does not implement the `java.util.Map` interface. Thus, if you want to index into
@@ -6,7 +6,7 @@ are set by using the `setVariable()` method in `EvaluationContext` implementatio
[NOTE]
====
Variable names must be begin with a letter (as defined below), an underscore, or a dollar
Variable names must begin with a letter (as defined below), an underscore, or a dollar
sign.
Variable names must be composed of one or more of the following supported types of
@@ -1,53 +1,216 @@
[[null-safety]]
= Null-safety
Although Java does not let you express null-safety with its type system, the Spring Framework
provides the following annotations in the `org.springframework.lang` package to let you
declare nullability of APIs and fields:
Although Java does not let you express nullness markers with its type system yet, the Spring Framework codebase is
annotated with https://jspecify.dev/docs/start-here/[JSpecify] annotations to declare the nullability of its APIs,
fields, and related type usages. Reading the https://jspecify.dev/docs/user-guide/[JSpecify user guide] is highly
recommended in order to get familiar with those annotations and semantics.
* {spring-framework-api}/lang/Nullable.html[`@Nullable`]: Annotation to indicate that a
specific parameter, return value, or field can be `null`.
* {spring-framework-api}/lang/NonNull.html[`@NonNull`]: Annotation to indicate that a specific
parameter, return value, or field cannot be `null` (not needed on parameters, return values,
and fields where `@NonNullApi` and `@NonNullFields` apply, respectively).
* {spring-framework-api}/lang/NonNullApi.html[`@NonNullApi`]: Annotation at the package level
that declares non-null as the default semantics for parameters and return values.
* {spring-framework-api}/lang/NonNullFields.html[`@NonNullFields`]: Annotation at the package
level that declares non-null as the default semantics for fields.
The primary goal of this null-safety arrangement is to prevent a `NullPointerException` from being thrown at
runtime via build time checks and to use explicit nullability as a way to express the possible absence of value.
It is useful in Java by leveraging nullability checkers such as https://github.com/uber/NullAway[NullAway] or IDEs
supporting JSpecify annotations such as IntelliJ IDEA and Eclipse (the latter requiring manual configuration). In Kotlin,
JSpecify annotations are automatically translated to {kotlin-docs}/null-safety.html[Kotlin's null safety].
The Spring Framework itself leverages these annotations, but they can also be used in any
Spring-based Java project to declare null-safe APIs and optionally null-safe fields.
Nullability declarations for generic type arguments, varargs, and array elements are not supported yet.
Nullability declarations are expected to be fine-tuned between Spring Framework releases,
including minor ones. Nullability of types used inside method bodies is outside the
scope of this feature.
NOTE: Other common libraries such as Reactor and Spring Data provide null-safe APIs that
use a similar nullability arrangement, delivering a consistent overall experience for
Spring application developers.
The {spring-framework-api}/core/Nullness.html[`Nullness` Spring API] can be used at runtime to detect the
nullness of a type usage, a field, a method return type, or a parameter. It provides full support for
JSpecify annotations, Kotlin null safety, and Java primitive types, as well as a pragmatic check on any
`@Nullable` annotation (regardless of the package).
[[use-cases]]
== Use cases
[[null-safety-libraries]]
== Annotating libraries with JSpecify annotations
In addition to providing an explicit declaration for Spring Framework API nullability,
these annotations can be used by an IDE (such as IDEA or Eclipse) to provide useful
warnings related to null-safety in order to avoid `NullPointerException` at runtime.
They are also used to make Spring APIs null-safe in Kotlin projects, since Kotlin natively
supports {kotlin-docs}/null-safety.html[null-safety]. More details
are available in the xref:languages/kotlin/null-safety.adoc[Kotlin support documentation].
As of Spring Framework 7, the Spring Framework codebase leverages JSpecify annotations to expose null-safe APIs
and to check the consistency of those nullability declarations with https://github.com/uber/NullAway[NullAway]
as part of its build. It is recommended for each library depending on Spring Framework and Spring portfolio projects,
as well as other libraries related to the Spring ecosystem (Reactor, Micrometer, and Spring community projects),
to do the same.
[[jsr-305-meta-annotations]]
== JSR-305 meta-annotations
[[null-safety-applications]]
== Leveraging JSpecify annotations in Spring applications
Spring annotations are meta-annotated with {JSR}305[JSR 305]
annotations (a dormant but widespread JSR). JSR-305 meta-annotations let tooling vendors
like IDEA or Kotlin provide null-safety support in a generic way, without having to
hard-code support for Spring annotations.
Developing applications with IDEs that support nullness annotations will provide warnings in Java and errors in
Kotlin when the nullability contracts are not honored, allowing Spring application developers to refine their
null handling to prevent a `NullPointerException` from being thrown at runtime.
It is neither necessary nor recommended to add a JSR-305 dependency to the project classpath to
take advantage of Spring's null-safe APIs. Only projects such as Spring-based libraries that use
null-safety annotations in their codebase should add `com.google.code.findbugs:jsr305:3.0.2`
with `compileOnly` Gradle configuration or Maven `provided` scope to avoid compiler warnings.
Optionally, Spring application developers can annotate their codebase and use build plugins like
https://github.com/uber/NullAway[NullAway] to enforce null-safety at the application level during build time.
[[null-safety-guidelines]]
== Guidelines
The purpose of this section is to share some proposed guidelines for explicitly specifying the nullability of
Spring-related libraries or applications.
[[null-safety-guidelines-jspecify]]
=== JSpecify
==== Defaults to non-null
A key point to understand is that the nullness of types is unknown by default in Java and that non-null type usage
is by far more frequent than nullable usage. In order to keep codebases readable, we typically want to define by
default that type usage is non-null unless marked as nullable for a specific scope. This is exactly the purpose
of https://jspecify.dev/docs/api/org/jspecify/annotations/NullMarked.html[`@NullMarked`] which is typically set
in Spring projects at the package level via a `package-info.java` file, for example:
[source,java,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
@NullMarked
package org.springframework.core;
import org.jspecify.annotations.NullMarked;
----
==== Explicit nullability
In `@NullMarked` code, nullable type usage is defined explicitly with
https://jspecify.dev/docs/api/org/jspecify/annotations/Nullable.html[`@Nullable`].
A key difference between JSpecify `@Nullable` / `@NonNull` annotations and most other variants is that the JSpecify
annotations are meta-annotated with `@Target(ElementType.TYPE_USE)`, so they apply only to type usage. This impacts
where such annotations should be placed, either to comply with
https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[related Java specifications] or to follow code
style best practices. From a style perspective, it is recommended to embrace the type-use nature of those annotations
by placing them on the same line as and immediately preceding the annotated type.
For example, for a field:
[source,java,subs="verbatim,quotes"]
----
private @Nullable String fileEncoding;
----
Or for method parameters and method return types:
[source,java,subs="verbatim,quotes"]
----
public @Nullable String buildMessage(@Nullable String message,
@Nullable Throwable cause) {
// ...
}
----
[NOTE]
====
When overriding a method, JSpecify annotations are not inherited from the original
method. That means the JSpecify annotations should be copied to the overriding method if
you want to override the implementation and keep the same nullability semantics.
====
https://jspecify.dev/docs/api/org/jspecify/annotations/NonNull.html[`@NonNull`] and
https://jspecify.dev/docs/api/org/jspecify/annotations/NullUnmarked.html[`@NullUnmarked`] should rarely be needed for
typical use cases.
==== Arrays and varargs
With arrays and varargs, you need to be able to differentiate the nullness of the elements from the nullness of
the array itself. Pay attention to the syntax
https://docs.oracle.com/javase/specs/jls/se17/html/jls-9.html#jls-9.7.4[defined by the Java specification] which may be
initially surprising. For example, in `@NullMarked` code:
- `@Nullable Object[] array` means individual elements can be `null` but the array itself cannot.
- `Object @Nullable [] array` means individual elements cannot be `null` but the array itself can.
- `@Nullable Object @Nullable [] array` means both individual elements and the array can be `null`.
==== Generics
JSpecify annotations apply to generics as well. For example, in `@NullMarked` code:
- `List<String>` means a list of non-null elements (equivalent of `List<@NonNull String>`)
- `List<@Nullable String>` means a list of nullable elements
Things are a bit more complicated when you are declaring generic types or generic methods. See the related
https://jspecify.dev/docs/user-guide/#generics[JSpecify generics documentation] for more details.
WARNING: The nullability of generic types and generic methods
https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[is not yet fully supported by NullAway].
==== Nested and fully qualified types
The Java specification also enforces that annotations defined with `@Target(ElementType.TYPE_USE)` like JSpecify's
`@Nullable` annotation must be declared after the last dot (`.`) within inner or fully qualified type names:
- `Cache.@Nullable ValueWrapper`
- `jakarta.validation.@Nullable Validator`
[[null-safety-guidelines-nullaway]]
=== NullAway
==== Configuration
The recommended configuration is:
- `NullAway:OnlyNullMarked=true` in order to perform nullability checks only for packages annotated with `@NullMarked`.
- `NullAway:CustomContractAnnotations=org.springframework.lang.Contract` which makes NullAway aware of the
{spring-framework-api}/lang/Contract.html[@Contract] annotation in the `org.springframework.lang` package which
can be used to express complementary semantics to avoid irrelevant warnings in your codebase.
A good example of the benefits of a `@Contract` declaration can be seen with
{spring-framework-api}/util/Assert.html#notNull(java.lang.Object,java.lang.String)[`Assert.notNull()`]
which is annotated with `@Contract("null, _ -> fail")`. With that contract declaration, NullAway will understand
that the value passed as a parameter cannot be null after a successful invocation of `Assert.notNull()`.
Optionally, it is possible to set `NullAway:JSpecifyMode=true` to enable
https://github.com/uber/NullAway/wiki/JSpecify-Support[checks on the full JSpecify semantics], including annotations on
arrays, varargs, and generics. Be aware that this mode is
https://github.com/uber/NullAway/issues?q=is%3Aissue+is%3Aopen+label%3Ajspecify[still under development] and requires
JDK 22 or later (typically combined with the `--release` Java compiler flag to configure the
expected baseline). It is recommended to enable the JSpecify mode only as a second step, after making sure the codebase
generates no warning with the recommended configuration mentioned previously in this section.
==== Warnings suppression
There are a few valid use cases where NullAway will incorrectly detect nullability problems. In such cases,
it is recommended to suppress related warnings and to document the reason:
- `@SuppressWarnings("NullAway.Init")` at field, constructor, or class level can be used to avoid unnecessary warnings
due to the lazy initialization of fields for example, due to a class implementing
{spring-framework-api}/beans/factory/InitializingBean.html[`InitializingBean`].
- `@SuppressWarnings("NullAway") // Dataflow analysis limitation` can be used when NullAway dataflow analysis is not
able to detect that the path involving a nullability problem will never happen.
- `@SuppressWarnings("NullAway") // Lambda` can be used when NullAway does not take into account assertions performed
outside of a lambda for the code path within the lambda.
- `@SuppressWarnings("NullAway") // Reflection` can be used for some reflection operations that are known to return
non-null values even if that cannot be expressed by the API.
- `@SuppressWarnings("NullAway") // Well-known map keys` can be used when `Map#get` invocations are performed with keys
that are known to be present and when non-null related values have been inserted previously.
- `@SuppressWarnings("NullAway") // Overridden method does not define nullability` can be used when the superclass does
not define nullability (typically when the superclass comes from an external dependency).
- `@SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075` can be used when NullAway is not able to detect type variable nullness in generic methods.
[[null-safety-migrating]]
== Migrating from Spring null-safety annotations
Spring null-safety annotations {spring-framework-api}/lang/Nullable.html[`@Nullable`],
{spring-framework-api}/lang/NonNull.html[`@NonNull`],
{spring-framework-api}/lang/NonNullApi.html[`@NonNullApi`], and
{spring-framework-api}/lang/NonNullFields.html[`@NonNullFields`] in the `org.springframework.lang` package were
introduced in Spring Framework 5 when JSpecify did not exist, and the best option at that time was to leverage
meta-annotations from JSR 305 (a dormant but widespread JSR). They are deprecated as of Spring Framework 7 in favor of
https://jspecify.dev/docs/start-here/[JSpecify] annotations, which provide significant enhancements such as properly
defined specifications, a canonical dependency with no split-package issues, better tooling, better Kotlin integration,
and the capability to specify nullability more precisely for more use cases.
A key difference is that Spring's deprecated null-safety annotations, which follow JSR 305 semantics, apply to fields,
parameters, and return values; while JSpecify annotations apply to type usage. This subtle difference
is pretty significant in practice, since it allows developers to differentiate between the nullness of elements and the
nullness of arrays/varargs as well as to define the nullness of generic types.
That means array and varargs null-safety declarations have to be updated to keep the same semantics. For example
`@Nullable Object[] array` with Spring annotations needs to be changed to `Object @Nullable [] array` with JSpecify
annotations. The same applies to varargs.
It is also recommended to move field and return value annotations closer to the type and on the same line, for example:
- For fields, instead of `@Nullable private String field` with Spring annotations, use `private @Nullable String field`
with JSpecify annotations.
- For method return types, instead of `@Nullable public String method()` with Spring annotations, use
`public @Nullable String method()` with JSpecify annotations.
Also, with JSpecify, you do not need to specify `@NonNull` when overriding a type usage annotated with `@Nullable`
in the super method to "undo" the nullable declaration in null-marked code. Just declare it unannotated, and the
null-marked defaults will apply (type usage is considered non-null unless explicitly annotated as nullable).
@@ -0,0 +1,359 @@
[[resilience]]
= Resilience Features
As of 7.0, the core Spring Framework includes common resilience features, in particular
<<resilience-annotations-retryable>> and <<resilience-annotations-concurrencylimit>>
annotations for method invocations as well as <<resilience-programmatic-retry,
programmatic retry support>>.
[[resilience-annotations-retryable]]
== `@Retryable`
{spring-framework-api}/resilience/annotation/Retryable.html[`@Retryable`] is an annotation
that specifies retry characteristics for an individual method (with the annotation
declared at the method level), or for all proxy-invoked methods in a given class hierarchy
(with the annotation declared at the type level).
[source,java,indent=0,subs="verbatim,quotes"]
----
@Retryable
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
----
By default, the method invocation will be retried for any exception thrown: with at most
3 retry attempts (`maxRetries = 3`) after an initial failure, and a delay of 1 second
between attempts. If all attempts have failed and the retry policy has been exhausted,
the last original exception from the target method will be propagated to the caller.
[NOTE]
====
A `@Retryable` method will be invoked at least once and retried at most `maxRetries`
times, where `maxRetries` is the maximum number of retry attempts. Specifically,
`total attempts = 1 initial attempt + maxRetries attempts`.
For example, if `maxRetries` is set to `4`, the `@Retryable` method will be invoked at
least once and at most 5 times.
====
This can be specifically adapted for every method if necessary — for example, by narrowing
the exceptions to retry via the `includes` and `excludes` attributes. The supplied
exception types will be matched against an exception thrown by a failed invocation as well
as nested causes.
[source,java,indent=0,subs="verbatim,quotes"]
----
@Retryable(MessageDeliveryException.class)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
----
NOTE: `@Retryable(MessageDeliveryException.class)` is a shortcut for
`@Retryable(includes{nbsp}={nbsp}MessageDeliveryException.class)`.
[TIP]
====
For advanced use cases, you can specify a custom `MethodRetryPredicate` via the
`predicate` attribute in `@Retryable`, and the predicate will be used to determine whether
to retry a failed method invocation based on a `Method` and a given `Throwable` for
example, by checking the message of the `Throwable`.
Custom predicates can be combined with `includes` and `excludes`; however, custom
predicates will always be applied after `includes` and `excludes` have been applied.
====
Or for 4 retry attempts and an exponential back-off strategy with a bit of jitter:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Retryable(
includes = MessageDeliveryException.class,
maxRetries = 4,
delay = 100,
jitter = 10,
multiplier = 2,
maxDelay = 1000)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
----
Last but not least, `@Retryable` also works for reactive methods with a reactive return
type, decorating the pipeline with Reactor's retry capabilities:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Retryable(maxRetries = 4, delay = 100)
public Mono<Void> sendNotification() {
return Mono.from(...); // <1>
}
----
<1> This raw `Mono` will get decorated with a retry spec.
For details on the various characteristics, see the available annotation attributes in
{spring-framework-api}/resilience/annotation/Retryable.html[`@Retryable`].
TIP: Several attributes in `@Retryable` have `String` variants that provide property
placeholder and SpEL support, as an alternative to the specifically typed annotation
attributes used in the above examples.
[TIP]
====
During `@Retryable` processing, Spring publishes a `MethodRetryEvent` for every exception
coming out of the target method. This can be used to track/log all original exceptions
whereas the caller of the `@Retryable` method will only ever see the last exception.
====
[[resilience-annotations-concurrencylimit]]
== `@ConcurrencyLimit`
{spring-framework-api}/resilience/annotation/ConcurrencyLimit.html[`@ConcurrencyLimit`] is
an annotation that specifies a concurrency limit for an individual method (with the
annotation declared at the method level), or for all proxy-invoked methods in a given
class hierarchy (with the annotation declared at the type level).
[source,java,indent=0,subs="verbatim,quotes"]
----
@ConcurrencyLimit(10)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
----
This is meant to protect the target resource from being accessed from too many threads at
the same time, similar to the effect of a pool size limit for a thread pool or a
connection pool that blocks access if its limit is reached.
You may optionally set the limit to `1`, effectively locking access to the target bean
instance:
[source,java,indent=0,subs="verbatim,quotes"]
----
@ConcurrencyLimit(1)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
----
Such limiting is particularly useful with Virtual Threads where there is generally no
thread pool limit in place. For asynchronous tasks, this can be constrained on
{spring-framework-api}/core/task/SimpleAsyncTaskExecutor.html[`SimpleAsyncTaskExecutor`].
For synchronous invocations, this annotation provides equivalent behavior through
{spring-framework-api}/aop/interceptor/ConcurrencyThrottleInterceptor.html[`ConcurrencyThrottleInterceptor`]
which has been available since Spring Framework 1.0 for programmatic use with the AOP
framework.
TIP: `@ConcurrencyLimit` also has a `limitString` attribute that provides property
placeholder and SpEL support, as an alternative to the `int` based examples above.
[[resilience-annotations-configuration]]
== Enabling Resilient Methods
Like many of Spring's core annotation-based features, `@Retryable` and `@ConcurrencyLimit`
are designed as metadata that you can choose to honor or ignore. The most convenient way
to enable processing of the resilience annotations is to declare
{spring-framework-api}/resilience/annotation/EnableResilientMethods.html[`@EnableResilientMethods`]
on a corresponding `@Configuration` class.
Alternatively, these annotations can be individually enabled by defining a
`RetryAnnotationBeanPostProcessor` or a `ConcurrencyLimitBeanPostProcessor` bean in the
context.
[[resilience-programmatic-retry]]
== Programmatic Retry Support
In contrast to <<resilience-annotations-retryable>> which provides a declarative approach
for specifying retry semantics for methods within beans registered in the
`ApplicationContext`,
{spring-framework-api}/core/retry/RetryTemplate.html[`RetryTemplate`] provides a
programmatic API for retrying arbitrary blocks of code.
Specifically, a `RetryTemplate` executes and potentially retries a
{spring-framework-api}/core/retry/Retryable.html[`Retryable`] operation based on a
configured {spring-framework-api}/core/retry/RetryPolicy.html[`RetryPolicy`].
[source,java,indent=0,subs="verbatim,quotes"]
----
var retryTemplate = new RetryTemplate(); // <1>
retryTemplate.invoke(
() -> jmsClient.destination("notifications").send(...));
----
<1> Implicitly uses `RetryPolicy.withDefaults()`.
By default, a retryable operation will be retried for any exception thrown: with at most
3 retry attempts (`maxRetries = 3`) after an initial failure, and a delay of 1 second
between attempts.
[NOTE]
====
A retryable operation will be executed at least once and retried at most `maxRetries`
times, where `maxRetries` is the maximum number of retry attempts. Specifically,
`total attempts = 1 initial attempt + maxRetries attempts`.
For example, if `maxRetries` is set to `4`, the retryable operation will be invoked at
least once and at most 5 times.
====
If you only need to customize the number of retry attempts, you can use the
`RetryPolicy.withMaxRetries()` factory method as demonstrated below.
[source,java,indent=0,subs="verbatim,quotes"]
----
var retryTemplate = new RetryTemplate(RetryPolicy.withMaxRetries(4)); // <1>
retryTemplate.invoke(
() -> jmsClient.destination("notifications").send(...));
----
<1> Explicitly uses `RetryPolicy.withMaxRetries(4)`.
If you need to narrow the types of exceptions to retry, that can be achieved via the
`includes()` and `excludes()` builder methods. The supplied exception types will be
matched against an exception thrown by a failed operation as well as nested causes.
[source,java,indent=0,subs="verbatim,quotes"]
----
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class) // <1>
.excludes(...) // <2>
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.invoke(
() -> jmsClient.destination("notifications").send(...));
----
<1> Specify one or more exception types to include.
<2> Specify one or more exception types to exclude.
[TIP]
====
For advanced use cases, you can specify a custom `Predicate<Throwable>` via the
`predicate()` method in the `RetryPolicy.Builder`, and the predicate will be used to
determine whether to retry a failed operation based on a given `Throwable` for example,
by checking the message of the `Throwable`.
Custom predicates can be combined with `includes` and `excludes`; however, custom
predicates will always be applied after `includes` and `excludes` have been applied.
====
The following example demonstrates how to configure a `RetryPolicy` with 4 retry attempts
and an exponential back-off strategy with a bit of jitter.
[source,java,indent=0,subs="verbatim,quotes"]
----
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class)
.maxRetries(4)
.delay(Duration.ofMillis(100))
.jitter(Duration.ofMillis(10))
.multiplier(2)
.maxDelay(Duration.ofSeconds(1))
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.invoke(
() -> jmsClient.destination("notifications").send(...));
----
[TIP]
====
Although the factory methods and builder API for `RetryPolicy` cover most common
configuration scenarios, you can implement a custom `RetryPolicy` for complete control
over the types of exceptions that should trigger a retry as well as the
{spring-framework-api}/util/backoff/BackOff.html[`BackOff`] strategy to use. Note that
you can also configure a customized `BackOff` strategy via the `backOff()` method in
the `RetryPolicy.Builder`.
====
Note that the examples above apply a pattern similar to `@Retryable` method invocations
where the last original exception will be propagated to the caller, using the `invoke`
variants on `RetryTemplate` which are available with and without a return value.
The callback may throw unchecked exceptions, the last one of which is exposed for
direct handling on the caller side:
[source,java,indent=0,subs="verbatim,quotes"]
----
try {
retryTemplate.invoke(
() -> jmsClient.destination("notifications").send(...));
}
catch (MessageDeliveryException ex) {
// coming out of the original JmsClient send method
}
----
[source,java,indent=0,subs="verbatim,quotes"]
----
try {
var result = retryTemplate.invoke(() -> {
jmsClient.destination("notifications").send(...);
return "result";
});
}
catch (MessageDeliveryException ex) {
// coming out of the original JmsClient send method
}
----
`RetryTemplate` instances are very light and can be created on the fly,
potentially with a specific retry policy to use for a given invocation:
[source,java,indent=0,subs="verbatim,quotes"]
----
try {
new RetryTemplate(RetryPolicy.withMaxRetries(4)).invoke(
() -> jmsClient.destination("notifications").send(...));
}
catch (MessageDeliveryException ex) {
// coming out of the original JmsClient send method
}
----
For deeper interaction, you may use RetryTemplate's `execute` method. The caller will
have to handle the checked `RetryException` thrown by `RetryTemplate`, exposing the
outcome of all attempts:
[source,java,indent=0,subs="verbatim,quotes"]
----
try {
var result = retryTemplate.execute(() -> {
jmsClient.destination("notifications").send(...);
return "result";
});
}
catch (RetryException ex) {
// ex.getExceptions() / ex.getLastException() ...
}
----
A {spring-framework-api}/core/retry/RetryListener.html[`RetryListener`] can be registered
with a `RetryTemplate` to react to key retry steps (before or after a retry attempt etc.)
or simply to every invocation attempt, being able to track all exceptions coming out of
the callback and all retry outcomes (exhaustion, interruption, timeout). This is
particularly useful when using `invoke` where no retry state other than the last
original exception is exposed otherwise:
[source,java,indent=0,subs="verbatim,quotes"]
----
var retryTemplate = new RetryTemplate();
retryTemplate.setRetryListener(new RetryListener() {
@Override
public void onRetryableExecution(RetryPolicy retryPolicy, Retryable<?> retryable, RetryState retryState) {
...
}
});
retryTemplate.invoke(
() -> jmsClient.destination("notifications").send(...));
----
You can also compose multiple listeners via a
{spring-framework-api}/core/retry/support/CompositeRetryListener.html[`CompositeRetryListener`].
@@ -1,47 +0,0 @@
[[spring-jcl]]
= Logging
Spring comes with its own Commons Logging bridge implemented
in the `spring-jcl` module. The implementation checks for the presence of the Log4j 2.x
API and the SLF4J 1.7 API in the classpath and uses the first one of those found as the
logging implementation, falling back to the Java platform's core logging facilities (also
known as _JUL_ or `java.util.logging`) if neither Log4j 2.x nor SLF4J is available.
Put Log4j 2.x or Logback (or another SLF4J provider) in your classpath, without any extra
bridges, and let the framework auto-adapt to your choice. For further information see the
{spring-boot-docs-ref}/features/logging.html[Spring
Boot Logging Reference Documentation].
[NOTE]
====
Spring's Commons Logging variant is only meant to be used for infrastructure logging
purposes in the core framework and in extensions.
For logging needs within application code, prefer direct use of Log4j 2.x, SLF4J, or JUL.
====
A `Log` implementation may be retrieved via `org.apache.commons.logging.LogFactory` as in
the following example.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MyBean {
private final Log log = LogFactory.getLog(getClass());
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MyBean {
private val log = LogFactory.getLog(javaClass)
// ...
}
----
======
@@ -310,9 +310,11 @@ Java::
List<Integer> input = ...
cs.convert(input,
TypeDescriptor.forObject(input), // List<Integer> type descriptor
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)), // <1>
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))); // <2>
----
<1> `List<Integer>` type descriptor
<2> `List<String>` type descriptor
Kotlin::
+
@@ -322,9 +324,11 @@ Kotlin::
val input: List<Integer> = ...
cs.convert(input,
TypeDescriptor.forObject(input), // List<Integer> type descriptor
TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(String::class.java)))
TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(Integer::class.java)), // <1>
TypeDescriptor.collection(List::class.java, TypeDescriptor.valueOf(String::class.java))) // <2>
----
<1> `List<Integer>` type descriptor
<2> `List<String>` type descriptor
======
Note that `DefaultConversionService` automatically registers converters that are
@@ -1,20 +1,20 @@
[[beans-binding]]
[[data-binding]]
= Data Binding
Data binding is useful for binding user input to a target object where user input is a map
with property paths as keys, following xref:beans-beans-conventions[JavaBeans conventions].
with property paths as keys, following xref:data-binding-conventions[JavaBeans conventions].
`DataBinder` is the main class that supports this, and it provides two ways to bind user
input:
- xref:beans-constructor-binding[Constructor binding] - bind user input to a public data
constructor, looking up constructor argument values in the user input.
- xref:beans-beans[Property binding] - bind user input to setters, matching keys from the
user input to properties of the target object structure.
- xref:data-binding-constructor-binding[Constructor binding] - bind user input to a
public data constructor, looking up constructor argument values in the user input.
- xref:data-binding-property-binding[Property binding] - bind user input to setters,
matching keys from the user input to properties of the target object structure.
You can apply both constructor and property binding or only one.
[[beans-constructor-binding]]
[[data-binding-constructor-binding]]
== Constructor Binding
To use constructor binding:
@@ -32,7 +32,7 @@ WebFlux support a custom name mapping through the `@BindParam` annotation on con
parameters or fields if present. If necessary, you can also configure a `NameResolver` on
`DataBinder` to customize the argument name to use.
xref:beans-beans-conventions[Type conversion] is applied as needed to convert user input.
xref:data-binding-conventions[Type conversion] is applied as needed to convert user input.
If the constructor parameter is an object, it is constructed recursively in the same
manner, but through a nested property path. That means constructor binding creates both
the target object and any objects it contains.
@@ -46,9 +46,7 @@ If the target is created successfully, then `target` is set to the created insta
after the call to `construct`.
[[beans-beans]]
[[data-binding-property-binding]]
== Property Binding with `BeanWrapper`
The `org.springframework.beans` package adheres to the JavaBeans standard.
@@ -74,15 +72,14 @@ The way the `BeanWrapper` works is partly indicated by its name: it wraps a bean
perform actions on that bean, such as setting and retrieving properties.
[[beans-beans-conventions]]
[[data-binding-conventions]]
=== Setting and Getting Basic and Nested Properties
Setting and getting properties is done through the `setPropertyValue` and
`getPropertyValue` overloaded method variants of `BeanWrapper`. See their Javadoc for
details. The below table shows some examples of these conventions:
[[beans-beans-conventions-properties-tbl]]
[[data-binding-conventions-properties-tbl]]
.Examples of properties
|===
| Expression| Explanation
@@ -106,7 +103,7 @@ details. The below table shows some examples of these conventions:
(This next section is not vitally important to you if you do not plan to work with
the `BeanWrapper` directly. If you use only the `DataBinder` and the `BeanFactory`
and their default implementations, you should skip ahead to the
xref:core/validation/beans-beans.adoc#beans-beans-conversion[section on `PropertyEditors`].)
xref:core/validation/data-binding.adoc#data-binding-conversion[section on `PropertyEditors`].)
The following two example classes use the `BeanWrapper` to get and set
properties:
@@ -239,9 +236,8 @@ Kotlin::
======
[[beans-beans-conversion]]
== ``PropertyEditor``'s
[[data-binding-conversion]]
== ``PropertyEditor``s
Spring uses the concept of a `PropertyEditor` to effect the conversion between an
`Object` and a `String`. It can be handy
@@ -272,7 +268,7 @@ package. Most, (but not all, as indicated in the following table) are, by defaul
still register your own variant to override the default one. The following table describes
the various `PropertyEditor` implementations that Spring provides:
[[beans-beans-property-editors-tbl]]
[[data-binding-property-editors-tbl]]
.Built-in `PropertyEditor` Implementations
[cols="30%,70%"]
|===
@@ -351,10 +347,10 @@ recognized and used as the `PropertyEditor` for `Something`-typed properties.
[literal,subs="verbatim,quotes"]
----
com
chank
pop
Something
SomethingEditor // the PropertyEditor for the Something class
└── example
└── things
├── *Something*
└── *SomethingEditor* // the PropertyEditor for the Something class
----
Note that you can also use the standard `BeanInfo` JavaBeans mechanism here as well
@@ -366,10 +362,10 @@ following example uses the `BeanInfo` mechanism to explicitly register one or mo
[literal,subs="verbatim,quotes"]
----
com
chank
pop
Something
SomethingBeanInfo // the BeanInfo for the Something class
└── example
└── things
├── *Something*
└── *SomethingBeanInfo* // the BeanInfo for the Something class
----
The following Java source code for the referenced `SomethingBeanInfo` class
@@ -426,8 +422,8 @@ Kotlin::
======
[[beans-beans-conversion-customeditor-registration]]
=== Custom ``PropertyEditor``'s
[[data-binding-conversion-customeditor-registration]]
=== Custom ``PropertyEditor``s
When setting bean properties as string values, a Spring IoC container ultimately uses
standard JavaBeans `PropertyEditor` implementations to convert these strings to the complex type of the
@@ -451,7 +447,7 @@ where it can be automatically detected and applied.
Note that all bean factories and application contexts automatically use a number of
built-in property editors, through their use of a `BeanWrapper` to
handle property conversions. The standard property editors that the `BeanWrapper`
registers are listed in the xref:core/validation/beans-beans.adoc#beans-beans-conversion[previous section].
registers are listed in the xref:core/validation/data-binding.adoc#data-binding-conversion[previous section].
Additionally, ``ApplicationContext``s also override or add additional editors to handle
resource lookups in a manner appropriate to the specific application context type.
@@ -569,7 +565,7 @@ Finally, the following example shows how to use `CustomEditorConfigurer` to regi
</bean>
----
[[beans-beans-conversion-customeditor-registration-per]]
[[data-binding-conversion-customeditor-registration-per]]
=== `PropertyEditorRegistrar`
Another mechanism for registering property editors with the Spring container is to
@@ -580,7 +576,7 @@ You can write a corresponding registrar and reuse it in each case.
`PropertyEditorRegistry`, an interface that is implemented by the Spring `BeanWrapper`
(and `DataBinder`). `PropertyEditorRegistrar` instances are particularly convenient
when used in conjunction with `CustomEditorConfigurer` (described
xref:core/validation/beans-beans.adoc#beans-beans-conversion-customeditor-registration[here]), which exposes a property
xref:core/validation/data-binding.adoc#data-binding-conversion-customeditor-registration[here]), which exposes a property
called `setPropertyEditorRegistrars(..)`. `PropertyEditorRegistrar` instances added
to a `CustomEditorConfigurer` in this fashion can easily be shared with `DataBinder` and
Spring MVC controllers. Furthermore, it avoids the need for synchronization on custom
@@ -1,7 +1,7 @@
[[validation-conversion]]
= Resolving Codes to Error Messages
[[validation-error-code-resolution]]
= Resolving Error Codes to Error Messages
We covered databinding and validation. This section covers outputting messages that correspond
We covered data binding and validation. This section covers outputting messages that correspond
to validation errors. In the example shown in the xref:core/validation/validator.adoc[preceding section],
we rejected the `name` and `age` fields. If we want to output the error messages by using a
`MessageSource`, we can do so using the error code we provide when rejecting the field
@@ -1,5 +1,5 @@
[[validator]]
= Validation by Using Spring's Validator Interface
= Validation Using Spring's Validator Interface
Spring features a `Validator` interface that you can use to validate objects. The
`Validator` interface works by using an `Errors` object so that, while validating,
@@ -15,7 +15,7 @@ configuration options. You should instantiate the `SimpleJdbcInsert` in the data
layer's initialization method. For this example, the initializing method is the
`setDataSource` method. You do not need to subclass the `SimpleJdbcInsert` class. Instead,
you can create a new instance and set the table name by using the `withTableName` method.
Configuration methods for this class follow the `fluid` style that returns the instance
Configuration methods for this class follow the `fluent` style that returns the instance
of the `SimpleJdbcInsert`, which lets you chain all configuration methods. The following
example uses only one configuration method (we show examples of multiple methods later):
@@ -349,11 +349,11 @@ parameters return the data read from the table.
You can declare `SimpleJdbcCall` in a manner similar to declaring `SimpleJdbcInsert`. You
should instantiate and configure the class in the initialization method of your data-access
layer. Compared to the `StoredProcedure` class, you need not create a subclass
and you need not to declare parameters that can be looked up in the database metadata.
The following example of a `SimpleJdbcCall` configuration uses the preceding stored
procedure (the only configuration option, in addition to the `DataSource`, is the name
of the stored procedure):
layer. In contrast to the `StoredProcedure` class, you do not need to create a subclass,
and you do not need to declare parameters that can be looked up in the database metadata.
The following `SimpleJdbcCall` configuration example uses the preceding stored procedure.
The only configuration option (other than the `DataSource`) is the name of the stored
procedure.
[tabs]
======
@@ -1,7 +1,7 @@
[[orm-hibernate]]
= Hibernate
We start with a coverage of https://hibernate.org/[Hibernate 5] in a Spring environment,
We start with a coverage of https://hibernate.org/[Hibernate] in a Spring environment,
using it to demonstrate the approach that Spring takes towards integrating OR mappers.
This section covers many issues in detail and shows different variations of DAO
implementations and transaction demarcation. Most of these patterns can be directly
@@ -10,13 +10,12 @@ cover the other ORM technologies and show brief examples.
[NOTE]
====
As of Spring Framework 6.0, Spring requires Hibernate ORM 5.5+ for Spring's
`HibernateJpaVendorAdapter` as well as for a native Hibernate `SessionFactory` setup.
We recommend Hibernate ORM 5.6 as the last feature branch in that Hibernate generation.
As of Spring Framework 7.0, Spring requires Hibernate ORM 7.x for Spring's
`HibernateJpaVendorAdapter`.
Hibernate ORM 6.x is primarily supported as a JPA provider (`HibernateJpaVendorAdapter`).
Plain `SessionFactory` setup with the `orm.hibernate5` package is tolerated for migration
purposes. We recommend Hibernate ORM 6.x with JPA-style setup for new development projects.
The `org.springframework.orm.jpa.hibernate` package supersedes the former `orm.hibernate5`:
now for use with Hibernate ORM 7.x, tightly integrated with `HibernateJpaVendorAdapter`
as well as supporting Hibernate's native `SessionFactory.getCurrentSession()` style.
====
@@ -43,7 +42,7 @@ JDBC `DataSource` and a Hibernate `SessionFactory` on top of it:
<property name="password" value=""/>
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<bean id="mySessionFactory" class="org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="mappingResources">
<list>
@@ -271,7 +270,7 @@ processing at runtime. The following example shows how to do so:
<!-- SessionFactory, DataSource, etc. omitted -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
class="org.springframework.orm.jpa.hibernate.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
@@ -301,7 +300,7 @@ and an example for a business method implementation:
----
<beans>
<bean id="myTxManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<bean id="myTxManager" class="org.springframework.orm.jpa.hibernate.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory"/>
</bean>
@@ -8,7 +8,7 @@ danger of undue coupling, because code that is meant to be used transactionally
almost always deployed that way anyway.
NOTE: The standard `jakarta.transaction.Transactional` annotation is also supported as
a drop-in replacement to Spring's own annotation. Please refer to the JTA documentation
a drop-in replacement for Spring's own annotation. Please refer to the JTA documentation
for more details.
The ease-of-use afforded by the use of the `@Transactional` annotation is best
@@ -89,47 +89,16 @@ annotation in a `@Configuration` class. See the
{spring-framework-api}/transaction/annotation/EnableTransactionManagement.html[javadoc]
for full details.
In XML configuration, the `<tx:annotation-driven/>` tag provides similar convenience:
The following example shows the configuration needed to enable annotation-driven transaction management:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
include-code::./AppConfig[tag=snippet,indent=0]
<!-- this is the service object that we want to make transactional -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<!-- a TransactionManager is still required -->
<tx:annotation-driven transaction-manager="txManager"/> <1>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- other <bean/> definitions here -->
</beans>
----
<1> The line that makes the bean instance transactional.
TIP: You can omit the `transaction-manager` attribute in the `<tx:annotation-driven/>`
tag if the bean name of the `TransactionManager` that you want to wire in has the name
`transactionManager`. If the `TransactionManager` bean that you want to dependency-inject
has any other name, you have to use the `transaction-manager` attribute, as in the
preceding example.
TIP: In programmatic configuration, the `@EnableTransactionManagement` annotation uses any
`TransactionManager` bean in the context. In XML configuration, you can omit
the `transaction-manager` attribute in the `<tx:annotation-driven/>` tag if the bean
name of the `TransactionManager` that you want to wire in has the name `transactionManager`.
If the `TransactionManager` bean has any other name, you have to use the
`transaction-manager` attribute explicitly, as in the preceding example.
Reactive transactional methods use reactive return types in contrast to imperative
programming arrangements as the following listing shows:
@@ -234,8 +203,10 @@ on an interface, a class definition, or a method on a class. However, the mere p
of the `@Transactional` annotation is not enough to activate the transactional behavior.
The `@Transactional` annotation is merely metadata that can be consumed by corresponding
runtime infrastructure which uses that metadata to configure the appropriate beans with
transactional behavior. In the preceding example, the `<tx:annotation-driven/>` element
switches on actual transaction management at runtime.
transactional behavior. In the preceding examples that use programmatic configuration,
the `@EnableTransactionManagement` annotation switches on actual transaction management
at runtime. Whereas, in the preceding example that uses XML configuration, the
`<tx:annotation-driven/>` element switches on actual transaction management at runtime.
TIP: The Spring team recommends that you annotate methods of concrete classes with the
`@Transactional` annotation, rather than relying on annotated methods in interfaces,
@@ -86,11 +86,13 @@ rollback rules may be configured via the `rollbackFor`/`noRollbackFor` and
`rollbackForClassName`/`noRollbackForClassName` attributes, which allow rules to be
defined based on exception types or patterns, respectively.
When a rollback rule is defined with an exception type, that type will be used to match
against the type of a thrown exception and its super types, providing type safety and
avoiding any unintentional matches that may occur when using a pattern. For example, a
value of `jakarta.servlet.ServletException.class` will only match thrown exceptions of
type `jakarta.servlet.ServletException` and its subclasses.
When a rollback rule is defined with an exception type for example, via `rollbackFor`
that type will be used to match against the type of a thrown exception. Specifically,
given a configured exception type `C`, a thrown exception of type `T` will be considered
a match against `C` if `T` is equal to `C` or a subclass of `C`. This provides type
safety and avoids any unintentional matches that may occur when using a pattern. For
example, a value of `jakarta.servlet.ServletException.class` will only match thrown
exceptions of type `jakarta.servlet.ServletException` and its subclasses.
When a rollback rule is defined with an exception pattern, the pattern can be a fully
qualified class name or a substring of a fully qualified class name for an exception type
@@ -22,7 +22,7 @@ where all the underlying resources have to participate in the service-level tran
NOTE: By default, a participating transaction joins the characteristics of the outer scope,
silently ignoring the local isolation level, timeout value, or read-only flag (if any).
Consider switching the `validateExistingTransactions` flag to `true` on your transaction
Consider switching the `validateExistingTransaction` flag to `true` on your transaction
manager if you want isolation level declarations to be rejected when participating in
an existing transaction with a different isolation level. This non-lenient mode also
rejects read-only mismatches (that is, an inner read-write transaction that tries to participate
@@ -212,7 +212,7 @@ example declares `sessionFactory` and `txManager` beans:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<bean id="sessionFactory" class="org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
@@ -226,7 +226,7 @@ example declares `sessionFactory` and `txManager` beans:
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<bean id="txManager" class="org.springframework.orm.jpa.hibernate.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
----
@@ -238,7 +238,7 @@ transaction coordinator and possibly also its connection release mode configurat
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<bean id="sessionFactory" class="org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
@@ -262,7 +262,7 @@ for enforcing the same defaults:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<bean id="sessionFactory" class="org.springframework.orm.jpa.hibernate.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
@@ -0,0 +1,120 @@
[[aot-cache]]
= JVM AOT Cache
:page-aliases: integration/class-data-sharing.adoc
:page-aliases: integration/cds.adoc
The ahead-of-time cache is a JVM feature introduced in Java 24 via
https://openjdk.org/jeps/483[JEP 483] that can help reduce the startup time and memory
footprint of Java applications. AOT cache is a natural evolution of
https://docs.oracle.com/en/java/javase/17/vm/class-data-sharing.html[Class Data Sharing (CDS)].
Spring Framework supports both CDS and AOT cache, and it is recommended that you use the
latter if available in the JVM version you are using (Java 24+).
To use this feature, an AOT cache should be created for the particular classpath of the
application. It is possible to create this cache on the deployed instance, or during a
training run performed for example when packaging the application thanks to a hook-point
provided by the Spring Framework to ease such use case. Once the cache is available, users
should opt in to use it via a JVM flag.
NOTE: If you are using Spring Boot, it is highly recommended to leverage its
{spring-boot-docs-ref}/packaging/efficient.html#packaging.efficient.unpacking[executable JAR unpacking support]
which is designed to fulfill the class loading requirements of both the AOT cache and CDS.
== Creating the cache
An AOT cache can typically be created when the application exits. The Spring Framework
provides a mode of operation where the process can exit automatically once the
`ApplicationContext` has refreshed. In this mode, all non-lazy initialized singletons
have been instantiated, and `InitializingBean#afterPropertiesSet` callbacks have been
invoked; but the lifecycle has not started, and the `ContextRefreshedEvent` has not yet
been published.
To create the cache during the training run, it is possible to specify the `-Dspring.context.exit=onRefresh`
JVM flag to start and then exit your Spring application once the
`ApplicationContext` has refreshed:
--
[tabs]
======
AOT cache (Java 25+)::
+
[source,bash,subs="verbatim,quotes"]
----
java -XX:AOTCacheOutput=app.aot -Dspring.context.exit=onRefresh -jar application.jar ...
----
AOT cache (Java 24)::
+
[source,bash,subs="verbatim,quotes"]
----
# Both commands need to be run with the same classpath
java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -Dspring.context.exit=onRefresh ...
java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf -XX:AOTCache=app.aot ...
----
CDS::
+
[source,bash,subs="verbatim,quotes"]
----
# To create a CDS archive, your JDK/JRE must have a base image
java -XX:ArchiveClassesAtExit=app.jsa -Dspring.context.exit=onRefresh ...
----
======
--
NOTE: With Java 25+, AOT cache stores, among other things, the
https://openjdk.org/jeps/515[method profiling information]. Therefore, to benefit of this capability,
it is recommended to create an AOT cache for an application that experienced a portion of a
production-like workflow instead of using the `-Dspring.context.exit=onRefresh` flag which designed to
optimize only the startup of your application.
== Using the cache
Once the cache file has been created, you can use it to start your application faster:
--
[tabs]
======
AOT cache::
+
[source,bash,subs="verbatim"]
----
# With the same classpath (or a superset) tan the training run
java -XX:AOTCache=app.aot ...
----
CDS::
+
[source,bash,subs="verbatim"]
----
# With the same classpath (or a superset) tan the training run
java -XX:SharedArchiveFile=app.jsa ...
----
======
--
Pay attention to the logs and the startup time to check if the AOT cache is used successfully.
To figure out how effective the cache is, you can enable class loading logs by adding
an extra attribute: `-Xlog:class+load:file=aot-cache.log`. This creates an `aot-cache.log` with
every attempt to load a class and its source. Classes that are loaded from the cache should have
a "shared objects file" source, as shown in the following example:
[source,shell,subs="verbatim"]
----
[0.151s][info][class,load] org.springframework.core.env.EnvironmentCapable source: shared objects file
[0.151s][info][class,load] org.springframework.beans.factory.BeanFactory source: shared objects file
[0.151s][info][class,load] org.springframework.beans.factory.ListableBeanFactory source: shared objects file
[0.151s][info][class,load] org.springframework.beans.factory.HierarchicalBeanFactory source: shared objects file
[0.151s][info][class,load] org.springframework.context.MessageSource source: shared objects file
----
If the AOT cache cannot be enabled or if you have a large number of classes that are not loaded from
the cache, make sure that the following conditions are fulfilled when creating and using the cache:
- The very same JVM must be used.
- The classpath must be specified as a JAR or a list of JARs, and avoid the usage of directories and `*` wildcard characters.
- The timestamps of the JARs must be preserved.
- When using the cache, the classpath must be the same as the one used to create it, in the same order.
Additional JARs or directories can be specified *at the end* (but will not be cached).
@@ -1,16 +1,11 @@
[[appendix]]
= Appendix
[[appendix.xsd-schemas]]
== XML Schemas
This part of the appendix lists XML schemas related to integration technologies.
[[appendix.xsd-schemas-jee]]
=== The `jee` Schema
@@ -172,7 +167,7 @@ different properties with `jee`:
The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless Session Bean.
The following example shows how to configures a reference to a local EJB Stateless Session Bean
The following example shows how to configure a reference to a local EJB Stateless Session Bean
without `jee`:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -184,7 +179,7 @@ without `jee`:
</bean>
----
The following example shows how to configures a reference to a local EJB Stateless Session Bean
The following example shows how to configure a reference to a local EJB Stateless Session Bean
with `jee`:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -200,7 +195,7 @@ with `jee`:
The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless Session Bean.
The following example shows how to configures a reference to a local EJB Stateless Session Bean
The following example shows how to configure a reference to a local EJB Stateless Session Bean
and a number of properties without `jee`:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -215,7 +210,7 @@ and a number of properties without `jee`:
</bean>
----
The following example shows how to configures a reference to a local EJB Stateless Session Bean
The following example shows how to configure a reference to a local EJB Stateless Session Bean
and a number of properties with `jee`:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -234,7 +229,7 @@ and a number of properties with `jee`:
The `<jee:remote-slsb/>` element configures a reference to a `remote` EJB Stateless Session Bean.
The following example shows how to configures a reference to a remote EJB Stateless Session Bean
The following example shows how to configure a reference to a remote EJB Stateless Session Bean
without `jee`:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -251,7 +246,7 @@ without `jee`:
</bean>
----
The following example shows how to configures a reference to a remote EJB Stateless Session Bean
The following example shows how to configure a reference to a remote EJB Stateless Session Bean
with `jee`:
[source,xml,indent=0,subs="verbatim,quotes"]
@@ -313,7 +308,7 @@ xref:integration/jmx/naming.adoc#jmx-context-mbeanexport[Configuring Annotation-
=== The `cache` Schema
You can use the `cache` elements to enable support for Spring's `@CacheEvict`, `@CachePut`,
and `@Caching` annotations. It it also supports declarative XML-based caching. See
and `@Caching` annotations. The `cache` schema also supports declarative XML-based caching. See
xref:integration/cache/annotations.adoc#cache-annotation-enable[Enabling Caching Annotations] and
xref:integration/cache/declarative-xml.adoc[Declarative XML-based Caching] for details.
@@ -35,7 +35,7 @@ xref:integration/cache/store-configuration.adoc#cache-store-configuration-jsr107
[[cache-store-configuration-caffeine]]
== Caffeine Cache
Caffeine is a Java 8 rewrite of Guava's cache, and its implementation is located in the
Caffeine is a rewrite of Guava's cache, and its implementation is located in the
`org.springframework.cache.caffeine` package and provides access to several features
of Caffeine.
@@ -1,74 +0,0 @@
[[cds]]
= CDS
:page-aliases: integration/class-data-sharing.adoc
Class Data Sharing (CDS) is a https://docs.oracle.com/en/java/javase/17/vm/class-data-sharing.html[JVM feature]
that can help reduce the startup time and memory footprint of Java applications.
To use this feature, a CDS archive should be created for the particular classpath of the
application. The Spring Framework provides a hook-point to ease the creation of the
archive. Once the archive is available, users should opt in to use it via a JVM flag.
== Creating the CDS Archive
A CDS archive for an application can be created when the application exits. The Spring
Framework provides a mode of operation where the process can exit automatically once the
`ApplicationContext` has refreshed. In this mode, all non-lazy initialized singletons
have been instantiated, and `InitializingBean#afterPropertiesSet` callbacks have been
invoked; but the lifecycle has not started, and the `ContextRefreshedEvent` has not yet
been published.
To create the archive, two additional JVM flags must be specified:
* `-XX:ArchiveClassesAtExit=application.jsa`: creates the CDS archive on exit
* `-Dspring.context.exit=onRefresh`: starts and then immediately exits your Spring
application as described above
To create a CDS archive, your JDK/JRE must have a base image. If you add the flags above to
your startup script, you may get a warning that looks like this:
[source,shell,indent=0,subs="verbatim"]
----
-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info.
----
The base CDS archive is usually provided out-of-the-box, but can also be created if needed by issuing the following
command:
[source,shell,indent=0,subs="verbatim"]
----
$ java -Xshare:dump
----
== Using the Archive
Once the archive is available, add `-XX:SharedArchiveFile=application.jsa` to your startup
script to use it, assuming an `application.jsa` file in the working directory.
To check if the CDS cache is effective, you can use (for testing purposes only, not in production) `-Xshare:on` which
prints an error message and exits if CDS can't be enabled.
To figure out how effective the cache is, you can enable class loading logs by adding
an extra attribute: `-Xlog:class+load:file=cds.log`. This creates a `cds.log` with every
attempt to load a class and its source. Classes that are loaded from the cache should have
a "shared objects file" source, as shown in the following example:
[source,shell,indent=0,subs="verbatim"]
----
[0.064s][info][class,load] org.springframework.core.env.EnvironmentCapable source: shared objects file (top)
[0.064s][info][class,load] org.springframework.beans.factory.BeanFactory source: shared objects file (top)
[0.064s][info][class,load] org.springframework.beans.factory.ListableBeanFactory source: shared objects file (top)
[0.064s][info][class,load] org.springframework.beans.factory.HierarchicalBeanFactory source: shared objects file (top)
[0.065s][info][class,load] org.springframework.context.MessageSource source: shared objects file (top)
----
If CDS can't be enabled or if you have a large number of classes that are not loaded from the cache, make sure that
the following conditions are fulfilled when creating and using the archive:
- The very same JVM must be used.
- The classpath must be specified as a list of JARs, and avoid the usage of directories and `*` wildcard characters.
- The timestamps of the JARs must be preserved.
- When using the archive, the classpath must be the same than the one used to create the archive, in the same order.
Additional JARs or directories can be specified *at the end* (but won't be cached).
@@ -11,9 +11,7 @@ Spring Framework's email support:
* The https://jakartaee.github.io/mail-api/[Jakarta Mail] library
This library is freely available on the web -- for example, in Maven Central as
`com.sun.mail:jakarta.mail`. Please make sure to use the latest 2.x version (which uses
the `jakarta.mail` package namespace) rather than Jakarta Mail 1.6.x (which uses the
`javax.mail` package namespace).
`org.eclipse.angus:angus-mail`.
****
The Spring Framework provides a helpful utility library for sending email that shields
@@ -26,7 +26,7 @@ behind the scenes for each annotated method, by using a `JmsListenerContainerFac
Such a container is not registered against the application context but can be easily
located for management purposes by using the `JmsListenerEndpointRegistry` bean.
TIP: `@JmsListener` is a repeatable annotation on Java 8, so you can associate
TIP: `@JmsListener` is a repeatable annotation, so you can associate
several JMS destinations with the same method by adding additional `@JmsListener`
declarations to it.
@@ -7,8 +7,8 @@ This describes how to receive messages with JMS in Spring.
[[jms-receiving-sync]]
== Synchronous Receipt
While JMS is typically associated with asynchronous processing, you can
consume messages synchronously. The overloaded `receive(..)` methods provide this
While JMS is typically associated with asynchronous processing, you can consume messages
synchronously. The `receive(..)` methods on `JmsTemplate` and `JmsClient` provide this
functionality. During a synchronous receive, the calling thread blocks until a message
becomes available. This can be a dangerous operation, since the calling thread can
potentially be blocked indefinitely. The `receiveTimeout` property specifies how long
@@ -9,39 +9,7 @@ that takes no destination argument uses the default destination.
The following example uses the `MessageCreator` callback to create a text message from the
supplied `Session` object:
[source,java,indent=0,subs="verbatim,quotes"]
----
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.Queue;
import jakarta.jms.Session;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.JmsTemplate;
public class JmsQueueSender {
private JmsTemplate jmsTemplate;
private Queue queue;
public void setConnectionFactory(ConnectionFactory cf) {
this.jmsTemplate = new JmsTemplate(cf);
}
public void setQueue(Queue queue) {
this.queue = queue;
}
public void simpleSend() {
this.jmsTemplate.send(this.queue, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage("hello queue world");
}
});
}
}
----
include-code::./JmsQueueSender[]
In the preceding example, the `JmsTemplate` is constructed by passing a reference to a
`ConnectionFactory`. As an alternative, a zero-argument constructor and
@@ -84,21 +52,7 @@ gives you access to the message after it has been converted but before it is sen
following example shows how to modify a message header and a property after a
`java.util.Map` is converted to a message:
[source,java,indent=0,subs="verbatim,quotes"]
----
public void sendWithConversion() {
Map<String, String> map = new HashMap<>();
map.put("Name", "Mark");
map.put("Age", new Integer(47));
jmsTemplate.convertAndSend("testQueue", map, new MessagePostProcessor() {
public Message postProcessMessage(Message message) throws JMSException {
message.setIntProperty("AccountID", 1234);
message.setJMSCorrelationID("123-00001");
return message;
}
});
}
----
include-code::./JmsSenderWithConversion[]
This results in a message of the following form:
@@ -120,6 +74,11 @@ MapMessage={
}
----
NOTE: This JMS-specific `org.springframework.jms.support.converter.MessageConverter`
arrangement operates on JMS message types and is responsible for immediate conversion
to `jakarta.jms.TextMessage`, `jakarta.jms.BytesMessage`, etc. For a contract supporting
generic message payloads, use `org.springframework.messaging.converter.MessageConverter`
with `JmsMessagingTemplate` or preferably `JmsClient` as your central delegate instead.
[[jms-sending-callbacks]]
== Using `SessionCallback` and `ProducerCallback` on `JmsTemplate`
@@ -129,3 +88,21 @@ want to perform multiple operations on a JMS `Session` or `MessageProducer`. The
`SessionCallback` and `ProducerCallback` expose the JMS `Session` and `Session` /
`MessageProducer` pair, respectively. The `execute()` methods on `JmsTemplate` run
these callback methods.
[[jms-sending-jmsclient]]
== Sending a Message with `JmsClient`
include-code::./JmsClientSample[]
[[jms-sending-postprocessor]]
== Post-processing outgoing messages
Applications often need to intercept messages before they are sent out, for example to add message properties to all outgoing messages.
The `org.springframework.messaging.core.MessagePostProcessor` based on the spring-messaging `Message` can do that,
when configured on the `JmsClient`. It will be used for all outgoing messages sent with the `send` and `sendAndReceive` methods.
Here is an example of an interceptor adding a "tenantId" property to all outgoing messages.
include-code::./JmsClientWithPostProcessor[]
@@ -4,13 +4,20 @@
This section describes how to use Spring's JMS components.
[[jms-jmstemplate]]
== Using `JmsTemplate`
[[jms-jmstemplate-jmsclient]]
== `JmsTemplate` and `JmsClient`
The `JmsTemplate` class is the central class in the JMS core package. It simplifies the
use of JMS, since it handles the creation and release of resources when sending or
synchronously receiving messages.
`JmsClient` is a new API variant in Spring Framework 7.0, following the design of
`JdbcClient` and co. `JmsClient` builds on `JmsTemplate` for straightforward send
and receive operations with customization options per operation.
[[jms-jmstemplate]]
=== Using `JmsTemplate`
Code that uses the `JmsTemplate` needs only to implement callback interfaces that give them
a clearly defined high-level contract. The `MessageCreator` callback interface creates a
message when given a `Session` provided by the calling code in `JmsTemplate`. To
@@ -43,10 +50,23 @@ and then safely inject this shared reference into multiple collaborators. To be
clear, the `JmsTemplate` is stateful, in that it maintains a reference to a
`ConnectionFactory`, but this state is not conversational state.
[[jms-jmsclient]]
=== Using `JmsClient`
As of Spring Framework 4.1, `JmsMessagingTemplate` is built on top of `JmsTemplate`
and provides an integration with the messaging abstraction -- that is,
`org.springframework.messaging.Message`. This lets you create the message to
send in a generic manner.
and provides an integration with the Spring's common messaging abstraction -- that is,
handling `org.springframework.messaging.Message` for sending and receiving,
throwing `org.springframework.messaging.MessagingException` and with payload conversion
going through `org.springframework.messaging.converter.MessageConverter` (with many
common converter implementations available).
As of Spring Framework 7.0, a fluent API called `JmsClient` is available. This provides
customizable operations around `org.springframework.messaging.Message` and throwing
`org.springframework.messaging.MessagingException`, similar to `JmsMessagingTemplate`,
as well as integration with `org.springframework.messaging.converter.MessageConverter`.
A `JmsClient can either be created for a given `ConnectionFactory` or for a given
`JmsTemplate`, in the latter case reusing its settings by default. See
{spring-framework-api}/jms/core/JmsClient.html[`JmsClient`] for usage examples.
[[jms-connections]]
@@ -1,10 +1,15 @@
[[observability]]
= Observability Support
With https://docs.micrometer.io/micrometer/reference/concepts.html[Micrometer], developers can instrument libraries and applications for metrics (timers, gauges, counters)
that collect statistics about their runtime behavior. Metrics can help you to track error rates, usage patterns, performance, and more.
https://docs.micrometer.io/tracing/reference/[Micrometer can also produce traces], giving you a holistic view of an entire system, crossing application boundaries; you can zoom in on particular user requests and follow their entire completion across applications.
Micrometer defines an {micrometer-docs}/observation.html[Observation concept that enables both Metrics and Traces] in applications.
Metrics support offers a way to create timers, gauges, or counters for collecting statistics about the runtime behavior of your application.
Metrics can help you to track error rates, usage patterns, performance, and more.
Traces provide a holistic view of an entire system, crossing application boundaries; you can zoom in on particular user requests and follow their entire completion across applications.
Each observation will produce:
* https://docs.micrometer.io/micrometer/reference/observation/components.html#micrometer-observation-default-meter-handler[several metrics - a timer, a long task timer and many counters]
* a https://docs.micrometer.io/tracing/reference/glossary.html[span for the current trace]
Spring Framework instruments various parts of its own codebase to publish observations if an `ObservationRegistry` is configured.
You can learn more about {spring-boot-docs-ref}/actuator/observability.html[configuring the observability infrastructure in Spring Boot].
@@ -189,13 +194,13 @@ This observation uses the `io.micrometer.jakarta9.instrument.jms.DefaultJmsProce
[[observability.http-server]]
== HTTP Server instrumentation
HTTP server exchange observations are created with the name `"http.server.requests"` for Servlet and Reactive applications.
HTTP server exchange observations are created with the name `"http.server.requests"` for Servlet and Reactive applications,
or `"http.server.request.duration"` if using the OpenTelemetry convention.
[[observability.http-server.servlet]]
=== Servlet applications
Applications need to configure the `org.springframework.web.filter.ServerHttpObservationFilter` Servlet filter in their application.
It uses the `org.springframework.http.server.observation.DefaultServerRequestObservationConvention` by default, backed by the `ServerRequestObservationContext`.
This will only record an observation as an error if the `Exception` has not been handled by the web framework and has bubbled up to the Servlet filter.
Typically, all exceptions handled by Spring MVC's `@ExceptionHandler` and xref:web/webmvc/mvc-ann-rest-exceptions.adoc[`ProblemDetail` support] will not be recorded with the observation.
@@ -207,6 +212,11 @@ NOTE: Because the instrumentation is done at the Servlet Filter level, the obser
Typically, Servlet container error handling is performed at a lower level and won't have any active observation or span.
For this use case, a container-specific implementation is required, such as a `org.apache.catalina.Valve` for Tomcat; this is outside the scope of this project.
[[observability.http-server.servlet.default]]
==== Default Semantic Convention
It uses the `org.springframework.http.server.observation.DefaultServerRequestObservationConvention` by default, backed by the `ServerRequestObservationContext`.
By default, the following `KeyValues` are created:
.Low cardinality Keys
@@ -228,6 +238,16 @@ By default, the following `KeyValues` are created:
|`http.url` _(required)_|HTTP request URI.
|===
[[observability.http-server.servlet.otel]]
==== OpenTelemetry Semantic Convention
An OpenTelemetry variant is available with `org.springframework.http.server.observation.OpenTelemetryServerRequestObservationConvention`, backed by the `ServerRequestObservationContext`.
This variant complies with the https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/http/http-metrics.md[OpenTelemetry Semantic Conventions for HTTP Metrics (v1.36.0)]
and the https://github.com/open-telemetry/semantic-conventions/blob/v1.36.0/docs/http/http-spans.md[OpenTelemetry Semantic Conventions for HTTP Spans (v1.36.0)].
[[observability.http-server.reactive]]
=== Reactive applications
@@ -3,26 +3,34 @@
The Spring Framework provides the following choices for making calls to REST endpoints:
* xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] - synchronous client with a fluent API.
* xref:integration/rest-clients.adoc#rest-webclient[`WebClient`] - non-blocking, reactive client with fluent API.
* xref:integration/rest-clients.adoc#rest-resttemplate[`RestTemplate`] - synchronous client with template method API.
* xref:integration/rest-clients.adoc#rest-http-interface[HTTP Interface] - annotated interface with generated, dynamic proxy implementation.
* xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] -- synchronous client with a fluent API
* xref:integration/rest-clients.adoc#rest-webclient[`WebClient`] -- non-blocking, reactive client with fluent API
* xref:integration/rest-clients.adoc#rest-resttemplate[`RestTemplate`] -- synchronous client with template method API, now deprecated in favor of `RestClient`
* xref:integration/rest-clients.adoc#rest-http-service-client[HTTP Service Clients] -- annotated interface backed by generated proxy
[[rest-restclient]]
== `RestClient`
The `RestClient` is a synchronous HTTP client that offers a modern, fluent API.
It offers an abstraction over HTTP libraries that allows for convenient conversion from a Java object to an HTTP request, and the creation of objects from an HTTP response.
`RestClient` is a synchronous HTTP client that provides a fluent API to perform requests.
It serves as an abstraction over HTTP libraries, and handles conversion of HTTP request and response content to and from higher level Java objects.
=== Creating a `RestClient`
=== Create a `RestClient`
The `RestClient` is created using one of the static `create` methods.
You can also use `builder()` to get a builder with further options, such as specifying which HTTP library to use (see <<rest-request-factories>>) and which message converters to use (see <<rest-message-conversion>>), setting a default URI, default path variables, default request headers, or `uriBuilderFactory`, or registering interceptors and initializers.
`RestClient` has static `create` shortcut methods.
It also exposes a `builder()` with further options:
Once created (or built), the `RestClient` can be used safely by multiple threads.
- select the HTTP library to use, see <<rest-request-factories>>
- configure message converters, see <<rest-message-conversion>>
- set a baseUrl
- set default request headers, cookies, path variables, API version
- configure an `ApiVersionInserter`
- register interceptors
- register request initializers
The following sample shows how to create a default `RestClient`, and how to build a custom one.
Once created, a `RestClient` is safe to use in multiple threads.
The below shows how to create or build a `RestClient`:
[tabs]
======
@@ -39,6 +47,8 @@ Java::
.defaultUriVariables(Map.of("variable", "foo"))
.defaultHeader("My-Header", "Foo")
.defaultCookie("My-Cookie", "Bar")
.defaultVersion("1.2")
.apiVersionInserter(ApiVersionInserter.fromHeader("API-Version").build())
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build();
@@ -57,23 +67,25 @@ Kotlin::
.defaultUriVariables(mapOf("variable" to "foo"))
.defaultHeader("My-Header", "Foo")
.defaultCookie("My-Cookie", "Bar")
.defaultVersion("1.2")
.apiVersionInserter(ApiVersionInserter.fromHeader("API-Version").build())
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build()
----
======
=== Using the `RestClient`
=== Use the `RestClient`
When making an HTTP request with the `RestClient`, the first thing to specify is which HTTP method to use.
This can be done with `method(HttpMethod)` or with the convenience methods `get()`, `head()`, `post()`, and so on.
To perform an HTTP request, first specify the HTTP method to use.
Use the convenience methods like `get()`, `head()`, `post()`, and others, or `method(HttpMethod)`.
==== Request URL
Next, the request URI can be specified with the `uri` methods.
This step is optional and can be skipped if the `RestClient` is configured with a default URI.
Next, specify the request URI with the `uri` methods.
This is optional, and you can skip this step if you configured a baseUrl through the builder.
The URL is typically specified as a `String`, with optional URI template variables.
The following example configures a GET request to `https://example.com/orders/42`:
The following shows how to perform a request:
[tabs]
======
@@ -108,6 +120,7 @@ For more details on working with and encoding URIs, see xref:web/webmvc/mvc-uri-
If necessary, the HTTP request can be manipulated by adding request headers with `header(String, String)`, `headers(Consumer<HttpHeaders>`, or with the convenience methods `accept(MediaType...)`, `acceptCharset(Charset...)` and so on.
For HTTP requests that can contain a body (`POST`, `PUT`, and `PATCH`), additional methods are available: `contentType(MediaType)`, and `contentLength(long)`.
You can set an API version for the request if the client is configured with `ApiVersionInserter`.
The request body itself can be set by `body(Object)`, which internally uses <<rest-message-conversion>>.
Alternatively, the request body can be set using a `ParameterizedTypeReference`, allowing you to use generics.
@@ -389,6 +402,27 @@ To serialize only a subset of the object properties, you can specify a {baeldung
.toBodilessEntity();
----
==== URL encoded Forms
URL encoded forms, using the `"application/x-www-form-urlencoded"` media type, are useful for sending String key/values over the wire.
This is supported by the `FormHttpMessageConverter`, if the application uses a `MultiValueMap<String, String>` as source instance
or a target type.
For example:
[source,java,indent=0,subs="verbatim"]
----
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.add("project", "Spring Framework");
form.add("module", "spring-web");
ResponseEntity<Void> response = this.restClient.post()
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(form)
.retrieve()
.toBodilessEntity();
----
==== Multipart
To send multipart data, you need to provide a `MultiValueMap<String, Object>` whose values may be an `Object` for part content, a `Resource` for a file part, or an `HttpEntity` for part content with headers.
@@ -406,18 +440,70 @@ For example:
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
// send using RestClient.post or RestTemplate.postForEntity
ResponseEntity<Void> response = this.restClient.post()
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(parts)
.retrieve()
.toBodilessEntity();
----
In most cases, you do not have to specify the `Content-Type` for each part.
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource`, based on the file extension.
If necessary, you can explicitly provide the `MediaType` with an `HttpEntity` wrapper.
Once the `MultiValueMap` is ready, you can use it as the body of a `POST` request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
The `Content-Type` is set to `multipart/form-data` by the `MultipartHttpMessageConverter`.
As seen in the previous section, `MultiValueMap` types can also be used for URL encoded forms.
It is preferable to explicitly set the media type in the `Content-Type` or `Accept` HTTP request headers to ensure that the expected
message converter is used.
`RestClient` can also receive multipart responses.
To decode a multipart response body, use a `ParameterizedTypeReference<MultiValueMap<String, Part>>`.
The decoded map contains `Part` instances where `FormFieldPart` represents form field values
and `FilePart` represents file parts with a `filename()` and a `transferTo()` method.
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim"]
----
MultiValueMap<String, Part> result = this.restClient.get()
.uri("https://example.com/upload")
.accept(MediaType.MULTIPART_FORM_DATA)
.retrieve()
.body(new ParameterizedTypeReference<>() {});
Part field = result.getFirst("fieldPart");
if (field instanceof FormFieldPart formField) {
String fieldValue = formField.value();
}
Part file = result.getFirst("filePart");
if (file instanceof FilePart filePart) {
filePart.transferTo(Path.of("/tmp/" + filePart.filename()));
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim"]
----
val result = this.restClient.get()
.uri("https://example.com/upload")
.accept(MediaType.MULTIPART_FORM_DATA)
.retrieve()
.body(object : ParameterizedTypeReference<MultiValueMap<String, Part>>() {})
val field = result?.getFirst("fieldPart")
if (field is FormFieldPart) {
val fieldValue = field.value()
}
val file = result?.getFirst("filePart")
if (file is FilePart) {
file.transferTo(Path.of("/tmp/" + file.filename()))
}
----
======
If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set to `multipart/form-data` by the `FormHttpMessageConverter`.
If the `MultiValueMap` has `String` values, the `Content-Type` defaults to `application/x-www-form-urlencoded`.
If necessary the `Content-Type` may also be set explicitly.
[[rest-request-factories]]
=== Client Request Factories
@@ -453,7 +539,7 @@ synchronous, asynchronous, and streaming scenarios.
* Non-blocking I/O
* Reactive Streams back pressure
* High concurrency with fewer hardware resources
* Functional-style, fluent API that takes advantage of Java 8 lambdas
* Functional-style, fluent API that takes advantage of lambda expressions
* Synchronous and asynchronous interactions
* Streaming up to or streaming down from a server
@@ -466,7 +552,8 @@ See xref:web/webflux-webclient.adoc[WebClient] for more details.
The `RestTemplate` provides a high-level API over HTTP client libraries in the form of a classic Spring Template class.
It exposes the following groups of overloaded methods:
NOTE: The xref:integration/rest-clients.adoc#rest-restclient[`RestClient`] offers a more modern API for synchronous HTTP access.
WARNING: As of Spring Framework 7.0, `RestTemplate` is deprecated in favor of `RestClient` and will be removed in a future version,
please use the xref:integration/rest-clients.adoc#migrating-to-restclient["Migrating to RestClient"] guide.
For asynchronous and streaming scenarios, consider the reactive xref:web/webflux-webclient.adoc[WebClient].
[[rest-overview-of-resttemplate-methods-tbl]]
@@ -534,10 +621,26 @@ See the xref:integration/observability.adoc#http-client.resttemplate[RestTemplat
Objects passed into and returned from `RestTemplate` methods are converted to and from HTTP messages
with the help of an `HttpMessageConverter`, see <<rest-message-conversion>>.
=== Migrating from `RestTemplate` to `RestClient`
[[migrating-to-restclient]]
=== Migrating to `RestClient`
Applications can adopt `RestClient` in a gradual fashion, first focusing on API usage and then on infrastructure setup.
You can consider the following steps:
1. Create one or more `RestClient` from existing `RestTemplate` instances, like: `RestClient restClient = RestClient.create(restTemplate)`.
Gradually replace `RestTemplate` usage in your application, component by component, by focusing first on issuing requests.
See the table below for API equivalents.
2. Once all client requests go through `RestClient` instances, you can now work on replicating your existing
`RestTemplate` instance creations by using `RestClient.Builder`. Because `RestTemplate` and `RestClient`
share the same infrastructure, you can reuse custom `ClientHttpRequestFactory` or `ClientHttpRequestInterceptor`
in your setup. See xref:integration/rest-clients.adoc#rest-restclient[the `RestClient` builder API].
If no other library is available on the classpath, `RestClient` will choose the `JdkClientHttpRequestFactory`
powered by the modern JDK `HttpClient`, whereas `RestTemplate` would pick the `SimpleClientHttpRequestFactory` that
uses `HttpURLConnection`. This can explain subtle behavior difference at runtime at the HTTP level.
The following table shows `RestClient` equivalents for `RestTemplate` methods.
It can be used to migrate from the latter to the former.
.RestClient equivalents for RestTemplate methods
[cols="1,1", options="header"]
@@ -841,17 +944,24 @@ It can be used to migrate from the latter to the former.
|===
`RestClient` and `RestTemplate` instances share the same behavior when it comes to throwing exceptions
(with the `RestClientException` type being at the top of the hierarchy).
When `RestTemplate` consistently throws `HttpClientErrorException` for "4xx" response statues,
`RestClient` allows for more flexibility with custom xref:integration/rest-clients.adoc#rest-http-service-client-exceptions["status handlers"].
[[rest-http-interface]]
== HTTP Interface
The Spring Framework lets you define an HTTP service as a Java interface with
`@HttpExchange` methods. You can pass such an interface to `HttpServiceProxyFactory`
to create a proxy which performs requests through an HTTP client such as `RestClient`
or `WebClient`. You can also implement the interface from an `@Controller` for server
request handling.
[[rest-http-service-client]]
== HTTP Service Clients
Start by creating the interface with `@HttpExchange` methods:
You can define an HTTP Service as a Java interface with `@HttpExchange` methods, and use
`HttpServiceProxyFactory` to create a client proxy from it for remote access over HTTP via
`RestClient`, `WebClient`, or `RestTemplate`. On the server side, an `@Controller` class
can implement the same interface to handle requests with
xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-httpexchange-annotation[@HttpExchange]
controller methods.
First, create the Java interface:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -865,43 +975,7 @@ Start by creating the interface with `@HttpExchange` methods:
}
----
Now you can create a proxy that performs requests when methods are called.
For `RestClient`:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestClient restClient = RestClient.builder().baseUrl("https://api.github.com/").build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
----
For `WebClient`:
[source,java,indent=0,subs="verbatim,quotes"]
----
WebClient webClient = WebClient.builder().baseUrl("https://api.github.com/").build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
----
For `RestTemplate`:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("https://api.github.com/"));
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RepositoryService service = factory.createClient(RepositoryService.class);
----
`@HttpExchange` is supported at the type level where it applies to all methods:
Optionally, use `@HttpExchange` at the type level to declare common attributes for all methods:
[source,java,indent=0,subs="verbatim,quotes"]
----
@@ -918,15 +992,52 @@ For `RestTemplate`:
}
----
[[rest-http-interface-method-parameters]]
Next, configure the client and create the `HttpServiceProxyFactory`:
[source,java,indent=0,subs="verbatim,quotes"]
----
// Using RestClient...
RestClient restClient = RestClient.create("...");
RestClientAdapter adapter = RestClientAdapter.create(restClient);
// or WebClient...
WebClient webClient = WebClient.create("...");
WebClientAdapter adapter = WebClientAdapter.create(webClient);
// or RestTemplate...
RestTemplate restTemplate = new RestTemplate();
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
Now, you're ready to create client proxies:
[source,java,indent=0,subs="verbatim,quotes"]
----
RepositoryService service = factory.createClient(RepositoryService.class);
// Use service methods for remote calls...
----
HTTP service clients is a powerful and expressive choice for remote access over HTTP.
It allows one team to own the knowledge of how a REST API works, what parts are relevant
to a client application, what input and output types to create, what endpoint method
signatures are needed, what Javadoc to have, and so on. The resulting Java API guides and
is ready to use.
[[rest-http-service-client-method-parameters]]
=== Method Parameters
Annotated, HTTP exchange methods support flexible method signatures with the following
method parameters:
`@HttpExchange` methods support flexible method signatures with the following inputs:
[cols="1,2", options="header"]
|===
| Method argument | Description
| Method parameter | Description
| `URI`
| Dynamically set the URL for the request, overriding the annotation's `url` attribute.
@@ -987,28 +1098,32 @@ Method parameters cannot be `null` unless the `required` attribute (where availa
parameter annotation) is set to `false`, or the parameter is marked optional as determined by
{spring-framework-api}/core/MethodParameter.html#isOptional()[`MethodParameter#isOptional`].
[[rest-http-interface.custom-resolver]]
=== Custom argument resolver
`RestClientAdapter` provides additional support for a method parameter of type
`StreamingHttpOutputMessage.Body` that allows sending the request body by writing to an
`OutputStream`.
For more complex cases, HTTP interfaces do not support `RequestEntity` types as method parameters.
This would take over the entire HTTP request and not improve the semantics of the interface.
Instead of adding many method parameters, developers can combine them into a custom type
and configure a dedicated `HttpServiceArgumentResolver` implementation.
[[rest-http-service-client.custom-resolver]]
=== Custom Arguments
In the following HTTP interface, we are using a custom `Search` type as a parameter:
You can configure a custom `HttpServiceArgumentResolver`. The example interface below
uses a custom `Search` method parameter type:
include-code::./CustomHttpServiceArgumentResolver[tag=httpinterface,indent=0]
include-code::./CustomHttpServiceArgumentResolver[tag=httpserviceclient,indent=0]
We can implement our own `HttpServiceArgumentResolver` that supports our custom `Search` type
and writes its data in the outgoing HTTP request.
A custom argument resolver could be implemented like this:
include-code::./CustomHttpServiceArgumentResolver[tag=argumentresolver,indent=0]
Finally, we can use this argument resolver during the setup and use our HTTP interface.
To configure the custom argument resolver:
include-code::./CustomHttpServiceArgumentResolver[tag=usage,indent=0]
[[rest-http-interface-return-values]]
TIP: By default, `RequestEntity` is not supported as a method parameter, instead encouraging
the use of more fine-grained method parameters for individual parts of the request.
[[rest-http-service-client-return-values]]
=== Return Values
The supported return values depend on the underlying client.
@@ -1080,63 +1195,206 @@ depends on how the underlying HTTP client is configured. You can set a `blockTim
value on the adapter level as well, but we recommend relying on timeout settings of the
underlying HTTP client, which operates at a lower level and provides more control.
[[rest-http-interface-exceptions]]
`RestClientAdapter` provides supports additional support for a return value of type
`InputStream` or `ResponseEntity<InputStream>` that provides access to the raw response
body content.
[[rest-http-service-client-exceptions]]
=== Error Handling
To customize error response handling, you need to configure the underlying HTTP client.
For `RestClient`:
By default, `RestClient` raises `RestClientException` for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
To customize error handling for HTTP Service client proxies, you can configure the
underlying client as needed. By default, clients raise an exception for 4xx and 5xx HTTP
status codes. To customize this, register a response status handler that applies to all
responses performed through the client as follows:
[source,java,indent=0,subs="verbatim,quotes"]
----
// For RestClient
RestClient restClient = RestClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, (request, response) -> ...)
.build();
RestClientAdapter adapter = RestClientAdapter.create(restClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, such as suppressing error status codes, see the Javadoc of
`defaultStatusHandler` in `RestClient.Builder`.
For `WebClient`:
By default, `WebClient` raises `WebClientResponseException` for 4xx and 5xx HTTP status codes.
To customize this, register a response status handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
// or for WebClient...
WebClient webClient = WebClient.builder()
.defaultStatusHandler(HttpStatusCode::isError, resp -> ...)
.build();
WebClientAdapter adapter = WebClientAdapter.create(webClient);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(adapter).build();
----
For more details and options, such as suppressing error status codes, see the Javadoc of
`defaultStatusHandler` in `WebClient.Builder`.
For `RestTemplate`:
By default, `RestTemplate` raises `RestClientException` for 4xx and 5xx HTTP status codes.
To customize this, register an error handler that applies to all responses
performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
// or for RestTemplate...
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, see the Javadoc of `setErrorHandler` in `RestTemplate` and
the `ResponseErrorHandler` hierarchy.
For more details and options such as suppressing error status codes, see the reference
documentation for each client, as well as the Javadoc of `defaultStatusHandler` in
`RestClient.Builder` or `WebClient.Builder`, and the `setErrorHandler` of `RestTemplate`.
[[rest-http-service-client-adapter-decorator]]
=== Decorating the Adapter
`HttpExchangeAdapter` and `ReactorHttpExchangeAdapter` are contracts that decouple HTTP
Interface client infrastructure from the details of invoking the underlying
client. There are adapter implementations for `RestClient`, `WebClient`, and
`RestTemplate`.
Occasionally, it may be useful to intercept client invocations through a decorator
configurable in the `HttpServiceProxyFactory.Builder`. For example, you can apply
built-in decorators to suppress 404 exceptions and return a `ResponseEntity` with
`NOT_FOUND` and a `null` body:
[source,java,indent=0,subs="verbatim,quotes"]
----
// For RestClient
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(restClientAdapter)
.exchangeAdapterDecorator(NotFoundRestClientAdapterDecorator::new)
.build();
// or for WebClient...
HttpServiceProxyFactory proxyFactory = HttpServiceProxyFactory.builderFor(webClientAdapter)
.exchangeAdapterDecorator(NotFoundWebClientAdapterDecorator::new)
.build();
----
[[rest-http-service-client-group-config]]
=== HTTP Service Groups
It's trivial to create client proxies with `HttpServiceProxyFactory`, but to have them
declared as beans leads to repetitive configuration. You may also have multiple
target hosts, and therefore multiple clients to configure, and even more client proxy
beans to create.
To make it easier to work with interface clients at scale the Spring Framework provides
dedicated configuration support. It lets applications focus on identifying HTTP Services
by group, and customizing the client for each group, while the framework transparently
creates a registry of client proxies, and declares each proxy as a bean.
An HTTP Service group is simply a set of interfaces that share the same client setup and
`HttpServiceProxyFactory` instance to create proxies. Typically, that means one group per
host, but you can have more than one group for the same target host in case the
underlying client needs to be configured differently.
One way to declare HTTP Service groups is via `@ImportHttpServices` annotations in
`@Configuration` classes as shown below:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ImportHttpServices(group = "echo", types = {EchoServiceA.class, EchoServiceB.class}) // <1>
@ImportHttpServices(group = "greeting", basePackageClasses = GreetServiceA.class) // <2>
public class ClientConfig {
}
----
<1> Manually list interfaces for group "echo"
<2> Detect interfaces for group "greeting" under a base package
It is also possible to declare groups programmatically by creating an HTTP Service
registrar and then importing it:
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MyHttpServiceRegistrar extends AbstractHttpServiceRegistrar { // <1>
@Override
protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata metadata) {
registry.forGroup("echo").register(EchoServiceA.class, EchoServiceB.class); // <2>
registry.forGroup("greeting").detectInBasePackages(GreetServiceA.class); // <3>
}
}
@Configuration
@Import(MyHttpServiceRegistrar.class) // <4>
public class ClientConfig {
}
----
<1> Create extension class of `AbstractHttpServiceRegistrar`
<2> Manually list interfaces for group "echo"
<3> Detect interfaces for group "greeting" under a base package
<4> Import the registrar
TIP: You can mix and match `@ImportHttpService` annotations with programmatic registrars,
and you can spread the imports across multiple configuration classes. All imports
contribute collaboratively the same, shared `HttpServiceProxyRegistry` instance.
Once HTTP Service groups are declared, add an `HttpServiceGroupConfigurer` bean to
customize the client for each group. For example:
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@ImportHttpServices(group = "echo", types = {EchoServiceA.class, EchoServiceB.class})
@ImportHttpServices(group = "greeting", basePackageClasses = GreetServiceA.class)
public class ClientConfig {
@Bean
public RestClientHttpServiceGroupConfigurer groupConfigurer() {
return groups -> {
// configure client for group "echo"
groups.filterByName("echo").forEachClient((group, clientBuilder) -> ...);
// configure the clients for all groups
groups.forEachClient((group, clientBuilder) -> ...);
// configure client and proxy factory for each group
groups.forEachGroup((group, clientBuilder, factoryBuilder) -> ...);
};
}
}
----
TIP: Spring Boot uses an `HttpServiceGroupConfigurer` to add support for client properties
by HTTP Service group, Spring Security to add OAuth support, and Spring Cloud to add load
balancing.
As a result of the above, each client proxy is available as a bean that you can
conveniently autowire by type:
[source,java,indent=0,subs="verbatim,quotes"]
----
@RestController
public class EchoController {
private final EchoService echoService;
public EchoController(EchoService echoService) {
this.echoService = echoService;
}
// ...
}
----
However, if there are multiple client proxies of the same type, e.g. the same interface
in multiple groups, then there is no unique bean of that type, and you cannot autowire by
type only. For such cases, you can work directly with the `HttpServiceProxyRegistry` that
holds all proxies, and obtain the ones you need by group:
[source,java,indent=0,subs="verbatim,quotes"]
----
@RestController
public class EchoController {
private final EchoService echoService1;
private final EchoService echoService2;
public EchoController(HttpServiceProxyRegistry registry) {
this.echoService1 = registry.getClient("echo1", EchoService.class); // <1>
this.echoService2 = registry.getClient("echo2", EchoService.class); // <2>
}
// ...
}
----
<1> Access the `EchoService` client proxy for group "echo1"
<2> Access the `EchoService` client proxy for group "echo2"
@@ -533,8 +533,7 @@ that returns a value:
----
TIP: `@Async` methods may not only declare a regular `java.util.concurrent.Future` return
type but also Spring's `org.springframework.util.concurrent.ListenableFuture` or, as of
Spring 4.2, JDK 8's `java.util.concurrent.CompletableFuture`, for richer interaction with
type but also `java.util.concurrent.CompletableFuture`, for richer interaction with
the asynchronous task and for immediate composition with further processing steps.
You can not use `@Async` in conjunction with lifecycle callbacks such as `@PostConstruct`.
@@ -1,831 +0,0 @@
[[dynamic-language]]
= Dynamic Language Support
Spring provides comprehensive support for using classes and objects that have been
defined by using a dynamic language (such as Groovy) with Spring. This support lets
you write any number of classes in a supported dynamic language and have the Spring
container transparently instantiate, configure, and dependency inject the resulting
objects.
Spring's scripting support primarily targets Groovy and BeanShell. Beyond those
specifically supported languages, the JSR-223 scripting mechanism is supported
for integration with any JSR-223 capable language provider (as of Spring 4.2),
for example, JRuby.
You can find fully working examples of where this dynamic language support can be
immediately useful in xref:languages/dynamic.adoc#dynamic-language-scenarios[Scenarios].
[[dynamic-language-a-first-example]]
== A First Example
The bulk of this chapter is concerned with describing the dynamic language support in
detail. Before diving into all of the ins and outs of the dynamic language support,
we look at a quick example of a bean defined in a dynamic language. The dynamic
language for this first bean is Groovy. (The basis of this example was taken from the
Spring test suite. If you want to see equivalent examples in any of the other
supported languages, take a look at the source code).
The next example shows the `Messenger` interface, which the Groovy bean is going to
implement. Note that this interface is defined in plain Java. Dependent objects that
are injected with a reference to the `Messenger` do not know that the underlying
implementation is a Groovy script. The following listing shows the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
public interface Messenger {
String getMessage();
}
----
The following example defines a class that has a dependency on the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
public class DefaultBookingService implements BookingService {
private Messenger messenger;
public void setMessenger(Messenger messenger) {
this.messenger = messenger;
}
public void processBooking() {
// use the injected Messenger object...
}
}
----
The following example implements the `Messenger` interface in Groovy:
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages",fold="none"]
----
package org.springframework.scripting.groovy
// Import the Messenger interface (written in Java) that is to be implemented
import org.springframework.scripting.Messenger
// Define the implementation in Groovy in file 'Messenger.groovy'
class GroovyMessenger implements Messenger {
String message
}
----
[NOTE]
====
To use the custom dynamic language tags to define dynamic-language-backed beans, you
need to have the XML Schema preamble at the top of your Spring XML configuration file.
You also need to use a Spring `ApplicationContext` implementation as your IoC
container. Using the dynamic-language-backed beans with a plain `BeanFactory`
implementation is supported, but you have to manage the plumbing of the Spring internals
to do so.
For more information on schema-based configuration, see xref:languages/dynamic.adoc#xsd-schemas-lang[XML Schema-based Configuration]
.
====
Finally, the following example shows the bean definitions that effect the injection of the
Groovy-defined `Messenger` implementation into an instance of the
`DefaultBookingService` class:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang https://www.springframework.org/schema/lang/spring-lang.xsd">
<!-- this is the bean definition for the Groovy-backed Messenger implementation -->
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
<!-- an otherwise normal bean that will be injected by the Groovy-backed Messenger -->
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
----
The `bookingService` bean (a `DefaultBookingService`) can now use its private `messenger`
member variable as normal, because the `Messenger` instance that was injected into it is
a `Messenger` instance. There is nothing special going on here -- just plain Java and
plain Groovy.
Hopefully, the preceding XML snippet is self-explanatory, but do not worry unduly if it is not.
Keep reading for the in-depth detail on the whys and wherefores of the preceding configuration.
[[dynamic-language-beans]]
== Defining Beans that Are Backed by Dynamic Languages
This section describes exactly how you define Spring-managed beans in any of the
supported dynamic languages.
Note that this chapter does not attempt to explain the syntax and idioms of the supported
dynamic languages. For example, if you want to use Groovy to write certain of the classes
in your application, we assume that you already know Groovy. If you need further details
about the dynamic languages themselves, see
xref:languages/dynamic.adoc#dynamic-language-resources[Further Resources] at the end of
this chapter.
[[dynamic-language-beans-concepts]]
=== Common Concepts
The steps involved in using dynamic-language-backed beans are as follows:
. Write the test for the dynamic language source code (naturally).
. Then write the dynamic language source code itself.
. Define your dynamic-language-backed beans by using the appropriate `<lang:language/>`
element in the XML configuration (you can define such beans programmatically by
using the Spring API, although you will have to consult the source code for
directions on how to do this, as this chapter does not cover this type of advanced configuration).
Note that this is an iterative step. You need at least one bean definition for each dynamic
language source file (although multiple bean definitions can reference the same source file).
The first two steps (testing and writing your dynamic language source files) are beyond
the scope of this chapter. See the language specification and reference manual
for your chosen dynamic language and crack on with developing your dynamic language
source files. You first want to read the rest of this chapter, though, as
Spring's dynamic language support does make some (small) assumptions about the contents
of your dynamic language source files.
[[dynamic-language-beans-concepts-xml-language-element]]
==== The <lang:language/> element
The final step in the list in the xref:languages/dynamic.adoc#dynamic-language-beans-concepts[preceding section]
involves defining dynamic-language-backed bean definitions, one for each bean that you
want to configure (this is no different from normal JavaBean configuration). However,
instead of specifying the fully qualified class name of the class that is to be
instantiated and configured by the container, you can use the `<lang:language/>`
element to define the dynamic language-backed bean.
Each of the supported languages has a corresponding `<lang:language/>` element:
* `<lang:groovy/>` (Groovy)
* `<lang:bsh/>` (BeanShell)
* `<lang:std/>` (JSR-223, for example, with JRuby)
The exact attributes and child elements that are available for configuration depends on
exactly which language the bean has been defined in (the language-specific sections
later in this chapter detail this).
[[dynamic-language-refreshable-beans]]
==== Refreshable Beans
One of the (and perhaps the single) most compelling value adds of the dynamic language
support in Spring is the "`refreshable bean`" feature.
A refreshable bean is a dynamic-language-backed bean. With a small amount of
configuration, a dynamic-language-backed bean can monitor changes in its underlying
source file resource and then reload itself when the dynamic language source file is
changed (for example, when you edit and save changes to the file on the file system).
This lets you deploy any number of dynamic language source files as part of an
application, configure the Spring container to create beans backed by dynamic
language source files (using the mechanisms described in this chapter), and (later,
as requirements change or some other external factor comes into play) edit a dynamic
language source file and have any change they make be reflected in the bean that is
backed by the changed dynamic language source file. There is no need to shut down a
running application (or redeploy in the case of a web application). The
dynamic-language-backed bean so amended picks up the new state and logic from the
changed dynamic language source file.
NOTE: This feature is off by default.
Now we can take a look at an example to see how easy it is to start using refreshable
beans. To turn on the refreshable beans feature, you have to specify exactly one
additional attribute on the `<lang:language/>` element of your bean definition. So,
if we stick with xref:languages/dynamic.adoc#dynamic-language-a-first-example[the example] from earlier in
this chapter, the following example shows what we would change in the Spring XML
configuration to effect refreshable beans:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<beans>
<!-- this bean is now 'refreshable' due to the presence of the 'refresh-check-delay' attribute -->
<lang:groovy id="messenger"
refresh-check-delay="5000" <!-- switches refreshing on with 5 seconds between checks -->
script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
----
That really is all you have to do. The `refresh-check-delay` attribute defined on the
`messenger` bean definition is the number of milliseconds after which the bean is
refreshed with any changes made to the underlying dynamic language source file.
You can turn off the refresh behavior by assigning a negative value to the
`refresh-check-delay` attribute. Remember that, by default, the refresh behavior is
disabled. If you do not want the refresh behavior, do not define the attribute.
If we then run the following application, we can exercise the refreshable feature.
(Please excuse the "`jumping-through-hoops-to-pause-the-execution`" shenanigans
in this next slice of code.) The `System.in.read()` call is only there so that the
execution of the program pauses while you (the developer in this scenario) go off
and edit the underlying dynamic language source file so that the refresh triggers
on the dynamic-language-backed bean when the program resumes execution.
The following listing shows this sample application:
[source,java,indent=0,subs="verbatim,quotes"]
----
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Messenger messenger = (Messenger) ctx.getBean("messenger");
System.out.println(messenger.getMessage());
// pause execution while I go off and make changes to the source file...
System.in.read();
System.out.println(messenger.getMessage());
}
}
----
Assume then, for the purposes of this example, that all calls to the `getMessage()`
method of `Messenger` implementations have to be changed such that the message is
surrounded by quotation marks. The following listing shows the changes that you
(the developer) should make to the `Messenger.groovy` source file when the
execution of the program is paused:
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting
class GroovyMessenger implements Messenger {
private String message = "Bingo"
public String getMessage() {
// change the implementation to surround the message in quotes
return "'" + this.message + "'"
}
public void setMessage(String message) {
this.message = message
}
}
----
When the program runs, the output before the input pause will be `I Can Do The Frug`.
After the change to the source file is made and saved and the program resumes execution,
the result of calling the `getMessage()` method on the dynamic-language-backed
`Messenger` implementation is `'I Can Do The Frug'` (notice the inclusion of the
additional quotation marks).
Changes to a script do not trigger a refresh if the changes occur within the window of
the `refresh-check-delay` value. Changes to the script are not actually picked up until
a method is called on the dynamic-language-backed bean. It is only when a method is
called on a dynamic-language-backed bean that it checks to see if its underlying script
source has changed. Any exceptions that relate to refreshing the script (such as
encountering a compilation error or finding that the script file has been deleted)
results in a fatal exception being propagated to the calling code.
The refreshable bean behavior described earlier does not apply to dynamic language
source files defined with the `<lang:inline-script/>` element notation (see
xref:languages/dynamic.adoc#dynamic-language-beans-inline[Inline Dynamic Language Source Files]).
Additionally, it applies only to beans where changes to the underlying source file can
actually be detected (for example, by code that checks the last modified date of a
dynamic language source file that exists on the file system).
[[dynamic-language-beans-inline]]
==== Inline Dynamic Language Source Files
The dynamic language support can also cater to dynamic language source files that are
embedded directly in Spring bean definitions. More specifically, the
`<lang:inline-script/>` element lets you define dynamic language source immediately
inside a Spring configuration file. An example might clarify how the inline script
feature works:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<lang:groovy id="messenger">
<lang:inline-script>
package org.springframework.scripting.groovy
import org.springframework.scripting.Messenger
class GroovyMessenger implements Messenger {
String message
}
</lang:inline-script>
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
----
If we put to one side the issues surrounding whether it is good practice to define
dynamic language source inside a Spring configuration file, the `<lang:inline-script/>`
element can be useful in some scenarios. For instance, we might want to quickly add a
Spring `Validator` implementation to a Spring MVC `Controller`. This is but a moment's
work using inline source. (See
xref:languages/dynamic.adoc#dynamic-language-scenarios-validators[Scripted Validators]
for such an example.)
[[dynamic-language-beans-ctor-injection]]
==== Understanding Constructor Injection in the Context of Dynamic-language-backed Beans
There is one very important thing to be aware of with regard to Spring's dynamic
language support. Namely, you can not (currently) supply constructor arguments
to dynamic-language-backed beans (and, hence, constructor-injection is not available for
dynamic-language-backed beans). In the interests of making this special handling of
constructors and properties 100% clear, the following mixture of code and configuration
does not work:
.An approach that cannot work
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting.groovy
import org.springframework.scripting.Messenger
// from the file 'Messenger.groovy'
class GroovyMessenger implements Messenger {
GroovyMessenger() {}
// this constructor is not available for Constructor Injection
GroovyMessenger(String message) {
this.message = message;
}
String message
String anotherMessage
}
----
[source,xml,indent=0,subs="verbatim,quotes"]
----
<lang:groovy id="badMessenger"
script-source="classpath:Messenger.groovy">
<!-- this next constructor argument will not be injected into the GroovyMessenger -->
<!-- in fact, this isn't even allowed according to the schema -->
<constructor-arg value="This will not work" />
<!-- only property values are injected into the dynamic-language-backed object -->
<lang:property name="anotherMessage" value="Passed straight through to the dynamic-language-backed object" />
</lang>
----
In practice this limitation is not as significant as it first appears, since setter
injection is the injection style favored by the overwhelming majority of developers
(we leave the discussion as to whether that is a good thing to another day).
[[dynamic-language-beans-groovy]]
=== Groovy Beans
This section describes how to use beans defined in Groovy in Spring.
The Groovy homepage includes the following description:
"`Groovy is an agile dynamic language for the Java 2 Platform that has many of the
features that people like so much in languages like Python, Ruby and Smalltalk, making
them available to Java developers using a Java-like syntax.`"
If you have read this chapter straight from the top, you have already
xref:languages/dynamic.adoc#dynamic-language-a-first-example[seen an example] of a Groovy-dynamic-language-backed
bean. Now consider another example (again using an example from the Spring test suite):
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
public interface Calculator {
int add(int x, int y);
}
----
The following example implements the `Calculator` interface in Groovy:
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting.groovy
// from the file 'calculator.groovy'
class GroovyCalculator implements Calculator {
int add(int x, int y) {
x + y
}
}
----
The following bean definition uses the calculator defined in Groovy:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<!-- from the file 'beans.xml' -->
<beans>
<lang:groovy id="calculator" script-source="classpath:calculator.groovy"/>
</beans>
----
Finally, the following small application exercises the preceding configuration:
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Calculator calc = ctx.getBean("calculator", Calculator.class);
System.out.println(calc.add(2, 8));
}
}
----
The resulting output from running the above program is (unsurprisingly) `10`.
(For more interesting examples, see the dynamic language showcase project for a more
complex example or see the examples xref:languages/dynamic.adoc#dynamic-language-scenarios[Scenarios] later in this chapter).
You must not define more than one class per Groovy source file. While this is perfectly
legal in Groovy, it is (arguably) a bad practice. In the interests of a consistent
approach, you should (in the opinion of the Spring team) respect the standard Java
conventions of one (public) class per source file.
[[dynamic-language-beans-groovy-customizer]]
==== Customizing Groovy Objects by Using a Callback
The `GroovyObjectCustomizer` interface is a callback that lets you hook additional
creation logic into the process of creating a Groovy-backed bean. For example,
implementations of this interface could invoke any required initialization methods,
set some default property values, or specify a custom `MetaClass`. The following listing
shows the `GroovyObjectCustomizer` interface definition:
[source,java,indent=0,subs="verbatim,quotes"]
----
public interface GroovyObjectCustomizer {
void customize(GroovyObject goo);
}
----
The Spring Framework instantiates an instance of your Groovy-backed bean and then
passes the created `GroovyObject` to the specified `GroovyObjectCustomizer` (if one
has been defined). You can do whatever you like with the supplied `GroovyObject`
reference. We expect that most people want to set a custom `MetaClass` with this
callback, and the following example shows how to do so:
[source,java,indent=0,subs="verbatim,quotes"]
----
public final class SimpleMethodTracingCustomizer implements GroovyObjectCustomizer {
public void customize(GroovyObject goo) {
DelegatingMetaClass metaClass = new DelegatingMetaClass(goo.getMetaClass()) {
public Object invokeMethod(Object object, String methodName, Object[] arguments) {
System.out.println("Invoking '" + methodName + "'.");
return super.invokeMethod(object, methodName, arguments);
}
};
metaClass.initialize();
goo.setMetaClass(metaClass);
}
}
----
A full discussion of meta-programming in Groovy is beyond the scope of the Spring
reference manual. See the relevant section of the Groovy reference manual or do a
search online. Plenty of articles address this topic. Actually, making use of a
`GroovyObjectCustomizer` is easy if you use the Spring namespace support, as the
following example shows:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<!-- define the GroovyObjectCustomizer just like any other bean -->
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer"/>
<!-- ... and plug it into the desired Groovy bean via the 'customizer-ref' attribute -->
<lang:groovy id="calculator"
script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy"
customizer-ref="tracingCustomizer"/>
----
If you do not use the Spring namespace support, you can still use the
`GroovyObjectCustomizer` functionality, as the following example shows:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<bean id="calculator" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="classpath:org/springframework/scripting/groovy/Calculator.groovy"/>
<!-- define the GroovyObjectCustomizer (as an inner bean) -->
<constructor-arg>
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer"/>
</constructor-arg>
</bean>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
----
NOTE: You may also specify a Groovy `CompilationCustomizer` (such as an `ImportCustomizer`)
or even a full Groovy `CompilerConfiguration` object in the same place as Spring's
`GroovyObjectCustomizer`. Furthermore, you may set a common `GroovyClassLoader` with custom
configuration for your beans at the `ConfigurableApplicationContext.setClassLoader` level;
this also leads to shared `GroovyClassLoader` usage and is therefore recommendable in case of
a large number of scripted beans (avoiding an isolated `GroovyClassLoader` instance per bean).
[[dynamic-language-beans-bsh]]
=== BeanShell Beans
This section describes how to use BeanShell beans in Spring.
The https://beanshell.github.io/intro.html[BeanShell homepage] includes the following
description:
----
BeanShell is a small, free, embeddable Java source interpreter with dynamic language
features, written in Java. BeanShell dynamically runs standard Java syntax and
extends it with common scripting conveniences such as loose types, commands, and method
closures like those in Perl and JavaScript.
----
In contrast to Groovy, BeanShell-backed bean definitions require some (small) additional
configuration. The implementation of the BeanShell dynamic language support in Spring is
interesting, because Spring creates a JDK dynamic proxy that implements all of the
interfaces that are specified in the `script-interfaces` attribute value of the
`<lang:bsh>` element (this is why you must supply at least one interface in the value
of the attribute, and, consequently, program to interfaces when you use BeanShell-backed
beans). This means that every method call on a BeanShell-backed object goes through the
JDK dynamic proxy invocation mechanism.
Now we can show a fully working example of using a BeanShell-based bean that implements
the `Messenger` interface that was defined earlier in this chapter. We again show the
definition of the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.scripting;
public interface Messenger {
String getMessage();
}
----
The following example shows the BeanShell "`implementation`" (we use the term loosely here)
of the `Messenger` interface:
[source,java,indent=0,subs="verbatim,quotes"]
----
String message;
String getMessage() {
return message;
}
void setMessage(String aMessage) {
message = aMessage;
}
----
The following example shows the Spring XML that defines an "`instance`" of the above
"`class`" (again, we use these terms very loosely here):
[source,xml,indent=0,subs="verbatim,quotes"]
----
<lang:bsh id="messageService" script-source="classpath:BshMessenger.bsh"
script-interfaces="org.springframework.scripting.Messenger">
<lang:property name="message" value="Hello World!" />
</lang:bsh>
----
See xref:languages/dynamic.adoc#dynamic-language-scenarios[Scenarios] for some scenarios
where you might want to use BeanShell-based beans.
[[dynamic-language-scenarios]]
== Scenarios
The possible scenarios where defining Spring managed beans in a scripting language would
be beneficial are many and varied. This section describes two possible use cases for the
dynamic language support in Spring.
[[dynamic-language-scenarios-controllers]]
=== Scripted Spring MVC Controllers
One group of classes that can benefit from using dynamic-language-backed beans is that
of Spring MVC controllers. In pure Spring MVC applications, the navigational flow
through a web application is, to a large extent, determined by code encapsulated within
your Spring MVC controllers. As the navigational flow and other presentation layer logic
of a web application needs to be updated to respond to support issues or changing
business requirements, it may well be easier to effect any such required changes by
editing one or more dynamic language source files and seeing those changes being
immediately reflected in the state of a running application.
Remember that, in the lightweight architectural model espoused by projects such as
Spring, you typically aim to have a really thin presentation layer, with all
the meaty business logic of an application being contained in the domain and service
layer classes. Developing Spring MVC controllers as dynamic-language-backed beans lets
you change presentation layer logic by editing and saving text files. Any
changes to such dynamic language source files is (depending on the configuration)
automatically reflected in the beans that are backed by dynamic language source files.
NOTE: To effect this automatic "`pickup`" of any changes to dynamic-language-backed
beans, you have to enable the "`refreshable beans`" functionality. See
xref:languages/dynamic.adoc#dynamic-language-refreshable-beans[Refreshable Beans] for a full treatment of this feature.
The following example shows an `org.springframework.web.servlet.mvc.Controller` implemented
by using the Groovy dynamic language:
[source,groovy,indent=0,subs="verbatim,quotes",chomp="-packages"]
----
package org.springframework.showcase.fortune.web
import org.springframework.showcase.fortune.service.FortuneService
import org.springframework.showcase.fortune.domain.Fortune
import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.mvc.Controller
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
// from the file '/WEB-INF/groovy/FortuneController.groovy'
class FortuneController implements Controller {
@Property FortuneService fortuneService
ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse httpServletResponse) {
return new ModelAndView("tell", "fortune", this.fortuneService.tellFortune())
}
}
----
[source,xml,indent=0,subs="verbatim,quotes"]
----
<lang:groovy id="fortune"
refresh-check-delay="3000"
script-source="/WEB-INF/groovy/FortuneController.groovy">
<lang:property name="fortuneService" ref="fortuneService"/>
</lang:groovy>
----
[[dynamic-language-scenarios-validators]]
=== Scripted Validators
Another area of application development with Spring that may benefit from the
flexibility afforded by dynamic-language-backed beans is that of validation. It can
be easier to express complex validation logic by using a loosely typed dynamic language
(that may also have support for inline regular expressions) as opposed to regular Java.
Again, developing validators as dynamic-language-backed beans lets you change
validation logic by editing and saving a simple text file. Any such changes is
(depending on the configuration) automatically reflected in the execution of a
running application and would not require the restart of an application.
NOTE: To effect the automatic "`pickup`" of any changes to dynamic-language-backed
beans, you have to enable the 'refreshable beans' feature. See
xref:languages/dynamic.adoc#dynamic-language-refreshable-beans[Refreshable Beans]
for a full and detailed treatment of this feature.
The following example shows a Spring `org.springframework.validation.Validator`
implemented by using the Groovy dynamic language (see
xref:core/validation/validator.adoc[Validation using Springs Validator interface]
for a discussion of the `Validator` interface):
[source,groovy,indent=0,subs="verbatim,quotes"]
----
import org.springframework.validation.Validator
import org.springframework.validation.Errors
import org.springframework.beans.TestBean
class TestBeanValidator implements Validator {
boolean supports(Class clazz) {
return TestBean.class.isAssignableFrom(clazz)
}
void validate(Object bean, Errors errors) {
if(bean.name?.trim()?.size() > 0) {
return
}
errors.reject("whitespace", "Cannot be composed wholly of whitespace.")
}
}
----
[[dynamic-language-final-notes]]
== Additional Details
This last section contains some additional details related to the dynamic language support.
[[dynamic-language-final-notes-aop]]
=== AOP -- Advising Scripted Beans
You can use the Spring AOP framework to advise scripted beans. The Spring AOP
framework actually is unaware that a bean that is being advised might be a scripted
bean, so all of the AOP use cases and functionality that you use (or aim to use)
work with scripted beans. When you advise scripted beans, you cannot use class-based
proxies. You must use xref:core/aop/proxying.adoc[interface-based proxies].
You are not limited to advising scripted beans. You can also write aspects themselves
in a supported dynamic language and use such beans to advise other Spring beans.
This really would be an advanced use of the dynamic language support though.
[[dynamic-language-final-notes-scopes]]
=== Scoping
In case it is not immediately obvious, scripted beans can be scoped in the same way as
any other bean. The `scope` attribute on the various `<lang:language/>` elements lets
you control the scope of the underlying scripted bean, as it does with a regular
bean. (The default scope is xref:core/beans/factory-scopes.adoc#beans-factory-scopes-singleton[singleton],
as it is with "`regular`" beans.)
The following example uses the `scope` attribute to define a Groovy bean scoped as
a xref:core/beans/factory-scopes.adoc#beans-factory-scopes-prototype[prototype]:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang https://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy" scope="prototype">
<lang:property name="message" value="I Can Do The RoboCop" />
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
</bean>
</beans>
----
See xref:core/beans/factory-scopes.adoc[Bean Scopes] in
xref:web/webmvc-view/mvc-xslt.adoc#mvc-view-xslt-beandefs[The IoC Container]
for a full discussion of the scoping support in the Spring Framework.
[[xsd-schemas-lang]]
=== The `lang` XML schema
The `lang` elements in Spring XML configuration deal with exposing objects that have been
written in a dynamic language (such as Groovy or BeanShell) as beans in the Spring container.
These elements (and the dynamic language support) are comprehensively covered in
xref:languages/dynamic.adoc[Dynamic Language Support]. See that section
for full details on this support and the `lang` elements.
To use the elements in the `lang` schema, you need to have the following preamble at the
top of your Spring XML configuration file. The text in the following snippet references
the correct schema so that the tags in the `lang` namespace are available to you:
[source,xml,indent=0,subs="verbatim,quotes"]
----
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang https://www.springframework.org/schema/lang/spring-lang.xsd">
<!-- bean definitions here -->
</beans>
----
[[dynamic-language-resources]]
== Further Resources
The following links go to further resources about the various dynamic languages referenced
in this chapter:
* The https://www.groovy-lang.org/[Groovy] homepage
* The https://beanshell.github.io/intro.html[BeanShell] homepage
* The https://www.jruby.org[JRuby] homepage
@@ -6,9 +6,37 @@ Groovy is a powerful, optionally typed, and dynamic language, with static-typing
compilation capabilities. It offers a concise syntax and integrates smoothly with any
existing Java application.
The Spring Framework provides a dedicated `ApplicationContext` that supports a Groovy-based
Bean Definition DSL. For more details, see
xref:core/beans/basics.adoc#beans-factory-groovy[The Groovy Bean Definition DSL].
[[beans-factory-groovy]]
== The Groovy Bean Definition DSL
The Spring Framework provides a dedicated `ApplicationContext` that supports a Groovy-based
Bean Definition DSL, as known from the Grails framework.
Typically, such configuration live in a ".groovy" file with the structure shown in the
following example:
[source,groovy,indent=0,subs="verbatim,quotes"]
----
beans {
dataSource(BasicDataSource) {
driverClassName = "org.hsqldb.jdbcDriver"
url = "jdbc:hsqldb:mem:grailsDB"
username = "sa"
password = ""
settings = [mynew:"setting"]
}
sessionFactory(SessionFactory) {
dataSource = dataSource
}
myService(MyService) {
nestedBean = { AnotherBean bean ->
dataSource = dataSource
}
}
}
----
This configuration style is largely equivalent to XML bean definitions and even
supports Spring's XML configuration namespaces. It also allows for importing XML
bean definition files through an `importBeans` directive.
Further support for Groovy, including beans written in Groovy, refreshable script beans,
and more is available in xref:languages/dynamic.adoc[Dynamic Language Support].
@@ -1,110 +0,0 @@
[[kotlin-bean-definition-dsl]]
= Bean Definition DSL
Spring Framework supports registering beans in a functional way by using lambdas
as an alternative to XML or Java configuration (`@Configuration` and `@Bean`). In a nutshell,
it lets you register beans with a lambda that acts as a `FactoryBean`.
This mechanism is very efficient, as it does not require any reflection or CGLIB proxies.
In Java, you can, for example, write the following:
[source,java,indent=0]
----
class Foo {}
class Bar {
private final Foo foo;
public Bar(Foo foo) {
this.foo = foo;
}
}
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class)));
----
In Kotlin, with reified type parameters and `GenericApplicationContext` Kotlin extensions,
you can instead write the following:
[source,kotlin,indent=0]
----
class Foo
class Bar(private val foo: Foo)
val context = GenericApplicationContext().apply {
registerBean<Foo>()
registerBean { Bar(it.getBean()) }
}
----
When the class `Bar` has a single constructor, you can even just specify the bean class,
the constructor parameters will be autowired by type:
[source,kotlin,indent=0]
----
val context = GenericApplicationContext().apply {
registerBean<Foo>()
registerBean<Bar>()
}
----
In order to allow a more declarative approach and cleaner syntax, Spring Framework provides
a {spring-framework-api-kdoc}/spring-context/org.springframework.context.support/-bean-definition-dsl/index.html[Kotlin bean definition DSL]
It declares an `ApplicationContextInitializer` through a clean declarative API,
which lets you deal with profiles and `Environment` for customizing
how beans are registered.
In the following example notice that:
* Type inference usually allows to avoid specifying the type for bean references like `ref("bazBean")`
* It is possible to use Kotlin top level functions to declare beans using callable references like `bean(::myRouter)` in this example
* When specifying `bean<Bar>()` or `bean(::myRouter)`, parameters are autowired by type
* The `FooBar` bean will be registered only if the `foobar` profile is active
[source,kotlin,indent=0]
----
class Foo
class Bar(private val foo: Foo)
class Baz(var message: String = "")
class FooBar(private val baz: Baz)
val myBeans = beans {
bean<Foo>()
bean<Bar>()
bean("bazBean") {
Baz().apply {
message = "Hello world"
}
}
profile("foobar") {
bean { FooBar(ref("bazBean")) }
}
bean(::myRouter)
}
fun myRouter(foo: Foo, bar: Bar, baz: Baz) = router {
// ...
}
----
NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans
through an `if` expression, a `for` loop, or any other Kotlin constructs.
You can then use this `beans()` function to register beans on the application context,
as the following example shows:
[source,kotlin,indent=0]
----
val context = GenericApplicationContext().apply {
myBeans.initialize(this)
refresh()
}
----
NOTE: Spring Boot is based on JavaConfig and
{spring-boot-issues}/8115[does not yet provide specific support for functional bean definition],
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
See {stackoverflow-questions}/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
for more details and up-to-date information. See also the experimental Kofu DSL developed in {spring-github-org}-experimental/spring-fu[Spring Fu incubator].
@@ -0,0 +1,4 @@
[[kotlin-bean-registration-dsl]]
= Bean Registration DSL
See xref:core/beans/java/programmatic-bean-registration.adoc[Programmatic Bean Registration].

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