Use helpers from java.nio.file.Files for some methods in FileCopyUtils.
Additionally, add unit tests for the various file-related methods.
Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
Prior to this commit, "new RetryTask<>" declarations whose
TaskCallbacks (implemented as lambda expressions) did not actually
throw an exception resulted in a compilation error in Eclipse:
"Unhandled exception type Exception".
This is due to the fact that RetryTask is declared with "E extends
Exception", and the Eclipse compiler therefore infers that the lambda
expression potentially throws a checked Exception.
To address that, this commit explicitly declares that the affected
lambda expressions throw unchecked RuntimeExceptions:
"new RetryTask<String, RuntimeException>"
This commits udpates ConverterFactory#getConverter to accept both
nullable and non-null T in the Converter return value.
Flexible nullability at ConverterFactory type level would have been
ideal, but is not possible due to how Kotlin deals with Class<T> when
T is nullable.
See gh-36063
In gh-35947, the `Converter` contract was refined to allow for nullable
return values. This created a mismatch with the `ConverterFactory`
contract.
This commit fixes this mismatch by allowing nullable return values in
`Converter` instances created by `ConverterFactory`.
Fixes gh-36063
This includes MethodParameter resolving getParameterName() by default now.
initParameterNameDiscovery(null) can be used to suppress such resolution.
Closes gh-36024
The error message in such cases now indicates that the retry process
is being aborted preemptively due to pending sleep time.
For example:
Retry policy for operation 'myMethod' would exceed timeout (5 ms) due
to pending sleep time (10 ms); preemptively aborting execution
See gh-35963
Specifically, this commit introduces:
- timeout and timeoutString attributes in @Retryable
- a default getTimeout() method in RetryPolicy
- a timeout() method in RetryPolicy.Builder
- an onRetryPolicyTimeout() callback in RetryListener
- support for checking exceeded timeouts in RetryTemplate (also used
for imperative method invocations with @Retryable)
- support for checking exceeded timeouts in reactive pipelines with
@Retryable
Closes gh-35963
Prior to this commit, if a meta-annotation could not be loaded because
its attributes referenced types not present in the classpath, the
meta-annotation was silently ignored.
To improve diagnostics for such use cases, this commit introduces WARN
support in IntrospectionFailureLogger and revises AttributeMethods.canLoad()
to log a warning if a meta-annotation is ignored due to an exception
thrown while attempting to load its attributes.
For example, a warning similar to the following is now logged in such
cases.
WARN o.s.c.a.MergedAnnotation -
Failed to introspect meta-annotation @example.MyAnnotation on class
example.Config: java.lang.TypeNotPresentException:
Type example.OptionalDependency not present
This commit also improves log messages in AnnotationTypeMappings.
Closes gh-35927
This commit refines BindingReflectionHintsRegistrar with additional
dynamic hints for application-defined types, main core Java conversion
ones being already covered by ObjectToObjectConverterRuntimeHints.
Closes gh-35847
The Spliterators returned by values, entrySet, and keySet incorrectly
reported the SIZED characteristic, instead of CONCURRENT. This could
lead to bugs when the map is concurrently modified during a stream
operation.
For keySet and values, the incorrect characteristics are inherited from
AbstractMap, so to rectify that the respective methods are overridden,
and custom collections are provided that report the correct Spliterator
characteristics.
Closes gh-35817
Signed-off-by: Patrick Strawderman <pstrawderman@netflix.com>
This commit introduces a KotlinDetector#hasSerializableAnnotation
utility method designed to detect types annotated with
`@Serializable` at type or generics level.
See gh-35761
Prior to this commit, the maximum number of retry attempts was
configured via @Retryable(maxAttempts = ...),
RetryPolicy.withMaxAttempts(), and RetryPolicy.Builder.maxAttempts().
However, this led to confusion for developers who were unsure if
"max attempts" referred to the "total attempts" (i.e., initial attempt
plus retry attempts) or only the "retry attempts".
To improve the programming model, this commit renames maxAttempts to
maxRetries in @Retryable and RetryPolicy.Builder and renames
RetryPolicy.withMaxAttempts() to RetryPolicy.withMaxRetries(). In
addition, this commit updates the documentation to consistently point
out that total attempts = 1 initial attempt + maxRetries attempts.
Closes gh-35772
When JAR manifest Class-Path entries contain absolute paths (as Gradle
creates on Windows for long classpaths), PathMatchingResourcePatternResolver
incorrectly rejected them.
Fixes#35730
Signed-off-by: Artur Signell <artur@vaadin.com>
When concurrency limiting is enabled via setConcurrencyLimit() and
thread creation fails in doExecute() (e.g., OutOfMemoryError from
Thread.start()), the concurrency permit acquired by beforeAccess()
is never released because TaskTrackingRunnable.run() never executes.
This causes the concurrency count to permanently remain at the limit,
causing all subsequent task submissions to block forever in
ConcurrencyThrottleSupport.onLimitReached().
Root cause:
- beforeAccess() increments concurrencyCount
- doExecute() throws Error before thread starts
- TaskTrackingRunnable.run() never executes
- afterAccess() in finally block never called
- Concurrency permit permanently leaked
Solution:
Wrap doExecute() in try-catch block in the concurrency throttle path
and call afterAccess() in catch block to ensure permit is always
released, even when thread creation fails.
The fix only applies to the concurrency throttle path. The
activeThreads-only path does not need fixing because it never calls
beforeAccess(), so there is no permit to leak.
Test approach:
The test simulates thread creation failure and verifies that a
subsequent execution does not deadlock. The first execution should
fail with some exception (type doesn't matter), and the second
execution should complete within timeout if the permit was properly
released.
Signed-off-by: Park Juhyeong <wngud5957@naver.com>
Previously, SingletonSupplier stored "null" in singletonInstance when
the supplied instance was "null". On subsequent get() calls, this was
treated as "uninitialized" and triggered another attempt to obtain an
instance from the Supplier.
This commit ensures that a "null" returned from the instanceSupplier or
defaultSupplier is handled correctly, so that subsequent calls to get()
return "null" consistently instead of repeatedly invoking the Supplier.
Closes gh-35380
Signed-off-by: Dmytro Nosan <dimanosan@gmail.com>
Prior to this commit, getPubliclyAccessibleMethodIfPossible() in
ClassUtils incorrectly returned a hidden static method as an
"equivalent" method for a static method with the same signature;
however, a static method cannot be overridden and therefore has no
"equivalent" method in a super type.
To fix that bug, this commit immediately aborts the search for an
"equivalent" publicly accessible method when the original method is a
static method.
See gh-33216
See gh-35189
See gh-35556
Closes gh-35667
As reported in gh-34651, `DataBuffer#getByte` can be inefficient for
some implementations, as bound checks are performed for each call.
This commit introduces a new `forEachByte` method that helps with
traversing operations without paying the bound check cost for each byte.
Closes gh-35623