Commit Graph
4877 Commits
Author SHA1 Message Date
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
Brian Clozel 9bedb06b9b Merge branch '7.0.x' 2026-09-04 17:34:11 +02:00
junhyeong9812 4a803961bc Generate compilable code for non-finite floating-point values
PrimitiveDelegate generated code via "$LF" for Float and "(double) $L"
for Double, which emit the value's toString() verbatim. For NaN and
infinities this produced non-compilable source such as "NaNF" or
"(double) Infinity", causing the generated AOT sources to fail to
compile.

Detect NaN (via isNaN, since NaN is never equal to itself) and the
positive/negative infinities, emitting the corresponding constant
field references (Float.NaN, Double.POSITIVE_INFINITY, etc.) through
the "$T" placeholder. Finite values keep their existing handling.

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-09-04 17:23:41 +02:00
Brian Clozel 54b3a8c868 Merge branch '7.0.x' 2026-09-04 17:17:23 +02:00
junhyeong9812 2b5229ff8f Fix reserveMethodNames to reserve each supplied name
GeneratedClass.reserveMethodNames(String...) passed the entire varargs
array to MethodName.of() inside the per-name loop instead of the current
element. Since MethodName.of(String...) joins all parts into a single
camel-case name, reserving two or more names (for example "apply" and
"test") produced "applyTest", and the per-element check
Assert.state(generatedName.equals(reservedMethodName)) failed with an
IllegalStateException. Single-name calls worked only by accident.

Reserve each supplied name individually by passing the loop variable.

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-09-04 17:14:25 +02:00
Patrick Strawderman 658c263cf6 Use immutable map for static cache in TypeDescriptor
Switch to Map.of for the static commonTypesCache field for immutability.

Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
2026-09-04 15:38:40 +02:00
Sam Brannen 21ee87448c Merge branch '7.0.x' 2026-09-04 15:28:48 +02:00
Hyunwoo Jung 8c151f5887 Move BackOff tests to correct package
Closes gh-37241

Signed-off-by: Hyunwoo Jung <hyunwoojung@kakao.com>
2026-09-04 15:27:27 +02:00
Sam Brannen c0519b9bbf Merge branch '7.0.x' 2026-09-04 15:14:36 +02:00
Sam Brannen ea2a26206c Polish contribution
See gh-36914
2026-09-04 15:13:35 +02:00
junhyeong9812 2b276311eb Honor sourceStart offset in AbstractXMLStreamReader#getTextCharacters
Prior to this commit, AbstractXMLStreamReader.getTextCharacters(int
sourceStart, char[], int, int) capped the copy length with
Math.min(length, source.length), ignoring sourceStart. When sourceStart
> 0 and sourceStart + length exceeds the text length, System.arraycopy
read past the end of the source array and threw
ArrayIndexOutOfBoundsException, contrary to the
XMLStreamReader#getTextCharacters contract (copy up to length
characters starting at sourceStart and return the number copied).

To address that, this commit caps the length by the number of
characters remaining from sourceStart.

Closes gh-36914

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-09-04 15:13:35 +02:00
Sam Brannen b5a358019f Polishing 2026-09-04 15:13:35 +02:00
Brian Clozel 136dddb67d Merge branch '7.0.x' 2026-09-03 17:38:29 +02:00
Brian Clozel 6316c06a97 Polishing contribution
See gh-36919
2026-09-03 17:36:26 +02:00
junhyeong9812 ad83d5ebd9 Render parameter type names in ClassFileMethodMetadata
ClassFileMethodMetadata's toString() formatted method parameter types
as packageName() + "." + displayName(). Since ClassDesc.packageName()
is empty for primitive, array and default-package types, these rendered
with a leading dot (for example ".int" and ".String[]") and reference
arrays lost their package. The return type already uses
ClassFileAnnotationMetadata.resolveTypeName(); apply it to the
parameters as well.

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-09-03 17:23:18 +02:00
Sam Brannen ff9192fa8f Merge branch '7.0.x' 2026-09-03 11:49:10 +02:00
Chengang Guan f2fe79e56d Use ArrayList instead of LinkedList in CompositeRetryListener
CompositeRetryListener currently uses LinkedList to store registered
listeners. The primary operation on this list is iteration (traversing
all listeners on every retry lifecycle event). ArrayList provides
better iteration performance due to better cache locality and lower
memory overhead.

Closes gh-37231

Signed-off-by: Chengang Guan <guanchengang@qq.com>
2026-09-03 11:45:36 +02:00
Artyom Tsvirko 2028eb3694 Handle MIME type parameter names case-insensitively
MIME type parameter names are case-insensitive, and MimeType already
stores them in a LinkedCaseInsensitiveMap. Several code paths, however,
still compared them with case-sensitive String.equals().

As a result, MimeType.hashCode() disagreed with MimeType.equals() for
parameter names that differ only in case, breaking the equals/hashCode
contract: text/plain;FOO=bar and text/plain;foo=bar are equal but hash
differently, so one is not found in a hash-based collection holding the
other. MimeType.compareTo() had the same blind spot for the charset
parameter.

MediaType was affected in two further ways: an out-of-range quality
value escaped validation when spelled Q=, and removeQualityValue() left
a Q= parameter in place.

Signed-off-by: Artyom Tsvirko <36863599+lArtiquel@users.noreply.github.com>
2026-08-31 17:30:39 +02:00
junhyeong9812andYash bc66622342 Reject MIME type parameters differing only in case
MIME type parameter names are case-insensitive, but MimeTypeParser
accumulates parameters in a case-sensitive LinkedHashMap. As a result,
duplicate parameters differing only in case (such as "charset" and
"CHARSET") were not rejected and were silently collapsed to the last
value by the case-insensitive parameter map of MimeType.

