Commit Graph
4910 Commits
Author SHA1 Message Date
Sam Brannen c259185b52 Polish CompositeMap and CollectionUtils 2026-10-02 16:41:39 +02:00
Yanming Zhou f5a7123044 Honor Collection.remove() contract in CompositeCollection
Before this commit, `second.remove(o)` was called no matter whether
`first.remove(o)` returned `true` or `false`. If the element was present
in both collections, it was removed from both, which violates the
`Collection.remove(Object)` contract of removing a single instance.

Closes gh-37332

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-10-02 16:26:53 +02:00
Sam Brannen 0ff69cfdb6 Merge branch '7.0.x' 2026-10-02 15:13:53 +02:00
Rene Schakmann 23cdf8465c Clarify ConcurrentReferenceHashMap reference semantics
Prior to this commit, the Javadoc for ConcurrentReferenceHashMap
stated that soft or weak references are used for both keys and values.

However, the references are applied to the internal map entries, each
of which holds strong references to its key and value. Consequently,
an entry may be discarded even if its key and value are still strongly
reachable from elsewhere, which differs from the semantics of
WeakHashMap.

This commit revises the class-level Javadoc as well as the Javadoc for
the ReferenceType constants to document this behavior.

See gh-24253
Closes gh-37357

Signed-off-by: rene.schakmann <rene.schakmann@reetgroup.com>
2026-10-02 15:13:24 +02:00
Chengang Guan 5e7630469c Fix container detection in RepeatableContainers.standardRepeatables()
StandardRepeatableContainers.computeRepeatedAnnotationsMethod()
previously treated any annotation as a container annotation if it
merely declared a `value` attribute returning an array of a
@⁠Repeatable annotated type, without verifying that the repeatable
annotation actually references the candidate container via
@⁠Repeatable.value().

Consequently, an unrelated annotation that happened to have the same
shape as the official container (e.g. a "fake" container with a `value`
attribute returning the same repeatable type) was incorrectly
recognized as a container.

This commit aligns the detection logic with the Java language semantics
by additionally asserting that the container type declared in
@⁠Repeatable.value() is identical to the candidate annotation type.

Closes gh-37326

Signed-off-by: Chengang Guan <guanchengang@qq.com>
2026-09-30 17:41:07 +02:00
Sam Brannen 9289f71ad7 Merge branch '7.0.x' 2026-09-30 17:14:52 +02:00
Sam Brannen 3a600481d2 Polish code base
- Remove redundant super() calls from constructors
- Add missing @⁠Override annotations
- Use switch rules in JdkClientHttpRequest and RfcUriParser
- Use instanceof pattern matching
- Use method references instead of trivial lambda expressions
- Use lambda expressions instead of anonymous inner classes
- Remove unused code and redundant semicolons
- Use braces with if-blocks
2026-09-30 17:08:47 +02:00
Brian Clozel 9a87fa6d12 Add DataBuffers utility class
Prior to this commit, `DataBufferUtils` would implement many utility
static methods for managing and processing `DataBuffer` instances.
`DataBuffer` is tightly linked to the reactive space, but its usage
shoudn't be limited to applications that use `Publisher` extensively.

This commit gathers methods that do not depend on `Publisher` into a new
`DataBuffers` type that `DataBufferUtils` now extend. This allows to use
`DataBuffer` instances in a non-reactive case.

Fixes gh-37353
2026-09-30 15:58:46 +02:00
Sam Brannen 634d187130 Merge branch '7.0.x' 2026-09-30 13:43:28 +02:00
Sam Brannen 043442a2a1 Test single-value to primitive array adaptation via @⁠AliasFor
This commit adds a test to MergedAnnotationsTests that verifies a
single primitive attribute in a composed annotation can be aliased via
@⁠AliasFor to a primitive array attribute in a meta-annotation.

See gh-37349
2026-09-30 13:42:35 +02:00
Chengang Guan 6afb65b225 Fix single-value adaptation for primitive array types in TypeMappedAnnotation
Prior to this commit, `adaptForAttribute(Method, Object)` created
the wrapping array from `value.getClass()` when a single non-array
value was provided for an array attribute. This worked for object
array types but failed for primitive array types: wrapping a boxed
value produced a boxed array, which then failed the compatibility
check and threw an `IllegalStateException`.

