Commit Graph
35026 Commits
Author SHA1 Message Date
Juergen Hoeller 133a372f91 Reduce lock-guarded boolean field to thread-local
Closes gh-37199
2026-08-29 20:00:24 +02:00
Gimin Kim 74a4b1a694 Preserve async API version resolver order
Prior to this commit, the `DefaultApiVersionStrategy` reactive variant
would attempt to resolve the API version with the first resolver that
replies with a version. This contradicts the API that registers
resolvers in order.
This commit ensures that each resolver is called in order.

Signed-off-by: Gimin Kim <138752849+Gimini-3@users.noreply.github.com>
2026-08-28 18:33:41 +02:00
Hyunsik Kang 6e5cf0ce45 Do not release body buffers already handed to the sink
BodyState.flush() emits every queued buffer and only clears the queue
afterwards, so a cancellation arriving while it emits makes dispose()
release buffers whose ownership has already been transferred to the sink.
Such a buffer is then released twice: once by the parser, and once by the
downstream consumer or the discard hook. With Netty, body buffers are
slices of the inbound buffer, so the second release frees the inbound
buffer prematurely, which surfaces as

  IllegalReferenceCountException: refCnt: 0, decrement: 1
    io.netty.handler.codec.http.DefaultHttpContent.release
    reactor.netty.channel.FluxReceive.drainReceiver

when reactor-netty releases its own share right after onNext.

Remove each buffer from the queue before emitting it, mirroring what
enqueue() already does, so that dispose() only ever releases buffers the
parser still owns.

Signed-off-by: Hyunsik Kang <cj848@hanmail.net>
2026-08-28 16:26:54 +02:00
Hyunsik Kang a99f4dd43c Release queued body token buffers on multipart cancel
When a multipart subscriber cancels while MultipartParser has already
emitted body tokens beyond the downstream demand, those tokens are held
in the Flux.create sink queue (and in downstream operator queues such
as windowUntil). On cancellation, Reactor discards the queued tokens,
but BodyToken is not a DataBuffer, so the buffers inside the discarded
tokens are never released and Netty reports "LEAK: ByteBuf.release()
was not called before it's garbage-collected".

Register a doOnDiscard hook for BodyToken in MultipartParser.parse() so
that a discarded body token releases its buffer, both in the sink queue
and in any downstream operator queue that supports discarding.

Closes gh-37115

Signed-off-by: Hyunsik Kang <cj848@hanmail.net>
2026-08-28 16:26:47 +02:00
Brian Clozel 3170dd5714 Fix mock servlet request behavior with session ids
Prior to this commit,
`MockHttpServletRequest.isRequestedSessionIdValid()` would return `true`
by default and could only be changed manually with a setter. This does
not align with the Servlet spec because of 1) its default value and 2)
it does not react to `changeSessionId()` calls.

This commit fixes that behavior while still allowing "manual" booleans
being set here.

Fixes gh-36631
2026-08-27 14:34:49 +02:00
rstoyanchev 495fd6b3a5 Polishing contribution
See gh-37099
2026-08-24 17:18:17 +01:00
Garvit Joshi 8d4208f030 Allow null contextPath in ServerHttpRequest.Builder
The builder method required a non-null contextPath while the underlying
field, MutatedServerHttpRequest constructor, and RequestPath.parse all
accept null and treat it the same as an empty string. Relax the method
parameter to @Nullable so callers can clear the context path directly.

Closes gh-37099

Signed-off-by: Garvit Joshi <garvitjoshi9@gmail.com>
2026-08-24 17:18:17 +01:00
rstoyanchev 82cf15c60f ProtobufJsonEncoder actually supports streaming
Closes gh-37158
2026-08-24 16:48:48 +01:00
Sam Brannen 37c8f41633 Introduce a builder for SpelParserConfiguration
Prior to this commit, SpelParserConfiguration exposed 8 overloaded
constructors that accumulated over time as new configuration options
were introduced (auto-grow support since 3.0, maximumExpressionLength
in 5.2.25, maximumOperations in 6.2.19, and maximumBigPowerBits in
7.0.9), culminating in an 8-parameter constructor. This made call sites
hard to read due to unlabeled sequences of booleans and ints, and it
forced users who wanted to override a single setting to also supply
every other value explicitly.

To address that, this commit introduces a builder API in
SpelParserConfiguration, following the pattern already established by
SimpleEvaluationContext's builder API.

