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
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
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>
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>
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
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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