Skip to content

Commit 907c1db

Browse files
committed
Merge branch '6.2.x'
# Conflicts: # spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
2 parents 98de16b + ee804ee commit 907c1db

File tree

8 files changed

+297
-95
lines changed

8 files changed

+297
-95
lines changed

Diff for: spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java

+2-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -104,7 +104,7 @@ public CacheErrorHandler getErrorHandler() {
104104
return valueLoader.call();
105105
}
106106
catch (Exception ex2) {
107-
throw new RuntimeException(ex2);
107+
throw new Cache.ValueRetrievalException(key, valueLoader, ex);
108108
}
109109
}
110110
}
@@ -122,16 +122,12 @@ public CacheErrorHandler getErrorHandler() {
122122
try {
123123
return cache.retrieve(key);
124124
}
125-
catch (Cache.ValueRetrievalException ex) {
126-
throw ex;
127-
}
128125
catch (RuntimeException ex) {
129126
getErrorHandler().handleCacheGetError(ex, cache, key);
130127
return null;
131128
}
132129
}
133130

134-
135131
/**
136132
* Execute {@link Cache#retrieve(Object, Supplier)} on the specified
137133
* {@link Cache} and invoke the error handler if an exception occurs.
@@ -144,9 +140,6 @@ protected <T> CompletableFuture<T> doRetrieve(Cache cache, Object key, Supplier<
144140
try {
145141
return cache.retrieve(key, valueLoader);
146142
}
147-
catch (Cache.ValueRetrievalException ex) {
148-
throw ex;
149-
}
150143
catch (RuntimeException ex) {
151144
getErrorHandler().handleCacheGetError(ex, cache, key);
152145
return valueLoader.get();

Diff for: spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java

+90-14
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Optional;
2727
import java.util.concurrent.CompletableFuture;
2828
import java.util.concurrent.ConcurrentHashMap;
29+
import java.util.concurrent.atomic.AtomicBoolean;
2930
import java.util.function.Supplier;
3031

3132
import org.apache.commons.logging.Log;
@@ -440,13 +441,40 @@ protected void clearMetadataCache() {
440441
return cacheHit;
441442
}
442443

444+
@SuppressWarnings("unchecked")
443445
private @Nullable Object executeSynchronized(CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
444446
CacheOperationContext context = contexts.get(CacheableOperation.class).iterator().next();
445447
if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {
446448
Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);
447449
Cache cache = context.getCaches().iterator().next();
448450
if (CompletableFuture.class.isAssignableFrom(method.getReturnType())) {
449-
return doRetrieve(cache, key, () -> (CompletableFuture<?>) invokeOperation(invoker));
451+
AtomicBoolean invokeFailure = new AtomicBoolean(false);
452+
CompletableFuture<?> result = doRetrieve(cache, key,
453+
() -> {
454+
CompletableFuture<?> invokeResult = ((CompletableFuture<?>) invokeOperation(invoker));
455+
if (invokeResult == null) {
456+
return null;
457+
}
458+
return invokeResult.exceptionallyCompose(ex -> {
459+
invokeFailure.set(true);
460+
return CompletableFuture.failedFuture(ex);
461+
});
462+
});
463+
return result.exceptionallyCompose(ex -> {
464+
if (!(ex instanceof RuntimeException rex)) {
465+
return CompletableFuture.failedFuture(ex);
466+
}
467+
try {
468+
getErrorHandler().handleCacheGetError(rex, cache, key);
469+
if (invokeFailure.get()) {
470+
return CompletableFuture.failedFuture(ex);
471+
}
472+
return (CompletableFuture) invokeOperation(invoker);
473+
}
474+
catch (Throwable ex2) {
475+
return CompletableFuture.failedFuture(ex2);
476+
}
477+
});
450478
}
451479
if (this.reactiveCachingHandler != null) {
452480
Object returnValue = this.reactiveCachingHandler.executeSynchronized(invoker, method, cache, key);
@@ -505,9 +533,17 @@ protected void clearMetadataCache() {
505533
if (CompletableFuture.class.isAssignableFrom(context.getMethod().getReturnType())) {
506534
CompletableFuture<?> result = doRetrieve(cache, key);
507535
if (result != null) {
508-
return result.exceptionally(ex -> {
509-
getErrorHandler().handleCacheGetError((RuntimeException) ex, cache, key);
510-
return null;
536+
return result.exceptionallyCompose(ex -> {
537+
if (!(ex instanceof RuntimeException rex)) {
538+
return CompletableFuture.failedFuture(ex);
539+
}
540+
try {
541+
getErrorHandler().handleCacheGetError(rex, cache, key);
542+
return CompletableFuture.completedFuture(null);
543+
}
544+
catch (Throwable ex2) {
545+
return CompletableFuture.failedFuture(ex2);
546+
}
511547
}).thenCompose(value -> (CompletableFuture<?>) evaluate(
512548
(value != null ? CompletableFuture.completedFuture(unwrapCacheValue(value)) : null),
513549
invoker, method, contexts));
@@ -1075,31 +1111,71 @@ private class ReactiveCachingHandler {
10751111

10761112
private final ReactiveAdapterRegistry registry = ReactiveAdapterRegistry.getSharedInstance();
10771113

1114+
@SuppressWarnings({"rawtypes", "unchecked"})
10781115
public @Nullable Object executeSynchronized(CacheOperationInvoker invoker, Method method, Cache cache, Object key) {
1116+
AtomicBoolean invokeFailure = new AtomicBoolean(false);
10791117
ReactiveAdapter adapter = this.registry.getAdapter(method.getReturnType());
10801118
if (adapter != null) {
10811119
if (adapter.isMultiValue()) {
10821120
// Flux or similar
10831121
return adapter.fromPublisher(Flux.from(Mono.fromFuture(
1084-
cache.retrieve(key,
1085-
() -> Flux.from(adapter.toPublisher(invokeOperation(invoker))).collectList().toFuture())))
1086-
.flatMap(Flux::fromIterable));
1122+
doRetrieve(cache, key,
1123+
() -> Flux.from(adapter.toPublisher(invokeOperation(invoker))).collectList().doOnError(ex -> invokeFailure.set(true)).toFuture())))
1124+
.flatMap(Flux::fromIterable)
1125+
.onErrorResume(RuntimeException.class, ex -> {
1126+
try {
1127+
getErrorHandler().handleCacheGetError(ex, cache, key);
1128+
if (invokeFailure.get()) {
1129+
return Flux.error(ex);
1130+
}
1131+
return Flux.from(adapter.toPublisher(invokeOperation(invoker)));
1132+
}
1133+
catch (RuntimeException exception) {
1134+
return Flux.error(exception);
1135+
}
1136+
}));
10871137
}
10881138
else {
10891139
// Mono or similar
10901140
return adapter.fromPublisher(Mono.fromFuture(
1091-
cache.retrieve(key,
1092-
() -> Mono.from(adapter.toPublisher(invokeOperation(invoker))).toFuture())));
1141+
doRetrieve(cache, key,
1142+
() -> Mono.from(adapter.toPublisher(invokeOperation(invoker))).doOnError(ex -> invokeFailure.set(true)).toFuture()))
1143+
.onErrorResume(RuntimeException.class, ex -> {
1144+
try {
1145+
getErrorHandler().handleCacheGetError(ex, cache, key);
1146+
if (invokeFailure.get()) {
1147+
return Mono.error(ex);
1148+
}
1149+
return Mono.from(adapter.toPublisher(invokeOperation(invoker)));
1150+
}
1151+
catch (RuntimeException exception) {
1152+
return Mono.error(exception);
1153+
}
1154+
}));
10931155
}
10941156
}
10951157
if (KotlinDetector.isSuspendingFunction(method)) {
1096-
return Mono.fromFuture(cache.retrieve(key, () -> {
1097-
Mono<?> mono = ((Mono<?>) invokeOperation(invoker));
1098-
if (mono == null) {
1158+
return Mono.fromFuture(doRetrieve(cache, key, () -> {
1159+
Mono<?> mono = (Mono<?>) invokeOperation(invoker);
1160+
if (mono != null) {
1161+
mono = mono.doOnError(ex -> invokeFailure.set(true));
1162+
}
1163+
else {
10991164
mono = Mono.empty();
11001165
}
11011166
return mono.toFuture();
1102-
}));
1167+
})).onErrorResume(RuntimeException.class, ex -> {
1168+
try {
1169+
getErrorHandler().handleCacheGetError(ex, cache, key);
1170+
if (invokeFailure.get()) {
1171+
return Mono.error(ex);
1172+
}
1173+
return (Mono) invokeOperation(invoker);
1174+
}
1175+
catch (RuntimeException exception) {
1176+
return Mono.error(exception);
1177+
}
1178+
});
11031179
}
11041180
return NOT_HANDLED;
11051181
}
@@ -1113,7 +1189,7 @@ private class ReactiveCachingHandler {
11131189
return NOT_HANDLED;
11141190
}
11151191

1116-
@SuppressWarnings({ "unchecked", "rawtypes" })
1192+
@SuppressWarnings({"rawtypes", "unchecked"})
11171193
public @Nullable Object findInCaches(CacheOperationContext context, Cache cache, Object key,
11181194
CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {
11191195

Diff for: spring-context/src/main/java/org/springframework/context/aot/AbstractAotProcessor.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.context.aot;
1818

1919
import java.io.IOException;
20+
import java.io.UncheckedIOException;
2021
import java.nio.file.Path;
2122

2223
import org.jspecify.annotations.Nullable;
@@ -103,7 +104,7 @@ private void deleteExistingOutput(Path... paths) {
103104
FileSystemUtils.deleteRecursively(path);
104105
}
105106
catch (IOException ex) {
106-
throw new RuntimeException("Failed to delete existing output in '" + path + "'");
107+
throw new UncheckedIOException("Failed to delete existing output in '" + path + "'", ex);
107108
}
108109
}
109110
}

Diff for: spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,9 @@ static final class SubscribingRunnable implements SchedulingAwareRunnable {
204204
final Supplier<ScheduledTaskObservationContext> contextSupplier;
205205

206206
SubscribingRunnable(Publisher<?> publisher, boolean shouldBlock,
207-
@Nullable String qualifier, List<Runnable> subscriptionTrackerRegistry,
208-
String displayName, Supplier<ObservationRegistry> observationRegistrySupplier,
209-
Supplier<ScheduledTaskObservationContext> contextSupplier) {
207+
@Nullable String qualifier, List<Runnable> subscriptionTrackerRegistry,
208+
String displayName, Supplier<ObservationRegistry> observationRegistrySupplier,
209+
Supplier<ScheduledTaskObservationContext> contextSupplier) {
210210

211211
this.publisher = publisher;
212212
this.shouldBlock = shouldBlock;
@@ -234,7 +234,7 @@ public void run() {
234234
latch.await();
235235
}
236236
catch (InterruptedException ex) {
237-
throw new RuntimeException(ex);
237+
Thread.currentThread().interrupt();
238238
}
239239
}
240240
else {

0 commit comments

Comments
 (0)