Specifically, SpelParserConfiguration.builder() returns a Builder that
is pre-populated with the same defaults as the no-arg constructor,
including the SpringProperties-driven overrides for the default
compiler mode, maximum operations, and maximum big-power bits -- the
latter two are only resolved lazily in build(), so that overriding them
via the builder never triggers an unnecessary SpringProperties lookup.
Each property has a dedicated, named setter (compilerMode(),
compilerClassLoader(), maximumAutoGrowSize(),
maximumExpressionLength(), maximumOperations(), maximumBigPowerBits()),
and the two auto-grow flags are exposed as simple no-arg opt-ins
(autoGrowNullReferences(), autoGrowCollections()) since they both
default to false. build() delegates to the existing canonical
constructor, so validation and defaults remain centralized in one
place.

In addition, a new SpelParserConfiguration.withDefaults() factory
method has been introduced as shorthand for
SpelParserConfiguration.builder().build(), for the common case where
none of the builder's defaults need to be overridden.

As the one deliberate exception to matching the no-arg constructor's
defaults, the builder defaults maximumAutoGrowSize to 256 -- aligned
with DataBinder.DEFAULT_AUTO_GROW_COLLECTION_LIMIT -- rather than the
constructors' Integer.MAX_VALUE. The constructors keep their legacy
default for backward compatibility, but the builder is a new, opt-in
API that is not bound by that compatibility contract.

This change is purely additive: none of the existing constructors have
been modified or deprecated. Deprecating those constructors in favor of
the builder is being deferred to 7.1, since new deprecations should not
be introduced in a patch release. In the meantime, the Javadoc for the
constructors and for the SPRING_EXPRESSION_*_PROPERTY_NAME constants
has been updated to favor the builder (or a specific Builder setter)
instead of the constructors, and the class-level Javadoc now states
that the constructors are planned to be deprecated in favor of the
builder as of Spring Framework 7.1.

SpelExpressionParser's no-arg constructor, ExpressionState's two
convenience constructors, and StandardBeanExpressionResolver's
ClassLoader-based constructor have all been switched from the
SpelParserConfiguration constructors to the builder (or
withDefaults()). This is behaviorally identical in every case:
autoGrowCollections remains false at each of those call sites, and
maximumAutoGrowSize -- the only property whose default differs between
the constructors and the builder -- has no effect when
autoGrowCollections is false.

Tests have been added in a new SpelParserConfigurationTests class to
verify that the builder's defaults match the no-arg constructor (with
the one intentional maximumAutoGrowSize exception called out above),
that custom values are applied correctly, and that invalid values are
rejected. The nested LegacyConstructorTests class provides regression
coverage for each of the legacy constructors, consolidating their usage
in tests to a single class -- which will keep any future deprecation
warnings confined to this class -- and documents that, unlike the
builder, the canonical constructor does not (yet) reject a negative
maximumAutoGrowSize. The remaining incidental usages of the
SpelParserConfiguration constructors throughout EvaluationTests,
IndexingTests, SpelCompilationCoverageTests, SpelReproTests, and
SpelCompilerTests have been converted to use the builder.

Furthermore, the reference documentation has been updated to recommend
the builder and withDefaults() over the constructors, both in prose and
in the Java/Kotlin examples.

Closes gh-37187
2026-08-22 11:41:12 +02:00
Brian Clozel 0e9a1d72f5 Merge commit 'v7.0.9~1' into 7.0.x 2026-08-20 18:17:01 +02:00
Sam Brannen 0acdf80830 Derive additional nohttp excludes from .gitignore
Excluding a path from nohttp scanning has so far required mirroring it
by hand in CheckstyleConventions, in addition to any existing
`.gitignore` entry. However, that extra step is easy to forget, as
happened when the .claude folder was added to `.gitignore` (49d2a202da)
but not to the nohttp excludes (48971139c0), only surfacing later as
an OutOfMemoryError that required a separate heap size increase
(90ad7f947d).

To address that, this commit introduces excludeGitIgnoredPaths() in
CheckstyleConventions, which parses the root `.gitignore` file and
translates its patterns into additional nohttp excludes, so that newly
ignored paths are picked up automatically. Note, however, that the
existing hand-maintained excludes are left in place for entries that
are specific to nohttp and are not otherwise ignored by git.

