Skip to content

Commit 5a3ad6b

Browse files
committed
Late key generation for consistent evaluation of unless expressions
Includes removal of evict step on pipeline exception, retaining a previous cache value and avoiding an incomplete key (for consistency with non-reactive caching). Closes gh-31626
1 parent 1410c46 commit 5a3ad6b

File tree

2 files changed

+36
-36
lines changed

2 files changed

+36
-36
lines changed

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

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -652,9 +652,8 @@ private void collectPutRequests(Collection<CacheOperationContext> contexts,
652652
@Nullable Object result, Collection<CachePutRequest> putRequests) {
653653

654654
for (CacheOperationContext context : contexts) {
655-
if (isConditionPassing(context, result) && context.canPutToCache(result)) {
656-
Object key = generateKey(context, result);
657-
putRequests.add(new CachePutRequest(context, key));
655+
if (isConditionPassing(context, result)) {
656+
putRequests.add(new CachePutRequest(context));
658657
}
659658
}
660659
}
@@ -943,22 +942,16 @@ private class CachePutRequest {
943942

944943
private final CacheOperationContext context;
945944

946-
private final Object key;
947-
948-
public CachePutRequest(CacheOperationContext context, Object key) {
945+
public CachePutRequest(CacheOperationContext context) {
949946
this.context = context;
950-
this.key = key;
951947
}
952948

953949
@Nullable
954950
public Object apply(@Nullable Object result) {
955951
if (result instanceof CompletableFuture<?> future) {
956952
return future.whenComplete((value, ex) -> {
957-
if (ex != null) {
958-
performEvict(ex);
959-
}
960-
else {
961-
performPut(value);
953+
if (ex == null) {
954+
performCachePut(value);
962955
}
963956
});
964957
}
@@ -968,27 +961,20 @@ public Object apply(@Nullable Object result) {
968961
return returnValue;
969962
}
970963
}
971-
performPut(result);
964+
performCachePut(result);
972965
return null;
973966
}
974967

975-
void performPut(@Nullable Object value) {
976-
if (logger.isTraceEnabled()) {
977-
logger.trace("Creating cache entry for key '" + this.key + "' in cache(s) " +
978-
this.context.getCacheNames());
979-
}
980-
for (Cache cache : this.context.getCaches()) {
981-
doPut(cache, this.key, value);
982-
}
983-
}
984-
985-
void performEvict(Throwable cause) {
986-
if (logger.isTraceEnabled()) {
987-
logger.trace("Removing cache entry for key '" + this.key + "' from cache(s) " +
988-
this.context.getCacheNames() + " due to exception: " + cause);
989-
}
990-
for (Cache cache : this.context.getCaches()) {
991-
doEvict(cache, this.key, false);
968+
public void performCachePut(@Nullable Object value) {
969+
if (this.context.canPutToCache(value)) {
970+
Object key = generateKey(this.context, value);
971+
if (logger.isTraceEnabled()) {
972+
logger.trace("Creating cache entry for key '" + key + "' in cache(s) " +
973+
this.context.getCacheNames());
974+
}
975+
for (Cache cache : this.context.getCaches()) {
976+
doPut(cache, key, value);
977+
}
992978
}
993979
}
994980
}
@@ -1017,11 +1003,10 @@ public void onNext(Object o) {
10171003
}
10181004
@Override
10191005
public void onError(Throwable t) {
1020-
this.request.performEvict(t);
10211006
}
10221007
@Override
10231008
public void onComplete() {
1024-
this.request.performPut(this.cacheValue);
1009+
this.request.performCachePut(this.cacheValue);
10251010
}
10261011
}
10271012

@@ -1107,7 +1092,7 @@ public Object processPutRequest(CachePutRequest request, @Nullable Object result
11071092
}
11081093
else {
11091094
return adapter.fromPublisher(Mono.from(adapter.toPublisher(result))
1110-
.doOnSuccess(request::performPut).doOnError(request::performEvict));
1095+
.doOnSuccess(request::performCachePut));
11111096
}
11121097
}
11131098
return NOT_HANDLED;

spring-context/src/test/java/org/springframework/cache/CacheReproTests.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ void spr14235AdaptsToCompletableFuture() {
197197
assertThat(bean.findById("tb1").join()).isSameAs(tb);
198198
assertThat(cache.get("tb1").get()).isSameAs(tb);
199199

200+
tb = bean.findById("tb2").join();
201+
assertThat(tb).isNotNull();
202+
assertThat(bean.findById("tb2").join()).isNotSameAs(tb);
203+
assertThat(cache.get("tb2")).isNull();
204+
200205
context.close();
201206
}
202207

@@ -247,6 +252,11 @@ void spr14235AdaptsToReactorMono() {
247252
assertThat(bean.findById("tb1").block()).isSameAs(tb);
248253
assertThat(cache.get("tb1").get()).isSameAs(tb);
249254

255+
tb = bean.findById("tb2").block();
256+
assertThat(tb).isNotNull();
257+
assertThat(bean.findById("tb2").block()).isNotSameAs(tb);
258+
assertThat(cache.get("tb2")).isNull();
259+
250260
context.close();
251261
}
252262

@@ -297,6 +307,11 @@ void spr14235AdaptsToReactorFlux() {
297307
assertThat(bean.findById("tb1").collectList().block()).isEqualTo(tb);
298308
assertThat(cache.get("tb1").get()).isEqualTo(tb);
299309

310+
tb = bean.findById("tb2").collectList().block();
311+
assertThat(tb).isNotEmpty();
312+
assertThat(bean.findById("tb2").collectList().block()).isNotEqualTo(tb);
313+
assertThat(cache.get("tb2")).isNull();
314+
300315
context.close();
301316
}
302317

@@ -548,7 +563,7 @@ public Spr14230Service service() {
548563

549564
public static class Spr14235FutureService {
550565

551-
@Cacheable(value = "itemCache")
566+
@Cacheable(value = "itemCache", unless = "#result.name == 'tb2'")
552567
public CompletableFuture<TestBean> findById(String id) {
553568
return CompletableFuture.completedFuture(new TestBean(id));
554569
}
@@ -581,7 +596,7 @@ public TestBean insertItem(TestBean item) {
581596

582597
public static class Spr14235MonoService {
583598

584-
@Cacheable(value = "itemCache")
599+
@Cacheable(value = "itemCache", unless = "#result.name == 'tb2'")
585600
public Mono<TestBean> findById(String id) {
586601
return Mono.just(new TestBean(id));
587602
}
@@ -616,7 +631,7 @@ public static class Spr14235FluxService {
616631

617632
private int counter = 0;
618633

619-
@Cacheable(value = "itemCache")
634+
@Cacheable(value = "itemCache", unless = "#result[0].name == 'tb2'")
620635
public Flux<TestBean> findById(String id) {
621636
return Flux.just(new TestBean(id), new TestBean(id + (counter++)));
622637
}

0 commit comments

Comments
 (0)