Skip to content

Commit bbcc788

Browse files
committed
Decouple exception messages for sync=true from @Cacheable
1 parent 038dda9 commit bbcc788

File tree

3 files changed

+41
-39
lines changed

3 files changed

+41
-39
lines changed

spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -177,9 +177,9 @@
177177
* <li>Only one cache may be specified</li>
178178
* <li>No other cache-related operation can be combined</li>
179179
* </ol>
180-
* This is effectively a hint and the actual cache provider that you are
181-
* using may not support it in a synchronized fashion. Check your provider
182-
* documentation for more details on the actual semantics.
180+
* This is effectively a hint and the chosen cache provider might not actually
181+
* support it in a synchronized fashion. Check your provider documentation for
182+
* more details on the actual semantics.
183183
* @since 4.3
184184
* @see org.springframework.cache.Cache#get(Object, Callable)
185185
*/

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

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ public void afterPropertiesSet() {
214214
@Override
215215
public void afterSingletonsInstantiated() {
216216
if (getCacheResolver() == null) {
217-
// Lazily initialize cache resolver via default cache manager...
217+
// Lazily initialize cache resolver via default cache manager
218218
Assert.state(this.beanFactory != null, "CacheResolver or BeanFactory must be set on cache aspect");
219219
try {
220220
setCacheManager(this.beanFactory.getBean(CacheManager.class));
@@ -307,22 +307,22 @@ else if (StringUtils.hasText(operation.getCacheManager())) {
307307
}
308308

309309
/**
310-
* Return a bean with the specified name and type. Used to resolve services that
311-
* are referenced by name in a {@link CacheOperation}.
312-
* @param beanName the name of the bean, as defined by the operation
313-
* @param expectedType type for the bean
314-
* @return the bean matching that name
310+
* Retrieve a bean with the specified name and type.
311+
* Used to resolve services that are referenced by name in a {@link CacheOperation}.
312+
* @param name the name of the bean, as defined by the cache operation
313+
* @param serviceType the type expected by the operation's service reference
314+
* @return the bean matching the expected type, qualified by the given name
315315
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException if such bean does not exist
316316
* @see CacheOperation#getKeyGenerator()
317317
* @see CacheOperation#getCacheManager()
318318
* @see CacheOperation#getCacheResolver()
319319
*/
320-
protected <T> T getBean(String beanName, Class<T> expectedType) {
320+
protected <T> T getBean(String name, Class<T> serviceType) {
321321
if (this.beanFactory == null) {
322322
throw new IllegalStateException(
323-
"BeanFactory must be set on cache aspect for " + expectedType.getSimpleName() + " retrieval");
323+
"BeanFactory must be set on cache aspect for " + serviceType.getSimpleName() + " retrieval");
324324
}
325-
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.beanFactory, expectedType, beanName);
325+
return BeanFactoryAnnotationUtils.qualifiedBeanOfType(this.beanFactory, serviceType, name);
326326
}
327327

328328
/**
@@ -388,12 +388,11 @@ private Object execute(final CacheOperationInvoker invoker, Method method, Cache
388388
}
389389
}
390390
else {
391-
// No caching required, only call the underlying method
391+
// No caching required, just call the underlying method
392392
return invokeOperation(invoker);
393393
}
394394
}
395395

396-
397396
// Process any early evictions
398397
processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
399398
CacheOperationExpressionEvaluator.NO_RESULT);
@@ -641,21 +640,21 @@ private boolean determineSyncFlag(Method method) {
641640
if (syncEnabled) {
642641
if (this.contexts.size() > 1) {
643642
throw new IllegalStateException(
644-
"@Cacheable(sync=true) cannot be combined with other cache operations on '" + method + "'");
643+
"A sync=true operation cannot be combined with other cache operations on '" + method + "'");
645644
}
646645
if (cacheOperationContexts.size() > 1) {
647646
throw new IllegalStateException(
648-
"Only one @Cacheable(sync=true) entry is allowed on '" + method + "'");
647+
"Only one sync=true operation is allowed on '" + method + "'");
649648
}
650649
CacheOperationContext cacheOperationContext = cacheOperationContexts.iterator().next();
651-
CacheableOperation operation = (CacheableOperation) cacheOperationContext.getOperation();
650+
CacheOperation operation = cacheOperationContext.getOperation();
652651
if (cacheOperationContext.getCaches().size() > 1) {
653652
throw new IllegalStateException(
654-
"@Cacheable(sync=true) only allows a single cache on '" + operation + "'");
653+
"A sync=true operation is restricted to a single cache on '" + operation + "'");
655654
}
656-
if (StringUtils.hasText(operation.getUnless())) {
655+
if (operation instanceof CacheableOperation cacheable && StringUtils.hasText(cacheable.getUnless())) {
657656
throw new IllegalStateException(
658-
"@Cacheable(sync=true) does not support unless attribute on '" + operation + "'");
657+
"A sync=true operation does not support the unless attribute on '" + operation + "'");
659658
}
660659
return true;
661660
}
@@ -884,13 +883,13 @@ public int compareTo(CacheOperationCacheKey other) {
884883
}
885884
}
886885

886+
887887
/**
888888
* Internal holder class for recording that a cache method was invoked.
889889
*/
890890
private static class InvocationAwareResult {
891891

892892
boolean invoked;
893-
894893
}
895894

896895
}

spring-context/src/test/java/org/springframework/cache/interceptor/CacheSyncFailureTests.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 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.
@@ -48,8 +48,9 @@ public class CacheSyncFailureTests {
4848

4949
private SimpleService simpleService;
5050

51+
5152
@BeforeEach
52-
public void setUp() {
53+
public void setup() {
5354
this.context = new AnnotationConfigApplicationContext(Config.class);
5455
this.simpleService = this.context.getBean(SimpleService.class);
5556
}
@@ -61,39 +62,40 @@ public void closeContext() {
6162
}
6263
}
6364

65+
6466
@Test
6567
public void unlessSync() {
66-
assertThatIllegalStateException().isThrownBy(() ->
67-
this.simpleService.unlessSync("key"))
68-
.withMessageContaining("@Cacheable(sync=true) does not support unless attribute");
68+
assertThatIllegalStateException()
69+
.isThrownBy(() -> this.simpleService.unlessSync("key"))
70+
.withMessageContaining("A sync=true operation does not support the unless attribute");
6971
}
7072

7173
@Test
7274
public void severalCachesSync() {
73-
assertThatIllegalStateException().isThrownBy(() ->
74-
this.simpleService.severalCachesSync("key"))
75-
.withMessageContaining("@Cacheable(sync=true) only allows a single cache");
75+
assertThatIllegalStateException()
76+
.isThrownBy(() -> this.simpleService.severalCachesSync("key"))
77+
.withMessageContaining("A sync=true operation is restricted to a single cache");
7678
}
7779

7880
@Test
7981
public void severalCachesWithResolvedSync() {
80-
assertThatIllegalStateException().isThrownBy(() ->
81-
this.simpleService.severalCachesWithResolvedSync("key"))
82-
.withMessageContaining("@Cacheable(sync=true) only allows a single cache");
82+
assertThatIllegalStateException()
83+
.isThrownBy(() -> this.simpleService.severalCachesWithResolvedSync("key"))
84+
.withMessageContaining("A sync=true operation is restricted to a single cache");
8385
}
8486

8587
@Test
8688
public void syncWithAnotherOperation() {
87-
assertThatIllegalStateException().isThrownBy(() ->
88-
this.simpleService.syncWithAnotherOperation("key"))
89-
.withMessageContaining("@Cacheable(sync=true) cannot be combined with other cache operations");
89+
assertThatIllegalStateException()
90+
.isThrownBy(() -> this.simpleService.syncWithAnotherOperation("key"))
91+
.withMessageContaining("A sync=true operation cannot be combined with other cache operations");
9092
}
9193

9294
@Test
9395
public void syncWithTwoGetOperations() {
94-
assertThatIllegalStateException().isThrownBy(() ->
95-
this.simpleService.syncWithTwoGetOperations("key"))
96-
.withMessageContaining("Only one @Cacheable(sync=true) entry is allowed");
96+
assertThatIllegalStateException()
97+
.isThrownBy(() -> this.simpleService.syncWithTwoGetOperations("key"))
98+
.withMessageContaining("Only one sync=true operation is allowed");
9799
}
98100

99101

@@ -131,6 +133,7 @@ public Object syncWithTwoGetOperations(Object arg1) {
131133
}
132134
}
133135

136+
134137
@Configuration
135138
@EnableCaching
136139
static class Config implements CachingConfigurer {

0 commit comments

Comments
 (0)