Closes gh-37164
2026-08-20 15:50:55 +02:00
Sam Brannen 15d7a3b327 Use in-document <<id,text>> syntax for same-page links in reference docs
Prior to this commit, some same-page links in our Antora-based docs
were written using the `xref:` macro, which Antora resolves as a
cross-page reference. However, a same-page target can be misread as a
page reference and break the site build (as nearly happened in
gh-37152), whereas `<<id,text>>` only ever resolves against the current
page's own anchors.

To address that inconsistency and avoid potential future bugs (broken
links), this commit converts all such same-page `xref:` links to
`<<id,text>>`, leaving genuine cross-page `xref:` links are unaffected.

Closes gh-37161
2026-08-20 14:53:32 +02:00
Sam Brannen 90ad7f947d Increase heap size for checkstyleNohttp task
On a developer machine, the nohttp check scans the whole project
directory, and things like local git worktrees can add enough extra
content on disk to push the task past its previous 1g heap limit,
causing an OutOfMemoryError. This goes beyond what was addressed by
excluding the .claude folder from nohttp scanning in 48971139c0.

This commit raises the heap size for checkstyleNohttp specifically
to 1536m, leaving the limit for other Checkstyle tasks unchanged so
as not to increase memory pressure on CI.
2026-08-20 12:43:02 +02:00
Sam Brannen 49d2a202da Add .claude folder contents to .gitignore
If we later wish to share certain settings, we can introduce
exclusions like: !.claude/commands/
2026-08-20 12:43:02 +02:00
Sam Brannen df10251539 Upgrade to Gradle 9.7.1
Closes gh-37160
2026-08-20 10:57:33 +02:00
Gabriel Gerhardt 507406c3cd Fix broken internal xref links in reference docs
Closes gh-37152

Signed-off-by: Gabriel Gerhardt <gabrielgerhardt27@gmail.com>
Signed-off-by: gabrielgerhardt <gabrielgerhardt27@gmail.com>
2026-08-19 18:39:12 +02:00
rstoyanchev 6dcdf19169 Polishing in Protobuf decoders
See gh-37147
2026-08-19 10:55:12 +03:00
rstoyanchev 76239d083b Make getMessageBuilder in Protobuf decoders protected
Closes gh-37147
2026-08-19 10:52:35 +03:00
rstoyanchev 40ea92621d Correct supported media types in ProtobufJsonEncoder
Closes gh-37154
2026-08-19 10:44:15 +03:00
rstoyanchev b0149b842b Polishing in Protobuf encoding support
See gh-37154
2026-08-19 10:44:15 +03:00
Sam Brannen a4720ccf77 Guard all AsynchronousFileChannel#write call sites in DataBufferUtils
Prior to this commit, only the very first AsynchronousFileChannel#write
call in DataBufferUtils$WriteCompletionHandler#hookOnNext(DataBuffer)
was guarded against exceptions escaping synchronously, and even then
only via `catch (RuntimeException ex)`, per the original fix for
gh-36184.