This commit derives the component type from the declared attribute
type when it is assignable from the value type, falling back to
`value.getClass()` otherwise. The existing adaptation path for
object array types is therefore preserved, and all primitive array
types now accept a single value.

The accompanying test covers single-value wrapping for every array
type declared by ArrayTypes.

Closes gh-37349

Signed-off-by: Chengang Guan <guanchengang@qq.com>
2026-09-30 13:37:25 +02:00
Sam Brannen 9b8850694d Merge branch '7.0.x' 2026-09-30 12:47:51 +02:00
김준형 1b4955e49f Avoid phantom keys in LinkedCaseInsensitiveMap.computeIfAbsent
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>
2026-09-30 12:47:30 +02:00
Chengang Guan 30d025e57e Fix internal Javadoc link in AttributeMethods
Closes gh-37337

Signed-off-by: Chengang Guan <guanchengang@qq.com>
2026-09-28 10:45:38 +02:00
Sam Brannen b096db843b Merge branch '7.0.x' 2026-09-28 10:44:15 +02:00
Tran Ngoc Nhan e19e17eca5 Add missing enclosing single quotes in Javadoc
Closes gh-37338

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-09-28 10:43:38 +02:00
Sam Brannen 82dd9480f2 Merge branch '7.0.x' 2026-09-20 14:58:32 +02:00
Tran Ngoc Nhan a8608e681b Remove redundant whitespace in exception messages
Closes gh-37277

Signed-off-by: Tran Ngoc Nhan <ngocnhan.tran1996@gmail.com>
2026-09-20 14:58:09 +02:00
Juergen Hoeller b9fa062918 Merge branch '7.0.x' 2026-09-18 21:00:53 +02:00
Juergen Hoeller 83ecf67455 Match manifest-specified jar names with pre-encoded escape sequence
Closes gh-37280
2026-09-18 20:58:46 +02:00
Sam Brannen bd1616b0aa Merge branch '7.0.x' 2026-09-18 15:54:08 +02:00
guanchengang b49252ed66 Avoid useless queue ops in ConcurrentLruCache.clear()
ConcurrentLruCache.clear() previously drained write operations before
cleaning up the cache. This could re-enqueue nodes that clear() was
about to remove, causing useless evictionQueue operations. Now clear()
iterates the cache values directly, removes and marks nodes as removed
first, and drains write operations afterward. Since AddTask fails
silently after a node is marked removed, this avoids the no-op work
and improves performance.

See gh-37287

Closes gh-37292

Signed-off-by: Chengang Guan <guanchengang@qq.com>
2026-09-18 15:53:18 +02:00
Yanming Zhou c1ba31c40f Use "isEmpty" to check if a collection is empty
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-09-18 14:14:36 +02:00
Brian Clozel 4cdd314850 Merge branch '7.0.x' 2026-09-18 14:09:23 +02:00
Brian Clozel 5d32f6719a Fix flaky test in RetryTemplateTests
`RetryTemplateTests` can, under load, break the build because of a flaky
test: "retryableWithTimeoutExceededAfterSecondRetry".
This usually happens when many cores are busy and the timeout check
runs before each retry attempt.
This commit extends the timeout to avoid such cases and failures.
2026-09-18 14:05:38 +02:00
Sam Brannen 884975b7eb Polish AOT generated resources support
This commit fixes Javadoc typos, grammar, and incorrect/swapped
references; avoids redundant self-validation in GeneratedResource's
createOrValidate(); adds missing Javadoc; and adds/renames tests
accordingly.

See gh-35862
2026-09-18 13:25:21 +02:00
Stéphane Nicoll 496ed729a0 Add support for AOT generated resources
This commit updates the AOT infrastructure to handle generated resources
in a similar fashion than generated classes: naming conventions, feature
prefixes, and uniqueness are applied.

The new abstraction also provides a more explicit contract that guides
users to either create the resource or create it if it does not exist
and validate its content if it does.

As part of this change ClassNameGenerator has been renamed to
NameGenerator as it is responsible to generate names for both classes
and resources.

Closes gh-35862
2026-09-17 18:22:26 +02:00
Sam Brannen e2cc271e0c Merge branch '7.0.x' 2026-09-17 12:52:59 +02:00
Sam Brannen bb7ea37f1b Drain pending writes before evicting in ConcurrentLruCache.clear()
Prior to this commit, clear() polled the eviction queue to remove
entries and only afterward drained the pending write operations queue.

