Allow @Cacheable method to return java.util.Optional variant of cached value
Includes renaming of internal delegate to CacheOperationExpressionEvaluator. Issue: SPR-14230
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,12 +20,14 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
@@ -39,6 +41,7 @@ import org.springframework.cache.support.SimpleCacheManager;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
@@ -83,11 +86,11 @@ public class CacheReproTests {
|
||||
|
||||
String key = "1";
|
||||
Object result = bean.getSimple("1");
|
||||
verify(cache, times(1)).get(key); // first call: cache miss
|
||||
verify(cache, times(1)).get(key); // first call: cache miss
|
||||
|
||||
Object cachedResult = bean.getSimple("1");
|
||||
assertSame(result, cachedResult);
|
||||
verify(cache, times(2)).get(key); // second call: cache hit
|
||||
verify(cache, times(2)).get(key); // second call: cache hit
|
||||
|
||||
context.close();
|
||||
}
|
||||
@@ -100,11 +103,11 @@ public class CacheReproTests {
|
||||
|
||||
String key = "1";
|
||||
Object result = bean.getNeverCache("1");
|
||||
verify(cache, times(0)).get(key); // no cache hit at all, caching disabled
|
||||
verify(cache, times(0)).get(key); // no cache hit at all, caching disabled
|
||||
|
||||
Object cachedResult = bean.getNeverCache("1");
|
||||
assertNotSame(result, cachedResult);
|
||||
verify(cache, times(0)).get(key); // caching disabled
|
||||
verify(cache, times(0)).get(key); // caching disabled
|
||||
|
||||
context.close();
|
||||
}
|
||||
@@ -114,8 +117,9 @@ public class CacheReproTests {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr13081Config.class);
|
||||
MyCacheResolver cacheResolver = context.getBean(MyCacheResolver.class);
|
||||
Spr13081Service bean = context.getBean(Spr13081Service.class);
|
||||
|
||||
assertNull(cacheResolver.getCache("foo").get("foo"));
|
||||
Object result = bean.getSimple("foo"); // cache name = id
|
||||
Object result = bean.getSimple("foo"); // cache name = id
|
||||
assertEquals(result, cacheResolver.getCache("foo").get("foo").get());
|
||||
}
|
||||
|
||||
@@ -124,12 +128,21 @@ public class CacheReproTests {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr13081Config.class);
|
||||
Spr13081Service bean = context.getBean(Spr13081Service.class);
|
||||
|
||||
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage(MyCacheResolver.class.getName());
|
||||
bean.getSimple(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spr14230AdaptsToOptional() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr14230Config.class);
|
||||
Spr14230Service bean = context.getBean(Spr14230Service.class);
|
||||
|
||||
TestBean tb = new TestBean("tb1");
|
||||
bean.insertItem(tb);
|
||||
assertSame(tb, bean.findById("tb1").get());
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@@ -245,6 +258,7 @@ public class CacheReproTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public static class Spr13081Config extends CachingConfigurerSupport {
|
||||
@@ -259,9 +273,9 @@ public class CacheReproTests {
|
||||
public Spr13081Service service() {
|
||||
return new Spr13081Service();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class MyCacheResolver extends AbstractCacheResolver {
|
||||
|
||||
public MyCacheResolver() {
|
||||
@@ -282,6 +296,7 @@ public class CacheReproTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Spr13081Service {
|
||||
|
||||
@Cacheable
|
||||
@@ -290,4 +305,34 @@ public class CacheReproTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Spr14230Service {
|
||||
|
||||
@Cacheable("itemCache")
|
||||
public Optional<TestBean> findById(String id) {
|
||||
return Optional.of(new TestBean(id));
|
||||
}
|
||||
|
||||
@CachePut(cacheNames = "itemCache", key = "#item.name")
|
||||
public TestBean insertItem(TestBean item) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public static class Spr14230Config {
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
return new ConcurrentMapCacheManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Spr14230Service service() {
|
||||
return new Spr14230Service();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -67,35 +67,35 @@ public class CacheSyncFailureTests {
|
||||
@Test
|
||||
public void unlessSync() {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("@Cacheable(sync = true) does not support unless attribute");
|
||||
thrown.expectMessage("@Cacheable(sync=true) does not support unless attribute");
|
||||
this.simpleService.unlessSync("key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalCachesSync() {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("@Cacheable(sync = true) only allows a single cache");
|
||||
thrown.expectMessage("@Cacheable(sync=true) only allows a single cache");
|
||||
this.simpleService.severalCachesSync("key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void severalCachesWithResolvedSync() {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("@Cacheable(sync = true) only allows a single cache");
|
||||
thrown.expectMessage("@Cacheable(sync=true) only allows a single cache");
|
||||
this.simpleService.severalCachesWithResolvedSync("key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncWithAnotherOperation() {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("@Cacheable(sync = true) cannot be combined with other cache operations");
|
||||
thrown.expectMessage("@Cacheable(sync=true) cannot be combined with other cache operations");
|
||||
this.simpleService.syncWithAnotherOperation("key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void syncWithTwoGetOperations() {
|
||||
thrown.expect(IllegalStateException.class);
|
||||
thrown.expectMessage("Only one @Cacheable(sync = true) entry is allowed");
|
||||
thrown.expectMessage("Only one @Cacheable(sync=true) entry is allowed");
|
||||
this.simpleService.syncWithTwoGetOperations("key");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,15 +47,17 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class ExpressionEvaluatorTests {
|
||||
|
||||
private ExpressionEvaluator eval = new ExpressionEvaluator();
|
||||
private final CacheOperationExpressionEvaluator eval = new CacheOperationExpressionEvaluator();
|
||||
|
||||
private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
||||
|
||||
private AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
||||
|
||||
private Collection<CacheOperation> getOps(String name) {
|
||||
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, name, Object.class, Object.class);
|
||||
return source.getCacheOperations(method, AnnotatedClass.class);
|
||||
return this.source.getCacheOperations(method, AnnotatedClass.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultipleCachingSource() throws Exception {
|
||||
Collection<CacheOperation> ops = getOps("multipleCaching");
|
||||
@@ -110,14 +112,14 @@ public class ExpressionEvaluatorTests {
|
||||
|
||||
@Test
|
||||
public void withoutReturnValue() throws Exception {
|
||||
EvaluationContext context = createEvaluationContext(ExpressionEvaluator.NO_RESULT);
|
||||
EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.NO_RESULT);
|
||||
Object value = new SpelExpressionParser().parseExpression("#result").getValue(context);
|
||||
assertThat(value, nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unavailableReturnValue() throws Exception {
|
||||
EvaluationContext context = createEvaluationContext(ExpressionEvaluator.RESULT_UNAVAILABLE);
|
||||
EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE);
|
||||
try {
|
||||
new SpelExpressionParser().parseExpression("#result").getValue(context);
|
||||
fail("Should have failed to parse expression, result not available");
|
||||
@@ -134,7 +136,7 @@ public class ExpressionEvaluatorTests {
|
||||
applicationContext.registerBeanDefinition("myBean", beanDefinition);
|
||||
applicationContext.refresh();
|
||||
|
||||
EvaluationContext context = createEvaluationContext(ExpressionEvaluator.NO_RESULT, applicationContext);
|
||||
EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.NO_RESULT, applicationContext);
|
||||
Object value = new SpelExpressionParser().parseExpression("@myBean.class.getName()").getValue(context);
|
||||
assertThat(value, is(String.class.getName()));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user