While widening that guard to match the read side's `catch (Throwable
ex)` combined with `Exceptions.throwIfFatal(ex)` (see gh-37143), we
discovered that completed(Integer, Attachment) contains two more direct
`this.channel.write(...)` calls -- for continuing a partial write and
for advancing to the next ByteBuffer within the same DataBuffer's
iterator -- neither of which was guarded at all. Since completed() is
invoked by the channel's own completion callback, typically on a
different thread than the one that issued the original write, a
synchronous exception escaping either of those calls has no path back
to the FluxSink, and the resulting Flux hangs indefinitely, exactly as
described in gh-37143, for any write that receives a partial OS write
or spans multiple ByteBuffers.

To address that, this commit extracts a private write(ByteBuffer, long,
Attachment) helper that wraps the channel.write(...) call with a
try/catch block, routing any non-fatal Throwable -- via
Exceptions.throwIfFatal() -- to the existing failed(Throwable,
Attachment) handler. All three call sites (hookOnNext() and both
branches in completed()) now go through this helper, ensuring the
Flux always terminates with a proper error signal instead of hanging
silently, regardless of which write attempt fails or which thread it
fails on.

See gh-36184
See gh-37143
Closes gh-37145
2026-08-18 17:13:56 +02:00
Sam Brannen 15ef2b21f0 Handle synchronous exceptions from AsynchronousFileChannel#read
Prior to this commit, DataBufferUtils$ReadCompletionHandler#read()
invoked AsynchronousFileChannel#read(ByteBuffer, long, Attachment,
CompletionHandler) without guarding against exceptions thrown directly
by that call. Although that method is documented to report failures
asynchronously via the supplied CompletionHandler, some platform-
specific implementations can instead throw synchronously – for
example, on Windows with JDK 25, when the JDK rejects a ByteBuffer
backed by a closeable shared memory Arena, as produced by Netty 4.2's
off-heap buffer allocation.

When such an exception is thrown from a recursive read() invocation
triggered from completed() – which happens once a resource requires
more than a single chunk – the exception has no path back to the
FluxSink: it escapes on whatever thread invoked the CompletionHandler,
and the resulting Flux never signals onError or onComplete. In
practice, this surfaced as an indefinite hang when serving a Resource
whose HTTP response is not a ZeroCopyHttpOutputMessage, since
ResourceHttpMessageWriter falls back to ResourceEncoder, which reads
the resource via DataBufferUtils.

To address that, this commit wraps the channel.read(...) call in a
try/catch block and routes any non-fatal Throwable to the existing
failed(Throwable, Attachment) handler, via Exceptions.throwIfFatal(),
mirroring the equivalent fix already applied to the write side for
gh-36184. This ensures the allocated DataBuffer is released and the
Flux always terminates with a proper error signal instead of leaking a
buffer or hanging silently.

See gh-36184
Closes gh-37143
2026-08-18 16:32:34 +02:00
Sam Brannen 48971139c0 Exclude the .claude folder from nohttp scanning
Without this exclusion, the Gradle build will fail (due to an
OutOfMemoryError) for temporary git work trees residing in the .claude
folder.
2026-08-18 16:32:24 +02:00
Brian Clozel 94beae1779 Next development version (7.0.10-SNAPSHOT) 2026-08-18 09:24:40 +02:00
Brian Clozel a7b1b59cbd Upgrade to Reactor 2025.0.7
Closes gh-37103
2026-08-14 09:12:18 +02:00
Brian Clozel 996e3d3f18 Upgrade to Micrometer 1.16.7
Closes gh-37104
2026-08-14 09:12:18 +02:00
rstoyanchev 73f5ddddcd Refactor maxInMemory limit handling for async XML parsing
The limit was previously enforced in XmlEventDecoder, because it is
what parses incoming buffers. However, the actual caching is in
Jaxb2Decoder, which holds on to XML events, but has no good way to
estimate their size.

After this commit XmlEventDecoder no longer enforces memory limits
for async parsing. It releases each buffer immediately anyway.

Instead XmlEventDecoder is only responsible to update the number
of bytes received via a new ReceivedByteTracker type while
Jaxb2XmlDecoder uses the same to perform limit and reset the
count depending on when it is aggregating XML events.

Closes gh-37031
2026-08-14 09:11:50 +02:00
rstoyanchev 675f25de72 Leading slash handling in UrlHandlerFilter
Closes gh-37030
2026-08-14 09:11:50 +02:00
rstoyanchev 692dbc9160 Apply ResourceHandlerUtils checks in XsltView
Closes gh-37029
2026-08-14 09:11:50 +02:00
rstoyanchev 8647e90bc7 Consistent maxPartSize check in PartEventHttpMessageReader
Closes gh-37028
2026-08-14 09:11:50 +02:00
rstoyanchev b9379e33d5 Check viewName for special prefixes in UrlFilenameViewController
Closes gh-37027
2026-08-14 09:11:50 +02:00
rstoyanchev a784dbe286 Ensure Payload release on early error in createHeaders
Closes gh-37026
2026-08-14 09:11:50 +02:00
rstoyanchev 3b492f3908 Return sameSite cookie value in Jetty response
Closes gh-37025
2026-08-14 09:11:50 +02:00
rstoyanchev 07cbd482a0 Add preflight handling in RouterFunctionWebHandler
Request predicates support preflight request matching based on the "would be"
request (e.g. target HTTP method) so the actual handler is not meant to be
invoked. That's the case only with a DispatcherHandler setup.

Closes gh-37024
2026-08-14 09:11:50 +02:00
rstoyanchev dadd474d21 Update exception messages in HandshakeWebSocketService
Closes gh-37023
2026-08-14 09:11:50 +02:00
Sam Brannen 0d08f8dfaf Disable SpEL expression compilation by default in SimpleEvaluationContext
Prior to this commit, SpEL expression compilation could be silently
activated in a SimpleEvaluationContext via the
`spring.expression.compiler.mode` Spring/system property or
SpelParserConfiguration. Once an expression is compiled, the evaluation
guards enforced during interpreted evaluation are no longer applied,
which is at odds with the restricted intent of SimpleEvaluationContext.

To address that, this commit introduces a mechanism analogous to
isAssignmentEnabled() which disables compilation by default in
SimpleEvaluationContext. Specifically:

- A new isCompilationSupported() default method has been introduced in
  the EvaluationContext API, which returns true by default.

- SimpleEvaluationContext overrides isCompilationSupported() to return
  false by default. However, compilation can be opted into explicitly
  via the new withCompilationSupported() method in the
  SimpleEvaluationContext.Builder.

- SpelExpression.checkCompile() now consults isCompilationSupported()
  before triggering new compilation, ensuring that evaluation within an
  EvaluationContext never produces a compiled form of the expression if
  the context's isCompilationSupported() method returns false.

- All eight getValue() variants in SpelExpression now consult
  isCompilationSupported() before executing a compiled expression,
  ensuring that a compiled expression produced via a different
  EvaluationContext is not silently reused if the caller inadvertently
  switches to an EvaluationContext that does not support compilation.

Closes gh-37035
2026-08-14 09:11:50 +02:00
Sam Brannen baae93f20a Limit result size of BigDecimal/BigInteger power operations in SpEL
This commit introduces a configurable limit on the estimated result size
of BigDecimal and BigInteger power operations within SpEL expressions.
The estimated result size in bits is computed as the product of the base
value's bit length and the exponent. If this limit is exceeded, a
SpelEvaluationException is thrown.

The limit defaults to 1,000,000 bits, which is approximately equivalent
to a decimal number with 300,000 digits, and can be configured either
on a per-use-case basis via the new maximumBigPowerBits constructor
argument in SpelParserConfiguration or globally as a JVM system
property or Spring property named `spring.expression.maxBigPowerBits`.
Parsers intended for trusted internal expressions may supply
Integer.MAX_VALUE to remove the limit entirely.

Closes ch-37034
2026-08-14 09:11:50 +02:00
Sam Brannen d186b381b9 Check list index after auto-grow in AbstractNestablePropertyAccessor
Prior to this commit, the List branch in
AbstractNestablePropertyAccessor's getPropertyValue() method called
list.get(index) unconditionally after invoking
growCollectionIfNecessary(), which implicitly relied on the list
throwing an IndexOutOfBoundsException for out-of-range access. Such an
exception is caught downstream and wrapped as an
InvalidPropertyException; however, any List implementation whose get()
method allocates elements on demand rather than throwing an
IndexOutOfBoundsException could bypass that check.

This behavior was also inconsistent with the Collection/Iterable branch
in the same method, which already performs an explicit `index >=
collection.size()` bounds check before attempting element access.

To address that, this commit aligns the List branch with the
Collection/Iterable branch by adding an explicit `index < 0 || index >=
list.size()` check immediately after the auto-grow attempt. If the
index remains out of bounds after growCollectionIfNecessary() runs –
for example, because growth was capped by autoGrowCollectionLimit or
auto-growing was disabled – an InvalidPropertyException is now thrown
rather than delegating to list.get() which may or may not throw an
exception.

Closes gh-37036
2026-08-14 09:11:50 +02:00
Sébastien Deleuze ac0f8be0d8 Ensure consistent EscapedErrors field error escaping
Closes gh-37055
2026-08-14 09:11:50 +02:00
Sébastien Deleuze 6e3dc633f0 Reject backslashes in SpringTemplateLoader template names
Closes gh-37054
2026-08-14 09:11:50 +02:00
Brian Clozel 35921cc01f Centralize Server Sent Event utility methods
Prior to this commit, many classes would support writing Server Sent
Events in some way to the response output stream. This has lead to some
code duplication.

This commit refactors the duplicated code in a shared `SseUtils` class.

Closes gh-37065
2026-08-14 09:11:50 +02:00
Brian Clozel 062032373e Ensure parsing/tostring symmetry in ContentDisposition
Prior to this commit, building a "Content-Disposition" header to a
String and then parsing it back would not always result in the original
header.

This commit ensures that ContentDisposition guarantees this and honors
the "equals" contract.

Fixes gh-37064
2026-08-14 09:11:50 +02:00
Brian Clozel 1994e0ebd0 Escape SSE view fragments
Prior to this commit, the MVC and WebFlux view fragments rendering would
only partially escape rendered view fragments before sending then as SSE
events. This could in some cases break the SSE stream with invalid data.

This commit ensures that the rendered views are properly escaped before
they are sent as SSE events.

Fixes gh-37061
2026-08-14 09:11:50 +02:00
Brian Clozel dc7fc89aec Switch to INTERNAL-SNAPSHOT versions
See gh-37103
See gh-37104
2026-08-14 09:11:49 +02:00
Brian Clozel f2a7f13d13 Prepare 7.0.x-internal branch 2026-08-14 09:11:49 +02:00
Sam Brannen f8a2bdad87 Clarify Bean Overrides and Spring AOP Proxies documentation
A user reported confusion between two distinct uses of "wraps" in the
AOP proxy documentation for Bean Overrides: the sense in which a
Mockito spy wraps the original bean instance it was created from, and
the sense in which a Spring AOP proxy wraps the spy in the actual
object graph.

To address that, this commit adds two small diagrams to the general
"Bean Overrides and Spring AOP Proxies" section, illustrating, from a
caller's perspective, the shape of the bean for the
REPLACE/REPLACE_OR_CREATE strategy (no proxy at all) versus the WRAP
strategy (an AOP proxy still created, now wrapping the override
instance instead of the original bean). Both diagrams use the same
generic "override instance" label, since the section is not specific to
Mockito; a Mockito spy created by @⁠MockitoSpyBean is mentioned only as
an example.

The accompanying text is revised to reserve "wraps" for the AOP proxy
relationship and to explicitly call out that a Mockito spy's
relationship to its original bean instance is a separate concern from
AOP proxy nesting.

The @⁠MockitoSpyBean-specific strategy paragraph in the
@⁠MockitoBean/@⁠MockitoSpyBean documentation has also been revised
similarly, and now points to the new diagram.

See gh-37121
2026-08-13 18:57:57 +02:00
Juergen Hoeller 9aeda49273 Polishing 2026-08-12 00:08:59 +02:00
Juergen Hoeller abd323d428 Polishing 2026-08-11 23:10:15 +02:00
Juergen Hoeller 176bc2a133 Upgrade to Groovy 5.0.8, Jetty 12.1.12, Netty 4.2.17, Hibernate ORM 7.2.24, Checkstyle 13.10 2026-08-11 23:08:52 +02:00
Sam Brannen 8df51ad6cc Document AOP proxy semantics for Bean Overrides in tests
This commit documents how the Bean Override support in the TestContext
framework interacts with Spring AOP proxies created for annotations
such as @⁠Transactional, @⁠Cacheable, and @⁠Retryable.

The new "Bean Overrides and Spring AOP Proxies" section in the general
Bean Overriding documentation explains that overrides using the WRAP
strategy (such as @⁠MockitoSpyBean) end up as the target of any AOP
proxy subsequently created for the original bean; whereas, overrides
using the REPLACE or REPLACE_OR_CREATE strategy (such as @⁠TestBean,
@⁠MockitoBean) bypass the container's bean post-processing entirely and
therefore carry no AOP advice at all.

The new "@⁠MockitoSpyBean and Spring AOP Proxies" section documents the
resulting stubbing and verification semantics. Verification via
Mockito's verify() API works transparently regardless of whether it is
invoked on the proxy or on the spy. Stubbing via doReturn(...)/doThrow(...)
is safe for stateless advice such as @⁠Retryable, but can silently
corrupt the spy's configured answers for stateful or memoizing advice
such as @⁠Cacheable, since the invocation used to declare a stub is
intercepted by Mockito before it reaches the spy and returns an empty
value that such advice may then cache.
AopTestUtils.getUltimateTargetObject(...) is documented as the way to
stub directly against the spy in that case.

The same section also documents how to disable the AOP advice for a
test altogether while leaving it in place in production code – for
example, binding a @⁠Retryable attribute to a property placeholder
overridden via @⁠TestPropertySource, or replacing the CacheManager with
a NoOpCacheManager via @⁠TestBean.

Brief cross-referencing notes have also been added to the @⁠TestBean
documentation and to the existing AopTestUtils description in the
"General Testing Utilities" section, to avoid duplicating the
explanation across pages.

In addition, the Javadoc for @⁠MockitoSpyBean now contains a concise
WARNING summarizing these AOP proxy implications and linking to the new
reference documentation section for details.

Closes gh-37121
2026-08-09 17:46:28 +03:00