Consequently, a put() whose AddTask had not yet been linked into the
eviction queue -- for example, because it lost the race to self-drain
while clear() held the eviction lock -- would only be applied by that
trailing drain, linking the entry into the eviction queue right after
clear() had already finished removing everything it could see.

The practical effect was that an entry already fully added to the cache
could still be present immediately after clear() returned, with no
further concurrent activity required at that point.

To address that, this commit revises clear() so that it drains the
pending write operations queue before polling the eviction queue, so
any write that was already queued gets cleaned up along with everything
else. However, a put() that is genuinely concurrent with an in-progress
clear() call can still survive, which is consistent with the cache's
weak-consistency design.

Thanks to @guanchengang for raising gh-37286, which prompted this fix.

Closes gh-37287
2026-09-17 12:45:42 +02:00
Sam Brannen 6504e75669 Merge branch '7.0.x' 2026-09-14 18:17:15 +02:00
Sam Brannen 3178df92bd Consistently use while (true) instead of for (;;) across the codebase 2026-09-14 18:15:02 +02:00
Sam Brannen 566887d573 Merge branch '7.0.x' 2026-09-14 18:07:12 +02:00
김준형 c1aa1b7405 Prevent double size decrement in ConcurrentLruCache
markAsRemoved() transitions a node to the removed state and decrements
the current size, but it did not check whether the node had already
been removed. The eviction path and an explicit removal can process
the same node in sequence: when a write drain runs a queued AddTask
whose eviction polls a node that a concurrent remove(K) has already
taken out of the cache, the eviction decrements the size, and the
queued RemovalTask for the same node decrements it again. The sibling
transition markForRemoval() guards against invalid transitions; this one
did not.

Each extra decrement makes currentSize permanently smaller than the
number of cached entries, so eviction stops triggering and the cache
exceeds its capacity for good, silently. A bounded two-thread stress
run accumulates the drift reliably: before the change the cache
stabilized far above its capacity in 20 out of 20 runs.

markAsRemoved() now returns without decrementing when the entry is
already in the removed state, mirroring the guard in markForRemoval().
The removed state is terminal, so each node is counted down exactly
once. The new test races explicit removals against eviction and then
verifies that the cache converges back to its capacity; it also
asserts that the racing thread ran and terminated cleanly.

Closes gh-37268

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-09-14 18:06:47 +02:00
Sam Brannen 05a1075b69 Merge branch '7.0.x' 2026-09-14 15:02:41 +02:00
Hyunwoo Jung 4898ed3ad8 Fix message supplier coverage in AssertTests
Closes gh-37255

Signed-off-by: Hyunwoo Jung <hyunwoojung@kakao.com>
2026-09-14 15:01:52 +02:00
Sam Brannen 9f8a476f94 Merge branch '7.0.x' 2026-09-14 14:51:44 +02:00
Sam Brannen f768641c08 Polish contribution
See gh-37254
2026-09-14 14:50:45 +02:00
Hyunwoo Jung 01a23e32b5 Fix CollectionToCollectionConverterTests
Closes gh-37254

Signed-off-by: Hyunwoo Jung <hyunwoojung@kakao.com>
2026-09-14 14:41:06 +02:00
Sam Brannen afdbebee70 Merge branch '7.0.x' 2026-09-14 14:39:51 +02:00
Hyunwoo Jung 9d1156f1fd Avoid redundant filtering in FilteredMap.size()
Since keySet() already applies the filter, size() evaluated the
predicate twice for every accepted key.

This commit uses delegate.keySet() instead, avoiding the second
evaluation as well as a FilteredSet and FilteredIterator allocation.

Closes gh-37256

Signed-off-by: Hyunwoo Jung <hyunwoojung@kakao.com>
2026-09-14 14:31:42 +02:00
Sam Brannen 8d50a5b724 Merge branch '7.0.x' 2026-09-10 16:27:35 +02:00
Sam Brannen b96592e4af Guard CharSequence-based logging methods in LogAccessor
Prior to this commit, LogAccessor's CharSequence-based logging methods
delegated directly to the corresponding method on the underlying
commons-logging Log instance without first checking whether the target
level was enabled. This differed from the Supplier-based overloads,
which have checked isXxxEnabled() before delegating since Spring
Framework 5.2.9.

