computeIfAbsent registered the case-insensitive key before invoking the
mapping function. If the function returned null or threw an exception,
no mapping was recorded in the target map, but the key registration was
left behind. The map then reported containsKey(key) as true while size()
was 0, keySet() was empty, and get(key) returned null. A later insertion
with a different casing also reused the stale casing of the failed call,
since the existing-key branch resolved to the registered key.
The case-insensitive key is now only looked up up front. For a new key,
it is registered from within the mapping function once a non-null value
has been computed, which is still before the entry is inserted. A null
result or an exception therefore leaves both maps untouched, while a
removeEldestEntry override that evicts the new entry right away still
removes the registration, as it does for put. The existing-key path
keeps computing under the stored casing.
Closes gh-37351
Signed-off-by: junhyeong9812 <pickjog@gmail.com>
KClass instances representing the same class are not guaranteed to be
identical, so the overridden function return type check introduced in
c39edeff15 could wrongly skip unboxing, for example when a class
implements an interface declaring the same suspending function.
See gh-37191
Prior to this commit, both variants of `CssLinkResourceTransformer`
would use a simple CSS parser for detecting CSS links and delegating to
the transformer for links rewrite.
This commit rewrites the internal parser for a single pass, byte by
byte, memory efficient parsing. This implementation is also more
resistant to edge cases.
Closes gh-37348
Only unbox value class results when the caller expects their unboxed
representation (non-primitive underlying type, non-nullable underlying
type for nullable return types, and no overridden function with a
different return type), and add related tests.
Cache the unbox method resolution per method and make it accessible
to support non-public value classes.
Closes gh-37191
Unbox Kotlin value class results returned from proxied suspending
methods before returning them to the caller.
Spring AOP interceptor chains expose return values as Object, which
causes Kotlin value class results to be boxed. For suspending functions,
the direct return path expects the unboxed value class representation.
Update both CglibAopProxy and JdkDynamicAopProxy to detect value class
return types and unbox boxed results after coroutine adaptation.
Add tests for suspending methods returning value classes.
See gh-37191
See gh-37155
Signed-off-by: Dmitry Sulman <dmitry.sulman@gmail.com>
Since Mockito 5.16.1, MockAccess moved from
org.mockito.internal.creation.bytebuddy.MockAccess to
org.mockito.internal.creation.bytebuddy.access.MockAccess.
Consequently, ProxyProcessorSupport.isInternalLanguageInterface() no
longer recognized it, causing an auto-proxied mock created with the
subclass mock maker and proxyTargetClass=false to receive a JDK proxy
that only implements MockAccess instead of a CGLIB proxy of its own
class.
This commit adds a check for the new package name alongside the
existing one, since older Mockito versions may still be on the
classpath.
Closes gh-37342
Prior to this commit, JdbcClient's BatchSpec bound parameters to a
"current" batch entry and separated consecutive entries via add(). That
style was error-prone, since a missing add() still compiled but
silently merged parameters into a single entry. It also did not lend
itself to providing batch parameters dynamically — for example, from an
existing collection of domain objects.
To address that, this commit replaces the chaining style with
self-contained batch entries. BatchSpec now provides entry(...) methods
that define a single entry — via a Consumer<BatchEntry> callback, a
List of positional parameters, or a Map of named parameters — as well
as entries(...) methods that define one entry per parameter object.
Such calls can be freely combined within the same batch.
The new BatchEntry type exposes only the singular param(...) and
paramSource(...) methods. The add() method as well as the param(...),
params(...), and paramSource(...) methods have been removed from
BatchSpec.
Closes gh-37341
Prior to this commit, both `CssLinkResourceTransformer` implementations
could fail at runtime in case of invalid CSS links (for example, with
out of bounds exceptions).
This commit skips invalid links and writes them out to the resulting CSS
without any transformation.
Fixes gh-37336
Prior to this commit, `ResponseStatusException` would resolve the
"detail" part of a problem detail response from message codes only
(default or custom ones). If the `reason` given as an argument to the
exception was a custom message, it would be overwritten in the process.
This commit ensures that we use custom reason messages when they don't
resolve as message codes.
Fixes gh-36984
This commit documents the semantics for the `#result` SpEL expression
variable for a method that returns a Flux for @Cacheable and
@CachePut, both of which have always collected such a Flux's values
into a List. For such a method, `#result` refers to that List rather
than the Flux itself.
This commit addresses a number of unrelated inconsistencies in the
documentation as well.
See gh-37309
Prior to this commit, ReactiveCachingHandler.processCacheEvicts()
adapted every reactive return value via Mono.from(), which subscribes
for only the first element and cancels the upstream Publisher. For a
@CacheEvict method that returns a Flux, this silently truncated the
returned sequence to its first element. In addition, the `#result`
variable in `condition` SpEL expressions was bound to only that first
emitted element.
To address that, this commit mirrors the existing multi-value handling
in processPutRequest(). When the adapter reports isMultiValue(), a side
Subscriber is subscribed via publish().refCount(2) that exhausts the
Flux and collects its values into a List for eviction, while the
original, unmodified Flux is returned to the caller. Consequently, the
`#result` variable in `condition` SpEL expressions for a Flux-returning
@CacheEvict method is now the full List of emitted elements rather
than just the first element, making it consistent with @Cacheable and
@CachePut.
This commit also improves spr14235AdaptsToReactorFlux() in
CacheReproTests. Previously it exercised @CacheEvict only with a
single-element Flux and never asserted on the returned sequence. Now it
uses a multi-element Flux and verifies that all elements are both
returned to the caller and visible to the `condition` expression.
Last but not least, this commit documents the aforementioned
`#result`/Flux semantics in @CacheEvict's Javadoc and in the reference
manual, since both were previously invalid or incomplete for this
scenario.
Closes gh-37309
`batchArgs[0]` in `NamedParameterJdbcTemplate` and `indexedBatch[0]` in
`DefaultJdbcClient` are already set by
`pscf::newPreparedStatementCreator`, so it is unnecessary to set them
again via `BatchPreparedStatementSetter::setValues`.
Closes gh-37308
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
Both target-class tests asserted the target-interface counter,
leaving the intended pointcut unchecked. Assert the target-class
counter in both the XML and @AspectJ variants.
Closes gh-37310
Signed-off-by: itaekyung <taeyun1411@gmail.com>
Prior to this commit, `DefaultFormattingConversionService` would
register converters with both `DateTimeFormatterRegistrar` and
`DateFormatterRegistrar`, the former also registering the legace date
converters that the latter contributes.
While we cannot change the behavior for `DateTimeFormatterRegistrar` or
`DateFormatterRegistrar` because of their public contract, we can update
the `DefaultFormattingConversionService` to not use
`DateFormatterRegistrar` and register manually the annotation support
that it contributes.
Closes gh-36951