Accumulate parameters in a LinkedCaseInsensitiveMap so that duplicates
differing only in case map to the same key and are rejected consistently
with exact duplicates.

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
Co-authored-by: Yash <190389954+yashsiwacha@users.noreply.github.com>
2026-08-31 16:23:20 +02:00
Brian Clozel 5524fc6a55 Merge branch '7.0.x' 2026-08-31 12:58:00 +02:00
Manu Sridharan fce57adc31 Update to NullAway 0.14.0 and fix new warnings
See gh-37188

Signed-off-by: Manu Sridharan <msridhar@gmail.com>
2026-08-31 12:57:32 +02:00
Yanming Zhou 2588fb078e Polish ConcurrentLruCache to refine null-safety
Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
2026-08-28 14:53:40 +02:00
Istvan Verhas 752193fca9 Refactor JettyDataBuffer with new JettyVirtualDataBuffer
This commits simplifies the Jetty buffer support by consolidating
the shared logic and delegating operations to the parent class
thanks to the new `JettyVirtualDataBuffer`.

Signed-off-by: Istvan Verhas <vi@mocker.guru>
2026-08-28 14:42:41 +02:00
junhyung8795 17e0daf8a1 Use computeIfAbsent in CommandLineArgs.addOptionArg
Signed-off-by: junhyung8795 <junhyung8795@naver.com>
2026-08-27 17:00:41 +02:00
Brian Clozel df72838ce1 Merge commit 'v7.1.0-M1~1' 2026-08-20 18:18:13 +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 6ee3ef6af5 Avoid unnecessarily synthesizing meta-annotations with attributes
In commit 622fc3edf7, I introduced a check in
TypeMappedAnnotation#isSynthesizable() intended to force synthesis when
an attribute value needs to be resolved from a different level of a
multi-level annotation hierarchy whose root annotation does not
redeclare the target attribute itself.

That check tested if `resolvedMirrors.length > 0` for a
meta-annotation; however, resolvedMirrors is always sized according to
the number of attributes declared by the mapped annotation type,
regardless of whether any of those attributes actually participate in
mirroring or an @⁠AliasFor override. As a result, the check effectively
synthesized any meta-annotation that declares at least one attribute,
which reintroduced the unnecessary-synthesis behavior that commit
d6768ccc18 had fixed, merely narrowed to meta-annotations with
attributes.

This commit replaces that overly broad check with a precise one in
AnnotationTypeMapping#computeSynthesizableFlag(), which now also
considers whether any attribute's value must be resolved from a
different annotation in the meta-annotation hierarchy (tracked via
annotationValueSource). This correctly identifies the original
multi-level hierarchy scenario without over-matching on ordinary
meta-annotations that have nothing to merge or override.

See gh-28704
See gh-28716
Closes gh-37135
2026-08-20 16:32:05 +02:00
greg taube 59a784cb7e Avoid unnecessary allocations for cached annotation mappings
This commit defers creation of the visited annotation types set until a
cache miss occurs, which avoids allocating a HashSet for every cached
annotation mapping lookup while preserving recursive annotation
handling during mapping creation.

Closes gh-37141

Signed-off-by: GT <gregjotau@gmail.com>
2026-08-20 16:27:18 +02:00
김준형 af466ccf63 Fix OptionalToObjectConverter applicability check
OptionalToObjectConverter.matches() used
TypeDescriptor.getElementTypeDescriptor(), which returns null for an
Optional (element types are only resolved for arrays, streams and
collections). ConversionUtils.canConvertElements() then treats a null
source element type as "maybe" and returns true unconditionally, so
ConversionService.canConvert(Optional<X>, target) reported true even
when X is not convertible to the target -- a violation of the
canConvert contract, since the subsequent conversion fails.

To address that, this commit resolves the Optional's element type from
its generic and checks it against the target, mirroring
ObjectToOptionalConverter. A raw or otherwise unresolved element type
remains permissive.

Closes gh-36913

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-08-20 16:19:37 +02:00
junhyeong9812 e8e293a706 Reject write methods not starting with "set" in Property
Prior to this commit, Property.resolveName() located the "set" prefix
of a write method with String.indexOf(), which matches the token
anywhere in the method name. A write method that merely contains "set"
(for example "offsetX" or "upset") was silently accepted and resolved
to a meaningless property name derived from whatever follows the token,
while only names with no "set" token at all were rejected.

To address that, this commit matches the "set" prefix only at the start
of the method name via startsWith(), so that an
IllegalArgumentException is consistently thrown for any write method
candidate that is not a setter.

See gh-36911
Closes gh-37139

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-08-19 18:26:46 +02:00
김준형 f067d40f0a Fix Property name resolution for record-style accessors
Property.resolveName() located the get/is accessor prefix with
String.indexOf, which matches the prefix anywhere in the method name.
A plain accessor whose name embeds such a prefix (for example
budget()) had the wrong portion stripped and resolved to an empty or
wrong property name, which in turn caused the backing field's
annotations to be silently dropped.

Match the get/is prefix only at the start of the method name and do
not strip it when the method is a plain accessor for a data class,
that is, a non-static no-arg method referring to an instance field of
the same name. This supports Java records, Kotlin data classes, and
custom Java data classes alike, without relying on java.lang.Record.

As a consequence, a getter backed by a field of the exact same name
(for example isUrgent()) now resolves to the field name.

Closes gh-36911

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
2026-08-19 18:19:04 +02:00
Sam Brannen a947f9bf79 Merge branch '7.0.x' 2026-08-18 17:14:31 +02: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 a13056f6af Merge branch '7.0.x' 2026-08-18 16:44:50 +02:00