That asymmetry was harmless as long as spring-jcl supplied the
underlying Log implementation, since its SLF4J adapter itself checked
the level before rendering the message. However, since Spring Framework
7 replaced spring-jcl with Apache commons-logging, whose SLF4J adapters
call String.valueOf(message) unconditionally, any CharSequence argument
-- most notably a LogMessage supplied via LogMessage.format(...) or
LogMessage.of(...) -- is now rendered eagerly, even when the
corresponding level is disabled. Since LogMessage exists specifically
to defer that work, and the idiom is used extensively throughout the
framework and its portfolio projects, this leads to unnecessary
computation and allocation whenever logging is disabled.

To address this, this commit adds the same isXxxEnabled() guard to all
twelve CharSequence-based methods in LogAccessor, matching the
existing Supplier-based overloads and making LogAccessor's laziness
guarantee independent of the underlying Log implementation.

This commit also introduces LogAccessorTests, which verifies that a
lazily rendering LogMessage passed to one of the CharSequence-based
methods is only rendered when the corresponding level is enabled.

See gh-25741
Closes gh-37266
2026-09-10 16:17:34 +02:00
Sam Brannen 9a396c8ed4 Improve Javadoc for LogAccessor 2026-09-10 16:08:23 +02:00
Brian Clozel 60b9f4cd3a Merge branch '7.0.x' 2026-09-09 14:56:35 +02:00
junhyeong9812 d3d8e05fa9 Complete empty Uni instances from the Mutiny reactive adapter
The Mutiny Uni adapter registers its empty-value supplier as
Uni.createFrom().nothing(), which returns a Uni that never signals an
item, a failure, or completion. Every sibling registration supplies an
empty value that completes immediately: Mono.empty(), Maybe.empty(),
Completable.complete(), and CompletableDeferred(null); the Multi
registration uses Multi.createFrom().empty() as well.

ReactiveAdapter.toPublisher(null) substitutes that empty value whenever
a null source needs to be adapted, for example when a WebFlux handler
method with a Uni return type returns null. With a never-completing
empty value the resulting Publisher emits no signal at all, so the
response is never written and the request hangs until a timeout,
whereas the same handler declared with Mono completes empty. The
adapter also becomes asymmetric with its own fromPublisher function,
which adapts an empty Publisher to a Uni that completes with a null
item.

The supplier now uses Uni.createFrom().nullItem(), whose conversion to
a Publisher completes without emitting an item, matching the sibling
adapters and the round-trip through fromPublisher. The descriptor is
shared by the Mutiny 1 and Mutiny 2 registrations, so both paths are
covered.

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-09-09 14:47:10 +02:00
Sam Brannen 572850bdcf Merge branch '7.0.x' 2026-09-08 13:30:50 +02:00
MoonFruitandSam Brannen e2fae069dc Avoid exception in ConversionService.canConvert() for Enum targets
Prior to this commit, ConversionService#canConvert(Class, Class)
threw an IllegalArgumentException when invoked with Enum.class as the
target type (i.e., `canConvert(String.class, Enum.class)`), because
ConverterFactory#getConverter() in StringToEnumConverterFactory and
IntegerToEnumConverterFactory eagerly resolved the concrete enum type.

To address that, StringToEnumConverterFactory and
IntegerToEnumConverterFactory now implement ConditionalConverter so
that matches() can reject non-concrete-enum targets before
getConverter() is ever invoked.

Closes gh-34532

Signed-off-by: MoonFruit <dkmoonfruit@gmail.com>

Co-authored-by: Sam Brannen <104798+sbrannen@users.noreply.github.com>
2026-09-08 13:29:30 +02:00
Sam Brannen 42fe29218b Merge branch '7.0.x' 2026-09-05 13:42:41 +02:00
Sam Brannen 35d8c4d06f Align synthesized annotation toString() with JDK for NaN/Infinity
Closes gh-37244
2026-09-05 13:37:06 +02:00
Sam Brannen c1d241928c Rename maxAttemptsReached() to maxElapsedTimeReached() and organize tests 2026-09-05 13:08:12 +02:00